auto import from //depot/cupcake/@135843
diff --git a/tests/AndroidTests/Android.mk b/tests/AndroidTests/Android.mk
new file mode 100644
index 0000000..f5e49d7
--- /dev/null
+++ b/tests/AndroidTests/Android.mk
@@ -0,0 +1,22 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := framework-tests android.test.runner
+
+LOCAL_STATIC_JAVA_LIBRARIES := googlelogin-client
+
+# Resource unit tests use a private locale
+LOCAL_AAPT_FLAGS = -c xx_YY -c cs
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files) \
+ src/com/android/unit_tests/os/IAidlTest.aidl
+
+LOCAL_PACKAGE_NAME := AndroidTests
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AndroidTests/AndroidManifest.xml b/tests/AndroidTests/AndroidManifest.xml
new file mode 100644
index 0000000..843d844
--- /dev/null
+++ b/tests/AndroidTests/AndroidManifest.xml
@@ -0,0 +1,226 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.unit_tests"
+ android:sharedUserId="com.android.uid.test">
+ <permission android:name="com.android.unit_tests.permission.TEST_GRANTED"
+ android:protectionLevel="normal"
+ android:label="@string/permlab_testGranted"
+ android:description="@string/permdesc_testGranted">
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+ </permission>
+ <permission android:name="com.android.unit_tests.permission.TEST_DENIED"
+ android:protectionLevel="normal"
+ android:label="@string/permlab_testDenied"
+ android:description="@string/permdesc_testDenied" />
+
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.READ_SMS"/>
+ <uses-permission android:name="android.permission.WRITE_SMS"/>
+ <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+ <uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
+ <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+ <uses-permission android:name="android.permission.GET_PACKAGE_SIZE" />
+ <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.WRITE_GSERVICES" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <uses-permission android:name="com.android.unit_tests.permission.TEST_GRANTED" />
+
+ <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH" />
+ <uses-permission android:name="com.google.android.googleapps.permission.GOOGLE_AUTH.ALL_SERVICES" />
+ <uses-permission android:name="com.google.android.googleapps.permission.ACCESS_GOOGLE_PASSWORD" />
+ <!-- InstrumentationTestRunner for AndroidTests -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.unit_tests"
+ android:label="Tests for AndroidTests (unit tests collection)"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <!-- Activity-level metadata -->
+ <meta-data android:name="com.android.unit_tests.isApp" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference"
+ android:resource="@xml/metadata_app" />
+
+ <activity android:name="AndroidPerformanceTests" android:label="Android Performance Tests">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.UNIT_TEST" />
+ </intent-filter>
+ </activity>
+
+ <!-- Application components used for activity tests -->
+
+ <activity android:name=".activity.TestedActivity"
+ android:process=":remoteActivity">
+ </activity>
+ <activity android:name=".activity.LocalActivity" android:multiprocess="true">
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+ </activity>
+ <activity android:name=".activity.TestedScreen"
+ android:process=":remoteScreen">
+ </activity>
+ <activity android:name=".activity.LocalScreen" android:multiprocess="true">
+ </activity>
+ <activity android:name=".activity.ClearTop" android:multiprocess="true"
+ android:launchMode="singleTop">
+ </activity>
+ <activity android:name=".activity.LocalDialog" android:multiprocess="true"
+ android:theme="@android:style/Theme.Dialog">
+ </activity>
+ <activity android:name=".activity.SubActivityScreen">
+ </activity>
+ <activity android:name=".activity.RemoteSubActivityScreen"
+ android:process=":remoteActivity">
+ </activity>
+ <activity android:name=".activity.LaunchpadActivity" android:multiprocess="true">
+ </activity>
+ <activity android:name=".activity.LaunchpadTabActivity" android:multiprocess="true">
+ </activity>
+
+ <receiver android:name=".activity.AbortReceiver">
+ <intent-filter android:priority="1">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.LocalReceiver">
+ <intent-filter android:priority="-1">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_ALL" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_REPEAT" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_FAIL_REGISTER" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_FAIL_BIND" />
+ </intent-filter>
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+ </receiver>
+ <receiver android:name=".activity.ResultReceiver">
+ <intent-filter>
+ <action android:name="com.android.unit_tests.activity.BROADCAST_RESULT" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.LocalGrantedReceiver"
+ android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+ <intent-filter android:priority="-1">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL_GRANTED" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.LocalDeniedReceiver"
+ android:permission="com.android.unit_tests.permission.TEST_DENIED">
+ <intent-filter android:priority="-1">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_LOCAL_DENIED" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.RemoteReceiver"
+ android:process=":remoteReceiver">
+ <intent-filter android:priority="2">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_ABORT" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_ALL" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_REPEAT" />
+ <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.RemoteGrantedReceiver"
+ android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+ <intent-filter android:priority="2">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE_GRANTED" />
+ </intent-filter>
+ </receiver>
+ <receiver android:name=".activity.RemoteDeniedReceiver"
+ android:permission="com.android.unit_tests.permission.TEST_DENIED">
+ <intent-filter android:priority="2">
+ <action android:name="com.android.unit_tests.activity.BROADCAST_REMOTE_DENIED" />
+ </intent-filter>
+ </receiver>
+ <service android:name=".activity.LocalService">
+ <intent-filter>
+ <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL" />
+ </intent-filter>
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+ </service>
+ <service android:name=".activity.LocalDeniedService"
+ android:permission="com.android.unit_tests.permission.TEST_DENIED">
+ <intent-filter>
+ <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL_DENIED" />
+ </intent-filter>
+ </service>
+ <service android:name=".activity.LocalGrantedService"
+ android:permission="com.android.unit_tests.permission.TEST_GRANTED">
+ <intent-filter>
+ <action android:name="com.android.unit_tests.activity.SERVICE_LOCAL_GRANTED" />
+ </intent-filter>
+ </service>
+
+ <provider android:name=".activity.LocalProvider"
+ android:authorities="com.android.unit_tests.LocalProvider">
+ <meta-data android:name="com.android.unit_tests.string" android:value="foo" />
+ <meta-data android:name="com.android.unit_tests.boolean" android:value="true" />
+ <meta-data android:name="com.android.unit_tests.integer" android:value="100" />
+ <meta-data android:name="com.android.unit_tests.color" android:value="#ff000000" />
+ <meta-data android:name="com.android.unit_tests.float" android:value="100.1" />
+ <meta-data android:name="com.android.unit_tests.reference" android:resource="@xml/metadata" />
+ </provider>
+
+ <!-- Application components used for os tests -->
+
+ <service android:name=".os.MessengerService"
+ android:process=":messengerService">
+ </service>
+
+ <!-- Application components used for search manager tests -->
+ <!-- TODO: Removed temporarily - need to be replaced using mocks -->
+
+ <!-- Used to test IPC. -->
+ <service android:name=".binder.BinderTestService"
+ android:process="binder.BinderTestService" />
+ <service android:name=".binder.BinderPerformanceService"
+ android:process="binder.BinderPerformanceService" />
+ <service android:name=".binder.BinderVsMessagingService"
+ android:process="binder.BinderVsMessagingService" />
+ </application>
+</manifest>
diff --git a/tests/AndroidTests/DisabledTestApp/Android.mk b/tests/AndroidTests/DisabledTestApp/Android.mk
new file mode 100644
index 0000000..a5daedf
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DisabledTestApp
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..4d6843e
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.unit_tests.disabled_app"
+ android:sharedUserId="com.android.uid.test">
+
+ <application enabled="false">
+
+ <!-- Used to test package component enabling and disabling -->
+ <activity android:name=".DisabledActivity" android:enabled="false" >
+ </activity>
+ <activity android:name=".EnabledActivity" >
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java
new file mode 100644
index 0000000..4e4dc85
--- /dev/null
+++ b/tests/AndroidTests/DisabledTestApp/src/com/android/unit_tests/disabled_app/EnabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.disabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class EnabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/Android.mk b/tests/AndroidTests/EnabledTestApp/Android.mk
new file mode 100644
index 0000000..4b986d3
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := EnabledTestApp
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml
new file mode 100644
index 0000000..ad610f1
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.unit_tests.enabled_app"
+ android:sharedUserId="com.android.uid.test">
+
+ <application>
+
+ <!-- Used to test package component enabling and disabling -->
+ <activity android:name=".DisabledActivity" android:enabled="false" >
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="com.android.unit_tests.enabled_app.TEST_CATEGORY" />
+ </intent-filter>
+ </activity>
+ <service android:name=".DisabledService" android:enabled="false" >
+ </service>
+ <receiver android:name=".DisabledReceiver" android:enabled="false" >
+ <intent-filter>
+ <action android:name="android.intent.action.ENABLED_APP_DISABLED_RECEIVER" />
+ </intent-filter>
+ </receiver>
+ <provider android:name=".DisabledProvider" android:enabled="false"
+ android:authorities="com.android.unit_tests.enabled_app.DisabledProvider"
+ android:process=":disabled.provider.process" />
+ <activity android:name=".EnabledActivity" >
+ </activity>
+ <service android:name=".EnabledService" android:enabled="true" >
+ </service>
+ <receiver android:name=".EnabledReceiver" >
+ <intent-filter>
+ <action android:name="android.intent.action.ENABLED_APP_ENABLED_RECEIVER" />
+ </intent-filter>
+ </receiver>
+ <provider android:name=".EnabledProvider"
+ android:authorities="com.android.unit_tests.enabled_app.EnabledProvider"
+ android:process=":enabled.provider.process" />
+ </application>
+</manifest>
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java
new file mode 100644
index 0000000..0ab0416
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class DisabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java
new file mode 100644
index 0000000..06527f9
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty ContentProvider for testing
+ */
+
+public class DisabledProvider extends ContentProvider {
+
+ public boolean onCreate() {
+ return false;
+ }
+
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java
new file mode 100644
index 0000000..c27b87e
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Empty IntentReceiver for testing
+ */
+
+public class DisabledReceiver extends BroadcastReceiver {
+
+ public void onReceive(Context context, Intent intent) {
+
+ }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java
new file mode 100644
index 0000000..ed8d0b9
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/DisabledService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.app.Service;
+import android.os.IBinder;
+import android.content.Intent;
+
+/**
+ * Empty Service for testing
+ */
+
+public class DisabledService extends Service {
+
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java
new file mode 100644
index 0000000..cfac3ec
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.app.Activity;
+
+/**
+ * Empty Activity for testing
+ */
+
+public class EnabledActivity extends Activity {
+
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java
new file mode 100644
index 0000000..764937f
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledProvider.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.content.ContentProvider;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+
+/**
+ * Empty ContentProvider for testing
+ */
+
+public class EnabledProvider extends ContentProvider {
+
+ public boolean onCreate() {
+ return false;
+ }
+
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ return null;
+ }
+
+ public String getType(Uri uri) {
+ return null;
+ }
+
+ public Uri insert(Uri uri, ContentValues values) {
+ return null;
+ }
+
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ return 0;
+ }
+
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ return 0;
+ }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java
new file mode 100644
index 0000000..707448f
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Empty IntentReceiver for testing
+ */
+
+public class EnabledReceiver extends BroadcastReceiver {
+
+ public void onReceive(Context context, Intent intent) {
+
+ }
+}
diff --git a/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java
new file mode 100644
index 0000000..81a80b3
--- /dev/null
+++ b/tests/AndroidTests/EnabledTestApp/src/com/android/unit_tests/enabled_app/EnabledService.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.enabled_app;
+
+import android.app.Service;
+import android.os.IBinder;
+import android.content.Intent;
+
+/**
+ * Empty Service for testing
+ */
+
+public class EnabledService extends Service {
+
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/tests/AndroidTests/MODULE_LICENSE_APACHE2 b/tests/AndroidTests/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/AndroidTests/MODULE_LICENSE_APACHE2
diff --git a/tests/AndroidTests/NOTICE b/tests/AndroidTests/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/tests/AndroidTests/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/tests/AndroidTests/assets/text.txt b/tests/AndroidTests/assets/text.txt
new file mode 100644
index 0000000..3d8c519
--- /dev/null
+++ b/tests/AndroidTests/assets/text.txt
@@ -0,0 +1 @@
+OneTwoThreeFourFiveSixSevenEightNineTen
\ No newline at end of file
diff --git a/tests/AndroidTests/res/drawable/test128x96.png b/tests/AndroidTests/res/drawable/test128x96.png
new file mode 100644
index 0000000..28dc925
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test128x96.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test16x12.png b/tests/AndroidTests/res/drawable/test16x12.png
new file mode 100644
index 0000000..1a3c7e5
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test16x12.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test256x192.png b/tests/AndroidTests/res/drawable/test256x192.png
new file mode 100644
index 0000000..ce8ee04
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test256x192.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test320x240.png b/tests/AndroidTests/res/drawable/test320x240.png
new file mode 100644
index 0000000..9b5800d
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test320x240.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test32x24.png b/tests/AndroidTests/res/drawable/test32x24.png
new file mode 100644
index 0000000..76bab75
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test32x24.png
Binary files differ
diff --git a/tests/AndroidTests/res/drawable/test64x48.png b/tests/AndroidTests/res/drawable/test64x48.png
new file mode 100644
index 0000000..9119613
--- /dev/null
+++ b/tests/AndroidTests/res/drawable/test64x48.png
Binary files differ
diff --git a/tests/AndroidTests/res/layout/layout_five.xml b/tests/AndroidTests/res/layout/layout_five.xml
new file mode 100644
index 0000000..fd1e0ef
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_five.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <TextView android:id="@+id/text" android:text="@string/layout_five_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_four.xml b/tests/AndroidTests/res/layout/layout_four.xml
new file mode 100644
index 0000000..e5a78bcfd
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_four.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text" android:text="@string/layout_four_text_text"/>
diff --git a/tests/AndroidTests/res/layout/layout_one.xml b/tests/AndroidTests/res/layout/layout_one.xml
new file mode 100644
index 0000000..f5c78bd
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_one.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<view xmlns:android="http://schemas.android.com/apk/res/android" class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/layout/layout_six.xml b/tests/AndroidTests/res/layout/layout_six.xml
new file mode 100644
index 0000000..6efcdf3
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_six.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView android:id="@+id/text" android:text="@string/layout_six_text_text" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_tag.xml b/tests/AndroidTests/res/layout/layout_tag.xml
new file mode 100644
index 0000000..1f17701
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_tag.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<view xmlns:android="http://schemas.android.com/apk/res/android"
+ class="com.android.unit_tests.InflateTest$ViewOne"
+ android:id="@+id/viewOne" android:tag="MyTag"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/layout/layout_three.xml b/tests/AndroidTests/res/layout/layout_three.xml
new file mode 100644
index 0000000..77b2aa9
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_three.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view1" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view2" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view3" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view4" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view5" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/view6" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+</LinearLayout>
diff --git a/tests/AndroidTests/res/layout/layout_two.xml b/tests/AndroidTests/res/layout/layout_two.xml
new file mode 100644
index 0000000..9c99710
--- /dev/null
+++ b/tests/AndroidTests/res/layout/layout_two.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <view class="com.android.unit_tests.InflateTest$ViewOne" android:id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
+</LinearLayout>
+
diff --git a/tests/AndroidTests/res/raw/calendarjs.txt b/tests/AndroidTests/res/raw/calendarjs.txt
new file mode 100644
index 0000000..15f7bab
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarjs.txt
@@ -0,0 +1 @@
+{"version":"1.0","encoding":"UTF-8","feed":{"xmlns":"http://www.w3.org/2005/Atom","xmlns$openSearch":"http://a9.com/-/spec/opensearchrss/1.0/","xmlns$gd":"http://schemas.google.com/g/2005","xmlns$gCal":"http://schemas.google.com/gCal/2005","id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},"updated":{"$t":"2007-02-06T02:55:15.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"w g"},"subtitle":{"type":"text","$t":"w g"},"link":[{"rel":"http://schemas.google.com/g/2005#feed","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic?alt\u003Djson\u0026max-results\u003D25"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"generator":{"version":"1.0","uri":"http://www.google.com/calendar","$t":"Google Calendar"},"openSearch$totalResults":{"$t":"13"},"openSearch$startIndex":{"$t":"1"},"openSearch$itemsPerPage":{"$t":"25"},"gCal$timezone":{"value":"America/Los_Angeles"},"entry":[{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"},"published":{"$t":"2007-02-05T22:04:50.000Z"},"updated":{"$t":"2007-02-05T22:04:50.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 13:30 to Wed Feb 7, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DN2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/7iqc1ro0ihc69vhsiq3uabooig"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"},"published":{"$t":"2007-02-05T22:04:42.000Z"},"updated":{"$t":"2007-02-05T22:04:42.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 15:30 to Fri Feb 9, 2007 18:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Da3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/kp4gil76n2vcrkt9kaotj3s12c"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"},"published":{"$t":"2007-02-05T22:04:35.000Z"},"updated":{"$t":"2007-02-05T22:04:35.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 6"},"summary":{"type":"html","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Sat Feb 10, 2007 14:00 to Sat Feb 10, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DZ2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/gkhb48fj68lcp15fd1k03tjbj0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"},"published":{"$t":"2007-02-05T22:04:29.000Z"},"updated":{"$t":"2007-02-05T22:04:29.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 5"},"summary":{"type":"html","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Fri Feb 9, 2007 09:00 to 10:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DMzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/32p5g68cpean3p2ol7kanj38sg"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"},"published":{"$t":"2007-02-05T22:04:19.000Z"},"updated":{"$t":"2007-02-05T22:04:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Thu Feb 8, 2007 15:00 to Thu Feb 8, 2007 17:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tfqpth26conshdmav0apje1tf4"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"},"published":{"$t":"2007-02-05T22:04:07.000Z"},"updated":{"$t":"2007-02-05T22:04:07.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks at Anaheim"},"summary":{"type":"html","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Wed Feb 7, 2007 19:00 to 22:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/onbo9mhbr5m6mo356nog7uel4s"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"},"published":{"$t":"2007-02-05T22:04:02.000Z"},"updated":{"$t":"2007-02-05T22:04:02.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"Sharks vs. ANAHEIM"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 19:30 to 22:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DdGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/tjqrd9fve576hieh3sa67nql5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"},"published":{"$t":"2007-02-05T22:03:52.000Z"},"updated":{"$t":"2007-02-05T22:03:52.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"skate"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 14:00 to 15:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/or6dtpn065f9mntond4jh2docc"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"},"published":{"$t":"2007-02-05T22:03:36.000Z"},"updated":{"$t":"2007-02-05T22:03:36.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"lunch"},"summary":{"type":"html","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600 \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"Recurring Event\u003Cbr\u003E First start: 2007-02-06 12:00:00 PST \u003Cbr\u003E Duration: 3600 \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DazcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/k70v8o4jt1afi17hg2spavq1c0"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"true"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"},"published":{"$t":"2007-02-05T22:03:19.000Z"},"updated":{"$t":"2007-02-05T22:03:19.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 4"},"summary":{"type":"html","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Tue Feb 6, 2007 09:00 to 11:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DNmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/6ee7b8nohdt03tv0gknm4v7124"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"},"published":{"$t":"2007-02-05T22:03:11.000Z"},"updated":{"$t":"2007-02-05T22:03:11.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 3"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 18:00 to 19:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Db2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/of1vh1r2q5aqdplo65i8bqbn3o"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"},"published":{"$t":"2007-02-05T22:02:40.000Z"},"updated":{"$t":"2007-02-05T22:03:04.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 2"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 16:30 to 17:30\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003DczdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/s7ahgfomlgii9qbkgpfbinr9u8"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}},{"id":{"$t":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"},"published":{"$t":"2007-02-05T22:02:28.000Z"},"updated":{"$t":"2007-02-05T22:02:53.000Z"},"category":[{"scheme":"http://schemas.google.com/g/2005#kind","term":"http://schemas.google.com/g/2005#event"}],"title":{"type":"text","$t":"test event 1"},"summary":{"type":"html","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"content":{"type":"text","$t":"When: Mon Feb 5, 2007 15:00 to Mon Feb 5, 2007 16:00\u0026nbsp; PST\u003Cbr\u003E \u003Cbr\u003EEvent Status: confirmed"},"link":[{"rel":"alternate","type":"text/html","href":"http://www.google.com/calendar/event?eid\u003Dcmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ","title":"alternate"},{"rel":"self","type":"application/atom+xml","href":"http://www.google.com/calendar/feeds/wg%40voiceme.net/public/basic/rl8focglfe6jndql4u8lg73q5k"}],"author":[{"name":{"$t":"w g"},"email":{"$t":"wg@voiceme.net"}}],"gCal$sendEventNotifications":{"value":"false"}}]}}
\ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/calendarjsgz.jsgz b/tests/AndroidTests/res/raw/calendarjsgz.jsgz
new file mode 100644
index 0000000..6f1bf54
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarjsgz.jsgz
Binary files differ
diff --git a/tests/AndroidTests/res/raw/calendarxml.xml b/tests/AndroidTests/res/raw/calendarxml.xml
new file mode 100644
index 0000000..1adcd74
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarxml.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:gd='http://schemas.google.com/g/2005' xmlns:gCal='http://schemas.google.com/gCal/2005'><id>http://www.google.com/calendar/feeds/default/private/full</id><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>w g</title><subtitle type='text'>w g</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='http://schemas.google.com/g/2005#post' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full?max-results=25'></link><author><name>w g</name><email>wg@voiceme.net</email></author><generator version='1.0' uri='http://www.google.com/calendar'>Google Calendar</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><gCal:timezone value='America/Los_Angeles'></gCal:timezone><entry><id>http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig</id><published>2007-02-05T22:04:50.000Z</published><updated>2007-02-05T22:04:50.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=N2lxYzFybzBpaGM2OXZoc2lxM3VhYm9vaWcgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/63306396290'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/7iqc1ro0ihc69vhsiq3uabooig/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-07T13:30:00.000-08:00' endTime='2007-02-07T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c</id><published>2007-02-05T22:04:42.000Z</published><updated>2007-02-05T22:04:42.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=a3A0Z2lsNzZuMnZjcmt0OWthb3RqM3MxMmMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/63306396282'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/kp4gil76n2vcrkt9kaotj3s12c/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T15:30:00.000-08:00' endTime='2007-02-09T18:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0</id><published>2007-02-05T22:04:35.000Z</published><updated>2007-02-05T22:04:35.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 6</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=Z2toYjQ4Zmo2OGxjcDE1ZmQxazAzdGpiajAgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/63306396275'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/gkhb48fj68lcp15fd1k03tjbj0/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-10T14:00:00.000-08:00' endTime='2007-02-10T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg</id><published>2007-02-05T22:04:29.000Z</published><updated>2007-02-05T22:04:29.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 5</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=MzJwNWc2OGNwZWFuM3Ayb2w3a2FuajM4c2cgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/63306396269'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/32p5g68cpean3p2ol7kanj38sg/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-09T09:00:00.000-08:00' endTime='2007-02-09T10:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4</id><published>2007-02-05T22:04:19.000Z</published><updated>2007-02-05T22:04:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGZxcHRoMjZjb25zaGRtYXYwYXBqZTF0ZjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/63306396259'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tfqpth26conshdmav0apje1tf4/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-08T15:00:00.000-08:00' endTime='2007-02-08T17:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s</id><published>2007-02-05T22:04:07.000Z</published><updated>2007-02-05T22:04:07.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks at Anaheim</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b25ibzltaGJyNW02bW8zNTZub2c3dWVsNHMgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/63306396247'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/onbo9mhbr5m6mo356nog7uel4s/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-07T19:00:00.000-08:00' endTime='2007-02-07T22:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k</id><published>2007-02-05T22:04:02.000Z</published><updated>2007-02-05T22:04:02.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>Sharks vs. ANAHEIM</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=dGpxcmQ5ZnZlNTc2aGllaDNzYTY3bnFsNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/63306396242'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/tjqrd9fve576hieh3sa67nql5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-06T19:30:00.000-08:00' endTime='2007-02-06T22:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc</id><published>2007-02-05T22:03:52.000Z</published><updated>2007-02-05T22:03:52.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>skate</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b3I2ZHRwbjA2NWY5bW50b25kNGpoMmRvY2Mgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/63306396232'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/or6dtpn065f9mntond4jh2docc/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T14:00:00.000-08:00' endTime='2007-02-06T15:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0</id><published>2007-02-05T22:03:36.000Z</published><updated>2007-02-05T22:03:36.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>lunch</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=azcwdjhvNGp0MWFmaTE3aGcyc3BhdnExYzBfMjAwNzAyMDZUMjAwMDAwWiB3Z0B2b2ljZW1lLm5ldA' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/k70v8o4jt1afi17hg2spavq1c0/63306396216'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='true'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:recurrence>DTSTART;TZID=America/Los_Angeles:20070206T120000
+DURATION:PT3600S
+RRULE:FREQ=DAILY;WKST=SU
+BEGIN:VTIMEZONE
+TZID:America/Los_Angeles
+X-LIC-LOCATION:America/Los_Angeles
+BEGIN:STANDARD
+TZOFFSETFROM:-0700
+TZOFFSETTO:-0800
+TZNAME:PST
+DTSTART:19701025T020000
+RRULE:FREQ=YEARLY;BYMONTH=10;BYDAY=-1SU
+END:STANDARD
+BEGIN:DAYLIGHT
+TZOFFSETFROM:-0800
+TZOFFSETTO:-0700
+TZNAME:PDT
+DTSTART:19700405T020000
+RRULE:FREQ=YEARLY;BYMONTH=4;BYDAY=1SU
+END:DAYLIGHT
+END:VTIMEZONE
+</gd:recurrence><gd:where valueString=''></gd:where><gd:reminder minutes='10'></gd:reminder></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124</id><published>2007-02-05T22:03:19.000Z</published><updated>2007-02-05T22:03:19.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 4</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=NmVlN2I4bm9oZHQwM3R2MGdrbm00djcxMjQgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/63306396199'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/6ee7b8nohdt03tv0gknm4v7124/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-06T09:00:00.000-08:00' endTime='2007-02-06T11:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o</id><published>2007-02-05T22:03:11.000Z</published><updated>2007-02-05T22:03:11.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 3</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=b2YxdmgxcjJxNWFxZHBsbzY1aThicWJuM28gd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/63306396191'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/of1vh1r2q5aqdplo65i8bqbn3o/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T18:00:00.000-08:00' endTime='2007-02-05T19:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8</id><published>2007-02-05T22:02:40.000Z</published><updated>2007-02-05T22:03:04.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 2</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=czdhaGdmb21sZ2lpOXFia2dwZmJpbnI5dTggd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/63306396184'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/s7ahgfomlgii9qbkgpfbinr9u8/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where valueString=''></gd:where><gd:when startTime='2007-02-05T16:30:00.000-08:00' endTime='2007-02-05T17:30:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry><entry><id>http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k</id><published>2007-02-05T22:02:28.000Z</published><updated>2007-02-05T22:02:53.000Z</updated><category scheme='http://schemas.google.com/g/2005#kind' term='http://schemas.google.com/g/2005#event'></category><title type='text'>test event 1</title><content type='text'></content><link rel='alternate' type='text/html' href='http://www.google.com/calendar/hosted/voiceme.net/event?eid=cmw4Zm9jZ2xmZTZqbmRxbDR1OGxnNzNxNWsgd2dAdm9pY2VtZS5uZXQ' title='alternate'></link><link rel='self' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k'></link><link rel='edit' type='application/atom+xml' href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/63306396173'></link><author><name>w g</name><email>wg@voiceme.net</email></author><gd:comments><gd:feedLink href='http://www.google.com/calendar/feeds/default/private/full/rl8focglfe6jndql4u8lg73q5k/comments'></gd:feedLink></gd:comments><gd:eventStatus value='http://schemas.google.com/g/2005#event.confirmed'></gd:eventStatus><gd:visibility value='http://schemas.google.com/g/2005#event.default'></gd:visibility><gCal:sendEventNotifications value='false'></gCal:sendEventNotifications><gd:transparency value='http://schemas.google.com/g/2005#event.opaque'></gd:transparency><gd:where></gd:where><gd:when startTime='2007-02-05T15:00:00.000-08:00' endTime='2007-02-05T16:00:00.000-08:00'><gd:reminder minutes='10'></gd:reminder></gd:when></entry></feed>
diff --git a/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz
new file mode 100644
index 0000000..6c86462
--- /dev/null
+++ b/tests/AndroidTests/res/raw/calendarxmlgz.xmlgz
Binary files differ
diff --git a/tests/AndroidTests/res/raw/medium.xml b/tests/AndroidTests/res/raw/medium.xml
new file mode 100644
index 0000000..51c952c
--- /dev/null
+++ b/tests/AndroidTests/res/raw/medium.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout id="@+id/content" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent">
+ <TextView id="@+id/text" android:text="S" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView id="@+id/text" android:text="M" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView id="@+id/text" android:text="T" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView id="@+id/text" android:text="W" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView id="@+id/text" android:text="H" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+ <TextView id="@+id/text" android:text="F" android:layout_width="fill_parent" android:layout_height="wrap_content" />
+</LinearLayout>
diff --git a/tests/AndroidTests/res/raw/small.xml b/tests/AndroidTests/res/raw/small.xml
new file mode 100644
index 0000000..2697fb8
--- /dev/null
+++ b/tests/AndroidTests/res/raw/small.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<view class="com.android.tests.InflateTest$ViewOne" id="@+id/viewOne" android:layout_width="fill_parent" android:layout_height="fill_parent"/>
diff --git a/tests/AndroidTests/res/raw/text.txt b/tests/AndroidTests/res/raw/text.txt
new file mode 100644
index 0000000..3d8c519
--- /dev/null
+++ b/tests/AndroidTests/res/raw/text.txt
@@ -0,0 +1 @@
+OneTwoThreeFourFiveSixSevenEightNineTen
\ No newline at end of file
diff --git a/tests/AndroidTests/res/raw/youtube.xml b/tests/AndroidTests/res/raw/youtube.xml
new file mode 100644
index 0000000..fedaeac
--- /dev/null
+++ b/tests/AndroidTests/res/raw/youtube.xml
@@ -0,0 +1,1852 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<feed xmlns='http://www.w3.org/2005/Atom'
+ xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/'
+ xmlns:media='http://search.yahoo.com/mrss/'
+ xmlns:gd='http://schemas.google.com/g/2005'
+ xmlns:yt='http://gdata.youtube.com/schemas/2007'>
+ <id>http://dm5.google.com/feeds/standardfeeds/top_rated</id>
+ <updated>2007-05-01T18:13:20.333Z</updated>
+ <title type='text'>Top Rated - Beta</title>
+ <logo>http://www.youtube.com/img/pic_youtubelogo_123x63.gif</logo>
+ <link rel='alternate' type='text/html'
+ href='http://www.youtube.com/browse?s=tr'></link>
+ <link rel='http://schemas.google.com/g/2005#feed'
+ type='application/atom+xml'
+ href='http://dm5.google.com/feeds/standardfeeds/top_rated'></link>
+ <link rel='self' type='application/atom+xml'
+ href='http://dm5.google.com/feeds/standardfeeds/top_rated?start-index=1&max-results=25'></link>
+ <link rel='next' type='application/atom+xml'
+ href='http://dm5.google.com/feeds/standardfeeds/top_rated?start-index=26&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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 & 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 <&> world</p>\n");
+
+ s = new SpannableString("Hello \u03D5 world");
+ assertEquals(Html.toHtml(s), "<p>Hello ϕ world</p>\n");
+
+ s = new SpannableString("Hello world");
+ assertEquals(Html.toHtml(s), "<p>Hello 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>Ĥëłło, world!</p>\n", Html.toHtml(s));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java
new file mode 100644
index 0000000..d7c9d60
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/InflateTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+
+import java.util.Map;
+
+public class InflateTest extends AndroidTestCase implements PerformanceTestCase {
+ private LayoutInflater mInflater;
+ private Resources mResources;
+ private View mView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mInflater = LayoutInflater.from(mContext);
+ mResources = mContext.getResources();
+
+ // to try to make things consistent, before doing timing
+ // do an initial instantiation of the layout and then clear
+ // out the layout cache.
+// mInflater.inflate(mResId, null, null);
+// mResources.flushLayoutCache();
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ return 0;
+ }
+
+ public boolean isPerformanceOnly() {
+ return false;
+ }
+
+ public void inflateTest(int resourceId) {
+ mView = mInflater.inflate(resourceId, null);
+ mResources.flushLayoutCache();
+ }
+
+ public void inflateCachedTest(int resourceId) {
+ // Make sure this layout is in the cache.
+ mInflater.inflate(resourceId, null);
+
+ mInflater.inflate(resourceId, null);
+ }
+
+ @SmallTest
+ public void testLayout1() throws Exception {
+ inflateTest(R.layout.layout_one);
+ }
+
+ @SmallTest
+ public void testLayout2() throws Exception {
+ inflateTest(R.layout.layout_two);
+ }
+
+ @SmallTest
+ public void testLayout3() throws Exception {
+ inflateTest(R.layout.layout_three);
+ }
+
+ @SmallTest
+ public void testLayout4() throws Exception {
+ inflateTest(R.layout.layout_four);
+ }
+
+ @SmallTest
+ public void testLayout5() throws Exception {
+ inflateTest(R.layout.layout_five);
+ }
+
+ @SmallTest
+ public void testLayout6() throws Exception {
+ inflateTest(R.layout.layout_six);
+ }
+
+ @SmallTest
+ public void testCachedLayout1() throws Exception {
+ inflateCachedTest(R.layout.layout_one);
+ }
+
+ @SmallTest
+ public void testCachedLayout2() throws Exception {
+ inflateCachedTest(R.layout.layout_two);
+ }
+
+ @SmallTest
+ public void testCachedLayout3() throws Exception {
+ inflateCachedTest(R.layout.layout_three);
+ }
+
+ @SmallTest
+ public void testCachedLayout4() throws Exception {
+ inflateCachedTest(R.layout.layout_four);
+ }
+
+ @SmallTest
+ public void testCachedLayout5() throws Exception {
+ inflateCachedTest(R.layout.layout_five);
+ }
+
+ @SmallTest
+ public void testCachedLayout6() throws Exception {
+ inflateCachedTest(R.layout.layout_six);
+ }
+
+// public void testLayoutTag() throws Exception {
+// public void setUp
+// (Context
+// context){
+// setUp(context, R.layout.layout_tag);
+// }
+// public void run
+// ()
+// {
+// super.run();
+// if (!"MyTag".equals(mView.getTag())) {
+// throw new RuntimeException("Incorrect tag: " + mView.getTag());
+// }
+// }
+// }
+
+ public static class ViewOne extends View {
+ public ViewOne(Context context) {
+ super(context);
+ }
+
+ public ViewOne(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java
new file mode 100644
index 0000000..1f82df8
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/InstanceofTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+
+public class InstanceofTest extends TestCase {
+
+ protected A mA;
+ protected ChildOfAOne mOne;
+ protected ChildOfAOne mTwo;
+ protected ChildOfAOne mThree;
+ protected ChildOfAOne mFour;
+ protected ChildOfAFive mFive;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mA = new A();
+ mOne = new ChildOfAOne();
+ mTwo = new ChildOfATwo();
+ mThree = new ChildOfAThree();
+ mFour = new ChildOfAFour();
+ mFive = new ChildOfAFive();
+ }
+
+
+ @MediumTest
+ public void testNoInterface() throws Exception {
+ A a = mA;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_a should not be a ChildOfAFive", a instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testDerivedOne() throws Exception {
+ InterfaceOne one = mOne;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_one should not be a ChildOfAFive", one instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testDerivedTwo() throws Exception {
+ InterfaceTwo two = mTwo;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_two should not be a ChildOfAFive", two instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testDerivedThree() throws Exception {
+ InterfaceThree three = mThree;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_three should not be a ChildOfAFive", three instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testDerivedFour() throws Exception {
+ InterfaceFour four = mFour;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_four should not be a ChildOfAFive", four instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testSuccessClass() throws Exception {
+ ChildOfAOne five = mFive;
+ for (int i = 0; i < 100000; i++) {
+ assertTrue("m_five is suppose to be a ChildOfAFive", five instanceof ChildOfAFive);
+ }
+ }
+
+ @MediumTest
+ public void testSuccessInterface() throws Exception {
+ ChildOfAFive five = mFive;
+ for (int i = 0; i < 100000; i++) {
+ assertTrue("m_five is suppose to be a InterfaceFour", five instanceof InterfaceFour);
+ }
+ }
+
+ @MediumTest
+ public void testFailInterface() throws Exception {
+ InterfaceOne one = mFive;
+ for (int i = 0; i < 100000; i++) {
+ assertFalse("m_five does not implement InterfaceFive", one instanceof InterfaceFive);
+ }
+ }
+
+ private interface InterfaceOne {
+ }
+
+ private interface InterfaceTwo {
+ }
+
+ private interface InterfaceThree {
+ }
+
+ private interface InterfaceFour {
+ }
+
+ private interface InterfaceFive {
+ }
+
+ private static class A {
+ }
+
+ private static class ChildOfAOne extends A implements InterfaceOne, InterfaceTwo, InterfaceThree, InterfaceFour {
+ }
+
+ private static class ChildOfATwo extends ChildOfAOne {
+ }
+
+ private static class ChildOfAThree extends ChildOfATwo {
+ }
+
+ private static class ChildOfAFour extends ChildOfAThree {
+ }
+
+ private static class ChildOfAFive extends ChildOfAFour {
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java
new file mode 100644
index 0000000..e778d53
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/JavaPerformanceTests.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+/**
+ *
+ */
+public class JavaPerformanceTests {
+
+ public static String[] children() {
+ return new String[] {
+ StringTest.class.getName(),
+ HashMapTest.class.getName(),
+ ArrayListTest.class.getName(),
+ TreeMapTest.class.getName(),
+ TreeSetTest.class.getName(),
+ HashSetTest.class.getName(),
+ HashtableTest.class.getName(),
+ VectorTest.class.getName(),
+ LinkedListTest.class.getName(),
+ MathTest.class.getName(),
+ };
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java
new file mode 100644
index 0000000..6b740ba
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/JniLibTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import junit.framework.TestCase;
+
+
+@Suppress
+public class JniLibTest extends TestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ /*
+ * This causes the native shared library to be loaded when the
+ * class is first used. The library is only loaded once, even if
+ * multiple classes include this line.
+ *
+ * The library must be in java.library.path, which is derived from
+ * LD_LIBRARY_PATH. The actual library name searched for will be
+ * "libjni_lib_test.so" under Linux, but may be different on other
+ * platforms.
+ */
+ try {
+ System.loadLibrary("jni_lib_test");
+ } catch (UnsatisfiedLinkError ule) {
+ Log.e("JniLibTest", "WARNING: Could not load jni_lib_test natives");
+ }
+ }
+
+ private static native int nativeStaticThing(float f);
+ private native void nativeThing(int val);
+
+ public void testNativeCall() {
+ Log.i("JniLibTest", "JNI search path is "
+ + System.getProperty("java.library.path"));
+ Log.i("JniLibTest", "'jni_lib_test' becomes '"
+ + System.mapLibraryName("jni_lib_test") + "'");
+
+ int result = nativeStaticThing(1234.5f);
+ nativeThing(result);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LabelView.java b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java
new file mode 100644
index 0000000..ac29776
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LabelView.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.view.View;
+
+/**
+ * Example of how to write a custom subclass of View. LabelView
+ * is used to draw simple text views. Note that it does not handle
+ * styled text or right-to-left writing systems.
+ *
+ */
+public class LabelView extends View {
+ /**
+ * Constructor. This version is only needed if you will be instantiating
+ * the object manually (not from a layout XML file).
+ * @param context the application environment
+ */
+ public LabelView(Context context) {
+ super(context);
+ initLabelView();
+ }
+
+ /**
+ * Construct object, initializing with any attributes we understand from a
+ * layout file. These attributes are defined in
+ * SDK/assets/res/any/classes.xml.
+ *
+ * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
+ public LabelView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ initLabelView();
+
+ Resources.StyledAttributes a = context.obtainStyledAttributes(attrs,
+ R.styleable.LabelView);
+
+ CharSequence s = a.getString(R.styleable.LabelView_text);
+ if (s != null) {
+ setText(s.toString());
+ }
+
+ ColorStateList textColor = a.getColorList(R.styleable.
+ LabelView_textColor);
+ if (textColor != null) {
+ setTextColor(textColor.getDefaultColor(0));
+ }
+
+ int textSize = a.getInt(R.styleable.LabelView_textSize, 0);
+ if (textSize > 0) {
+ setTextSize(textSize);
+ }
+
+ a.recycle();
+ }
+
+ */
+ private void initLabelView() {
+ mTextPaint = new Paint();
+ mTextPaint.setAntiAlias(true);
+ mTextPaint.setTextSize(16);
+ mTextPaint.setColor(0xFF000000);
+
+ mPaddingLeft = 3;
+ mPaddingTop = 3;
+ mPaddingRight = 3;
+ mPaddingBottom = 3;
+ }
+
+ /**
+ * Sets the text to display in this label
+ * @param text The text to display. This will be drawn as one line.
+ */
+ public void setText(String text) {
+ mText = text;
+ requestLayout();
+ invalidate();
+ }
+
+ /**
+ * Sets the text size for this label
+ * @param size Font size
+ */
+ public void setTextSize(int size) {
+ mTextPaint.setTextSize(size);
+ requestLayout();
+ invalidate();
+ }
+
+ /**
+ * Sets the text color for this label
+ * @param color ARGB value for the text
+ */
+ public void setTextColor(int color) {
+ mTextPaint.setColor(color);
+ invalidate();
+ }
+
+
+ /**
+ * @see android.view.View#measure(int, int)
+ */
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(measureWidth(widthMeasureSpec),
+ measureHeight(heightMeasureSpec));
+ }
+
+ /**
+ * Determines the width of this view
+ * @param measureSpec A measureSpec packed into an int
+ * @return The width of the view, honoring constraints from measureSpec
+ */
+ private int measureWidth(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ if (specMode == MeasureSpec.EXACTLY) {
+ // We were told how big to be
+ result = specSize;
+ } else {
+ // Measure the text
+ result = (int) mTextPaint.measureText(mText) + mPaddingLeft
+ + mPaddingRight;
+ if (specMode == MeasureSpec.AT_MOST) {
+ // Respect AT_MOST value if that was what is called for by measureSpec
+ result = Math.min(result, specSize);
+ }
+ }
+
+ return result;
+ }
+
+ /**
+ * Determines the height of this view
+ * @param measureSpec A measureSpec packed into an int
+ * @return The height of the view, honoring constraints from measureSpec
+ */
+ private int measureHeight(int measureSpec) {
+ int result;
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ mAscent = (int) mTextPaint.ascent();
+ if (specMode == MeasureSpec.EXACTLY) {
+ // We were told how big to be
+ result = specSize;
+ } else {
+ // Measure the text (beware: ascent is a negative number)
+ result = (int) (-mAscent + mTextPaint.descent()) + mPaddingTop
+ + mPaddingBottom;
+ if (specMode == MeasureSpec.AT_MOST) {
+ // Respect AT_MOST value if that was what is called for by measureSpec
+ result = Math.min(result, specSize);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Render the text
+ *
+ * @see android.view.View#onDraw(android.graphics.Canvas)
+ */
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawText(mText, mPaddingLeft, mPaddingTop - mAscent, mTextPaint);
+ }
+
+ private Paint mTextPaint;
+ private String mText;
+ private int mAscent;
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java
new file mode 100644
index 0000000..ca470cd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LinkedListTest.java
@@ -0,0 +1,529 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+import java.util.LinkedList;
+import java.util.ListIterator;
+
+/**
+ * This class contains performance tests for methods in java.util.LinkedList
+ *
+ */
+@SuppressWarnings("unchecked")
+public class LinkedListTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ LinkedList<Integer> mLinkedList;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mLinkedList = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mLinkedList.add(i);
+ }
+ }
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testLinkedListAdd() {
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ list.add(i);
+ }
+ }
+
+ public void testLinkedListAdd1() {
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ list.add(0, i);
+ }
+ }
+
+ public void testLinkedListToArray() {
+ Object array;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ array = list.toArray();
+ }
+ }
+
+ public void testLinkedListSize() {
+ LinkedList<Integer> list = mLinkedList;
+ int len;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ len = list.size();
+ }
+ }
+
+ public void testLinkedListGet() {
+ int element;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ element = list.get(i);
+ }
+ }
+
+ public void testLinkedListContains() {
+ boolean flag;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ flag = list.contains(i);
+ }
+ }
+
+ public void testLinkedListToArray1() {
+ Integer[] rArray = new Integer[100];
+ Integer[] array;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ array = list.toArray(rArray);
+ }
+ }
+
+ public void testLinkedListSet() {
+ LinkedList<Integer> list = mLinkedList;
+ int value1 = 500, value2 = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ list.set(value1, value2);
+ }
+ }
+
+ public void testLinkedListIndexOf() {
+ int index;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+ index = list.indexOf(0);
+
+ }
+ }
+
+ public void testLinkedListLastIndexOf() {
+ int index;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ index = list.lastIndexOf(0);
+ }
+ }
+
+ public void testLinkedListRemove() {
+ int index;
+ LinkedList<Integer> list = new LinkedList(mLinkedList);
+ for (int i = 10; i > 0; i--) {
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ index = list.remove();
+ }
+ }
+
+ public void testLinkedListRemove1() {
+ int index;
+ LinkedList<Integer> list = new LinkedList(mLinkedList);
+ for (int i = 10; i > 0; i--) {
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ index = list.remove(0);
+ }
+ }
+
+ public void testLinkedListRemoveFirst() {
+ int index;
+ LinkedList<Integer> list = new LinkedList(mLinkedList);
+ for (int i = 10; i > 0; i--) {
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ index = list.removeFirst();
+ }
+ }
+
+ public void testLinkedListRemoveLast() {
+ int index;
+ LinkedList<Integer> list = new LinkedList(mLinkedList);
+ for (int i = 10; i > 0; i--) {
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ index = list.removeLast();
+ }
+ }
+
+ public void testLinkedListAddAll() {
+ LinkedList<Integer> mList = mLinkedList;
+ boolean flag;
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = 10; i > 0; i--) {
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ flag = list.addAll(mList);
+ }
+ }
+
+ public void testLinkedListRemove2() {
+ LinkedList<String> list;
+ String s = new String("a");
+ list = new LinkedList();
+ for (int j = 1000; j > 0; j--) {
+ list.add("a");
+ list.add("b");
+ }
+ boolean flag;
+ for (int i = 10; i > 0; i--) {
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ flag = list.remove(s);
+ }
+ }
+
+ public void testLinkedListAddAll1() {
+ LinkedList<Integer> mList = new LinkedList();
+ int pos = 0;
+ boolean flag;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = 0; i < 10; i++) {
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ flag = mList.addAll(pos, list);
+ }
+ }
+
+ public void testLinkedListClone() {
+ Object rObj;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = 100; i > 0; i--) {
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ rObj = list.clone();
+ }
+ }
+
+ public void testLinkedListHashcode() {
+ int element;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ element = list.hashCode();
+ }
+ }
+
+ public void testLinkedListElement() {
+ int element;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ element = list.element();
+ }
+ }
+
+ public void testLinkedListToString() {
+ String str;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ str = list.toString();
+ }
+ }
+
+ public void testLinkedListIsEmpty() {
+ boolean flag;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ flag = list.isEmpty();
+ }
+ }
+
+ public void testLinkedListOffer() {
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ list.offer(i);
+ }
+ }
+
+ public void testLinkedListPeek() {
+ int element;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ element = list.peek();
+ }
+ }
+
+ public void testLinkedListPoll() {
+ int element;
+ LinkedList<Integer> list = new LinkedList(mLinkedList);
+ for (int i = 10; i > 0; i--) {
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ element = list.poll();
+ }
+ }
+
+ public void testLinkedListAddLast() {
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ list.addLast(i);
+ }
+ }
+
+ public void testLinkedListAddFirst() {
+ LinkedList<Integer> list = new LinkedList();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ list.addFirst(i);
+ }
+ }
+
+ public void testLinkedListIterator() {
+ ListIterator iterator;
+ LinkedList<Integer> list = mLinkedList;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ iterator = list.listIterator();
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java
new file mode 100644
index 0000000..83e0758
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LinkifyTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.*;
+import android.text.method.*;
+import android.text.style.*;
+import android.text.util.*;
+import android.widget.*;
+
+/**
+ * LinkifyTest tests {@link Linkify}.
+ */
+public class LinkifyTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testNothing() throws Exception {
+ TextView tv;
+
+ tv = new TextView(getContext());
+ tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+ assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod);
+ assertTrue(tv.getUrls().length == 0);
+ }
+
+ @MediumTest
+ public void testNormal() throws Exception {
+ TextView tv;
+
+ tv = new TextView(getContext());
+ tv.setAutoLinkMask(Linkify.ALL);
+ tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+ assertTrue(tv.getMovementMethod() instanceof LinkMovementMethod);
+ assertTrue(tv.getUrls().length == 2);
+ }
+
+ @SmallTest
+ public void testUnclickable() throws Exception {
+ TextView tv;
+
+ tv = new TextView(getContext());
+ tv.setAutoLinkMask(Linkify.ALL);
+ tv.setLinksClickable(false);
+ tv.setText("Hey, foo@google.com, call 415-555-1212.");
+
+ assertFalse(tv.getMovementMethod() instanceof LinkMovementMethod);
+ assertTrue(tv.getUrls().length == 2);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java
new file mode 100644
index 0000000..0b8ec74
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LocalSocketTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+
+public class LocalSocketTest extends TestCase {
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ LocalServerSocket ss;
+ LocalSocket ls;
+ LocalSocket ls1;
+
+ ss = new LocalServerSocket("com.android.unit_tests.LocalSocketTest");
+
+ ls = new LocalSocket();
+
+ ls.connect(new LocalSocketAddress("com.android.unit_tests.LocalSocketTest"));
+
+ ls1 = ss.accept();
+
+ // Test trivial read and write
+ ls.getOutputStream().write(42);
+
+ assertEquals(42, ls1.getInputStream().read());
+
+ // Test getting credentials
+ Credentials c = ls1.getPeerCredentials();
+
+ MoreAsserts.assertNotEqual(0, c.getPid());
+
+ // Test sending and receiving file descriptors
+ ls.setFileDescriptorsForSend(
+ new FileDescriptor[]{FileDescriptor.in});
+
+ ls.getOutputStream().write(42);
+
+ assertEquals(42, ls1.getInputStream().read());
+
+ FileDescriptor[] out = ls1.getAncillaryFileDescriptors();
+
+ assertEquals(1, out.length);
+
+ // Test multible byte write and available()
+ ls1.getOutputStream().write(new byte[]{0, 1, 2, 3, 4, 5}, 1, 5);
+
+ assertEquals(1, ls.getInputStream().read());
+ assertEquals(4, ls.getInputStream().available());
+
+ byte[] buffer = new byte[16];
+ int countRead;
+
+ countRead = ls.getInputStream().read(buffer, 1, 15);
+
+ assertEquals(4, countRead);
+ assertEquals(2, buffer[1]);
+ assertEquals(3, buffer[2]);
+ assertEquals(4, buffer[3]);
+ assertEquals(5, buffer[4]);
+
+ // Try various array-out-of-bound cases
+ try {
+ ls.getInputStream().read(buffer, 1, 16);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ try {
+ ls.getOutputStream().write(buffer, 1, 16);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ try {
+ ls.getOutputStream().write(buffer, -1, 15);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ try {
+ ls.getOutputStream().write(buffer, 0, -1);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ try {
+ ls.getInputStream().read(buffer, -1, 15);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ try {
+ ls.getInputStream().read(buffer, 0, -1);
+ fail("expected exception");
+ } catch (ArrayIndexOutOfBoundsException ex) {
+ // excpected
+ }
+
+ // Try read of length 0
+ ls.getOutputStream().write(42);
+ countRead = ls1.getInputStream().read(buffer, 0, 0);
+ assertEquals(0, countRead);
+ assertEquals(42, ls1.getInputStream().read());
+
+ ss.close();
+
+ ls.close();
+
+ // Try write on closed socket
+
+ try {
+ ls.getOutputStream().write(42);
+ fail("expected exception");
+ } catch (IOException ex) {
+ // Expected
+ }
+
+ // Try read on closed socket
+
+ try {
+ ls.getInputStream().read();
+ fail("expected exception");
+ } catch (IOException ex) {
+ // Expected
+ }
+
+ // Try write on socket whose peer has closed
+
+ try {
+ ls1.getOutputStream().write(42);
+ fail("expected exception");
+ } catch (IOException ex) {
+ // Expected
+ }
+
+ // Try read on socket whose peer has closed
+
+ assertEquals(-1, ls1.getInputStream().read());
+
+ ls1.close();
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java
new file mode 100644
index 0000000..47c7522
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LocationManagerTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.location.LocationProvider;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+@Suppress
+public class LocationManagerTest extends AndroidTestCase {
+ private static final String LOG_TAG = "LocationManagerTest";
+
+ private LocationManager manager;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ manager = (LocationManager) mContext.getSystemService(Context.LOCATION_SERVICE);
+ assertNotNull(manager);
+ }
+
+ public void testGetBogusProvider() {
+ LocationProvider p = manager.getProvider("bogus");
+ assertNull(p);
+ }
+
+ public void testGetNetworkProvider() {
+ LocationProvider p = manager.getProvider("network");
+ assertNotNull(p);
+ }
+
+ public void testGetGpsProvider() {
+ LocationProvider p = manager.getProvider("gps");
+ assertNotNull(p);
+ }
+
+ public void testGetBestProviderEmptyCriteria() {
+ String p = manager.getBestProvider(new Criteria(), true);
+ assertNotNull(p);
+ }
+
+ public void testGetBestProviderPowerCriteria() {
+ Criteria c = new Criteria();
+ c.setPowerRequirement(Criteria.POWER_HIGH);
+ String p = manager.getBestProvider(c, true);
+ assertNotNull(p);
+
+ c.setPowerRequirement(Criteria.POWER_MEDIUM);
+ p = manager.getBestProvider(c, true);
+ assertNotNull(p);
+
+ c.setPowerRequirement(Criteria.POWER_LOW);
+ p = manager.getBestProvider(c, true);
+ assertNotNull(p);
+
+ c.setPowerRequirement(Criteria.NO_REQUIREMENT);
+ p = manager.getBestProvider(c, true);
+ assertNotNull(p);
+ }
+
+ public void testGpsTracklog() {
+ LocationProvider p = manager.getProvider("gps");
+ assertNotNull(p);
+
+ // TODO: test requestUpdates method
+ }
+
+ public void testLocationConversions() {
+ String loc1 = Location.convert(-80.075, Location.FORMAT_DEGREES);
+ Log.i(LOG_TAG, "Input = " + (-80.075) + ", output = " + loc1);
+ assertEquals("-80.075", loc1);
+
+ String loc1b = Location.convert(-80.0, Location.FORMAT_DEGREES);
+ Log.i(LOG_TAG, "Input = " + (-80.0) + ", output = " + loc1b);
+ assertEquals("-80", loc1b);
+
+ String loc2 = Location.convert(-80.085, Location.FORMAT_DEGREES);
+ Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc2);
+ assertEquals("-80.085", loc2);
+
+ String loc3 = Location.convert(-80.085, Location.FORMAT_MINUTES);
+ Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc3);
+ assertEquals("-80:5.1", loc3);
+
+ String loc4 = Location.convert(-80.085, Location.FORMAT_SECONDS);
+ Log.i(LOG_TAG, "Input = " + (-80.085) + ", output = " + loc4);
+ assertEquals("-80:5:6", loc4);
+
+ String loc5 = Location.convert(5 + 0.5f / 60.0f, Location.FORMAT_MINUTES);
+ Log.i(LOG_TAG, "Input = 5:0.5, output = " + loc5);
+ int index = loc5.indexOf(':');
+ String loc5a = loc5.substring(0, index);
+ Log.i(LOG_TAG, "loc5a = " + loc5a);
+ assertTrue(loc5a.equals("5"));
+ String loc5b = loc5.substring(index + 1);
+ Log.i(LOG_TAG, "loc5b = " + loc5b);
+ double minutes = Double.parseDouble(loc5b);
+ Log.i(LOG_TAG, "minutes = " + minutes);
+ assertTrue(Math.abs(minutes - 0.5) < 0.0001);
+
+ String loc6 = Location.convert(0.1, Location.FORMAT_DEGREES);
+ Log.i(LOG_TAG, "loc6 = " + loc6);
+ assertEquals(loc6, "0.1");
+
+ String loc7 = Location.convert(0.1, Location.FORMAT_MINUTES);
+ Log.i(LOG_TAG, "loc7 = " + loc7);
+ assertEquals(loc7, "0:6");
+
+ String loc8 = Location.convert(0.1, Location.FORMAT_SECONDS);
+ Log.i(LOG_TAG, "loc8 = " + loc8);
+ assertEquals(loc8, "0:6:0");
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/LogTest.java b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java
new file mode 100644
index 0000000..786c4b9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/LogTest.java
@@ -0,0 +1,152 @@
+package com.android.unit_tests;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import android.os.SystemProperties;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+//This is an empty TestCase.
+@Suppress
+public class LogTest extends TestCase {
+ private static final String PROPERTY_TAG = "log.tag.LogTest";
+ private static final String LOG_TAG = "LogTest";
+
+
+ // TODO: remove this test once we uncomment out the following test.
+ public void testLogTestDummy() {
+ return;
+ }
+
+
+ /* TODO: This test is commented out because we will not be able to set properities. Fix the test.
+ public void testIsLoggable() {
+ // First clear any SystemProperty setting for our test key.
+ SystemProperties.set(PROPERTY_TAG, null);
+
+ String value = SystemProperties.get(PROPERTY_TAG);
+ Assert.assertTrue(value == null || value.length() == 0);
+
+ // Check to make sure that all levels expect for INFO, WARN, ERROR, and ASSERT are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be VERBOSE for this tag.
+ SystemProperties.set(PROPERTY_TAG, "VERBOSE");
+
+ // Test to make sure all log levels >= VERBOSE are loggable.
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be DEBUG for this tag.
+ SystemProperties.set(PROPERTY_TAG, "DEBUG");
+
+ // Test to make sure all log levels >= DEBUG are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be INFO for this tag.
+ SystemProperties.set(PROPERTY_TAG, "INFO");
+
+ // Test to make sure all log levels >= INFO are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be WARN for this tag.
+ SystemProperties.set(PROPERTY_TAG, "WARN");
+
+ // Test to make sure all log levels >= WARN are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be ERROR for this tag.
+ SystemProperties.set(PROPERTY_TAG, "ERROR");
+
+ // Test to make sure all log levels >= ERROR are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be ASSERT for this tag.
+ SystemProperties.set(PROPERTY_TAG, "ASSERT");
+
+ // Test to make sure all log levels >= ASSERT are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertTrue(Log.isLoggable(LOG_TAG, Log.ASSERT));
+
+ // Set the log level to be SUPPRESS for this tag.
+ SystemProperties.set(PROPERTY_TAG, "SUPPRESS");
+
+ // Test to make sure all log levels >= ASSERT are loggable.
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.VERBOSE));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.DEBUG));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.INFO));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.WARN));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ERROR));
+ Assert.assertFalse(Log.isLoggable(LOG_TAG, Log.ASSERT));
+ }
+ */
+
+ public static class PerformanceTest extends TestCase implements PerformanceTestCase {
+ private static final int ITERATIONS = 1000;
+
+ @Override
+ public void setUp() {
+ SystemProperties.set(LOG_TAG, "VERBOSE");
+ }
+
+ public boolean isPerformanceOnly() {
+ return true;
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testIsLoggable() {
+ boolean canLog = false;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ canLog = Log.isLoggable(LOG_TAG, Log.VERBOSE);
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MathTest.java b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java
new file mode 100644
index 0000000..caf2d20
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MathTest.java
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+/**
+ *
+ * Implements basic performance test functionality for java.lang.Math
+ *
+ */
+
+public class MathTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ public static final double sDouble1 = -2450.50;
+ public static final double sDouble2 = -500;
+ public static final float sFloat = 300.50f;
+ public static final int sInt = 90;
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testDoubleAbs() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ result = Math.abs(sDouble1);
+ }
+ }
+
+ public void testFloatAbs() {
+ float result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ result = Math.abs(sFloat);
+ }
+ }
+
+ public void testMathSin() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ result = Math.sin(sDouble1);
+ }
+ }
+
+ public void testMathCos() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ result = Math.cos(sDouble1);
+ }
+ }
+
+ public void testMathTan() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ result = Math.tan(sDouble1);
+ }
+ }
+
+ public void testMathASin() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ result = Math.asin(sDouble1);
+ }
+ }
+
+ public void testMathACos() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ result = Math.acos(sDouble1);
+ }
+ }
+
+ public void testMathATan() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ result = Math.atan(sDouble1);
+ }
+ }
+
+ public void testMathLog() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ result = Math.log(sDouble1);
+ }
+ }
+
+ public void testMathSqrt() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ result = Math.sqrt(sDouble1);
+ }
+ }
+
+ public void testMathCeil() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ result = Math.ceil(sDouble1);
+ }
+ }
+
+ public void testMathRound() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ result = Math.round(sDouble1);
+ }
+ }
+
+ public void testMathFloor() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ result = Math.floor(sDouble1);
+ }
+ }
+
+ public void testMathExp() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ result = Math.exp(sDouble1);
+ }
+ }
+
+ /**
+ *
+ */
+
+ public void testMathPow() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ result = Math.pow(sDouble1, sDouble2);
+ }
+ }
+
+ public void testMathMax() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ result = Math.max(sDouble1, sDouble2);
+ }
+ }
+
+ public void testMathMin() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ result = Math.min(sDouble1, sDouble2);
+ }
+ }
+
+ public void testMathRandom() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ result = Math.random();
+ }
+ }
+
+ public void testMathIEEERemainder() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ result = Math.IEEEremainder(sDouble1, sDouble2);
+ }
+ }
+
+ public void testMathToDegrees() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ result = Math.toDegrees(sDouble1);
+ }
+ }
+
+ public void testMathToRadians() {
+ double result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ result = Math.toRadians(sDouble1);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
new file mode 100644
index 0000000..c436726
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MenuTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.internal.view.menu.MenuBuilder;
+
+import junit.framework.Assert;
+
+import android.test.AndroidTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+public class MenuTest extends AndroidTestCase {
+
+ private MenuBuilder mMenu;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mMenu = new MenuBuilder(super.getContext());
+ }
+
+ @SmallTest
+ public void testItemId() {
+ final int id = 512;
+ final MenuItem item = mMenu.add(0, id, 0, "test");
+
+ Assert.assertEquals(id, item.getItemId());
+ Assert.assertEquals(item, mMenu.findItem(id));
+ Assert.assertEquals(0, mMenu.findItemIndex(id));
+ }
+
+ @SmallTest
+ public void testGroupId() {
+ final int groupId = 541;
+ final int item1Index = 1;
+ final int item2Index = 3;
+
+ mMenu.add(0, 0, item1Index - 1, "ignore");
+ final MenuItem item = mMenu.add(groupId, 0, item1Index, "test");
+ mMenu.add(0, 0, item2Index - 1, "ignore");
+ final MenuItem item2 = mMenu.add(groupId, 0, item2Index, "test2");
+
+ Assert.assertEquals(groupId, item.getGroupId());
+ Assert.assertEquals(groupId, item2.getGroupId());
+ Assert.assertEquals(item1Index, mMenu.findGroupIndex(groupId));
+ Assert.assertEquals(item2Index, mMenu.findGroupIndex(groupId, item1Index + 1));
+ }
+
+ @SmallTest
+ public void testGroup() {
+ // This test does the following
+ // 1. Create a grouped item in the menu
+ // 2. Check that findGroupIndex() finds the grouped item.
+ // 3. Check that findGroupIndex() doesn't find a non-existent group.
+
+ final int GROUP_ONE = Menu.FIRST;
+ final int GROUP_TWO = Menu.FIRST + 1;
+
+ mMenu.add(GROUP_ONE, 0, 0, "Menu text");
+ Assert.assertEquals(mMenu.findGroupIndex(GROUP_ONE), 0);
+ Assert.assertEquals(mMenu.findGroupIndex(GROUP_TWO), -1);
+ //TODO: expand this test case to do multiple groups,
+ //adding and removing, hiding and showing, etc.
+ }
+
+ @SmallTest
+ public void testIsShortcutWithAlpha() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A, 0)));
+ Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_B,
+ makeKeyEvent(KeyEvent.KEYCODE_B, 0)));
+ }
+
+ @SmallTest
+ public void testIsShortcutWithNumeric() throws Exception {
+ mMenu.setQwertyMode(false);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_2,
+ makeKeyEvent(KeyEvent.KEYCODE_2, 0)));
+ Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A, 0)));
+ }
+
+ @SmallTest
+ public void testIsShortcutWithAlt() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A,
+ KeyEvent.META_ALT_ON)));
+ Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A,
+ KeyEvent.META_SYM_ON)));
+ }
+
+ @SmallTest
+ public void testIsNotShortcutWithShift() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+ Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A,
+ KeyEvent.META_SHIFT_ON)));
+ }
+
+ @SmallTest
+ public void testIsNotShortcutWithSym() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'a');
+ Assert.assertFalse(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A,
+ KeyEvent.META_SYM_ON)));
+ }
+
+ @SmallTest
+ public void testIsShortcutWithUpperCaseAlpha() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', 'A');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_A,
+ makeKeyEvent(KeyEvent.KEYCODE_A, 0)));
+ }
+
+ @SmallTest
+ public void testIsShortcutWithBackspace() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', '\b');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_DEL,
+ makeKeyEvent(KeyEvent.KEYCODE_DEL, 0)));
+ }
+
+ @SmallTest
+ public void testIsShortcutWithNewline() throws Exception {
+ mMenu.setQwertyMode(true);
+ mMenu.add(0, 0, 0, "test").setShortcut('2', '\n');
+ Assert.assertTrue(mMenu.isShortcutKey(KeyEvent.KEYCODE_ENTER,
+ makeKeyEvent(KeyEvent.KEYCODE_ENTER, 0)));
+ }
+
+ @SmallTest
+ public void testOrder() {
+ final String a = "a", b = "b", c = "c";
+ final int firstOrder = 7, midOrder = 8, lastOrder = 9;
+
+ mMenu.add(0, 0, lastOrder, c);
+ mMenu.add(0, 0, firstOrder, a);
+ mMenu.add(0, 0, midOrder, b);
+
+ Assert.assertEquals(firstOrder, mMenu.getItem(0).getOrder());
+ Assert.assertEquals(a, mMenu.getItem(0).getTitle());
+ Assert.assertEquals(midOrder, mMenu.getItem(1).getOrder());
+ Assert.assertEquals(b, mMenu.getItem(1).getTitle());
+ Assert.assertEquals(lastOrder, mMenu.getItem(2).getOrder());
+ Assert.assertEquals(c, mMenu.getItem(2).getTitle());
+ }
+
+ @SmallTest
+ public void testTitle() {
+ final String title = "test";
+ final MenuItem stringItem = mMenu.add(title);
+ final MenuItem resItem = mMenu.add(R.string.menu_test);
+
+ Assert.assertEquals(title, stringItem.getTitle());
+ Assert.assertEquals(getContext().getResources().getString(R.string.menu_test), resItem
+ .getTitle());
+ }
+
+ @SmallTest
+ public void testCheckable() {
+ final int groupId = 1;
+ final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1");
+ final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2");
+
+ // Set to exclusive
+ mMenu.setGroupCheckable(groupId, true, true);
+ Assert.assertTrue("Item was not set to checkable", item1.isCheckable());
+ item1.setChecked(true);
+ Assert.assertTrue("Item did not get checked", item1.isChecked());
+ Assert.assertFalse("Item was not unchecked due to exclusive checkable", item2.isChecked());
+ mMenu.findItem(2).setChecked(true);
+ Assert.assertTrue("Item did not get checked", item2.isChecked());
+ Assert.assertFalse("Item was not unchecked due to exclusive checkable", item1.isChecked());
+
+ // Multiple non-exlusive checkable items
+ mMenu.setGroupCheckable(groupId, true, false);
+ Assert.assertTrue("Item was not set to checkable", item1.isCheckable());
+ item1.setChecked(false);
+ Assert.assertFalse("Item did not get unchecked", item1.isChecked());
+ item1.setChecked(true);
+ Assert.assertTrue("Item did not get checked", item1.isChecked());
+ mMenu.findItem(2).setChecked(true);
+ Assert.assertTrue("Item did not get checked", item2.isChecked());
+ Assert.assertTrue("Item was unchecked when it shouldnt have been", item1.isChecked());
+ }
+
+ @SmallTest
+ public void testVisibility() {
+ final MenuItem item1 = mMenu.add(0, 1, 0, "item1");
+ final MenuItem item2 = mMenu.add(0, 2, 0, "item2");
+
+ // Should start as visible
+ Assert.assertTrue("Item did not start as visible", item1.isVisible());
+ Assert.assertTrue("Item did not start as visible", item2.isVisible());
+
+ // Hide
+ item1.setVisible(false);
+ Assert.assertFalse("Item did not become invisible", item1.isVisible());
+ mMenu.findItem(2).setVisible(false);
+ Assert.assertFalse("Item did not become invisible", item2.isVisible());
+ }
+
+ @SmallTest
+ public void testSubMenu() {
+ final SubMenu subMenu = mMenu.addSubMenu(0, 0, 0, "submenu");
+ final MenuItem subMenuItem = subMenu.getItem();
+ final MenuItem item1 = subMenu.add(0, 1, 0, "item1");
+ final MenuItem item2 = subMenu.add(0, 2, 0, "item2");
+
+ // findItem should recurse into submenus
+ Assert.assertEquals(item1, mMenu.findItem(1));
+ Assert.assertEquals(item2, mMenu.findItem(2));
+ }
+
+ @SmallTest
+ public void testRemove() {
+ final int groupId = 1;
+ final MenuItem item1 = mMenu.add(groupId, 1, 0, "item1");
+ final MenuItem item2 = mMenu.add(groupId, 2, 0, "item2");
+ final MenuItem item3 = mMenu.add(groupId, 3, 0, "item3");
+ final MenuItem item4 = mMenu.add(groupId, 4, 0, "item4");
+ final MenuItem item5 = mMenu.add(groupId, 5, 0, "item5");
+ final MenuItem item6 = mMenu.add(0, 6, 0, "item6");
+
+ Assert.assertEquals(item1, mMenu.findItem(1));
+ mMenu.removeItemAt(0);
+ Assert.assertNull(mMenu.findItem(1));
+
+ Assert.assertEquals(item2, mMenu.findItem(2));
+ mMenu.removeItem(2);
+ Assert.assertNull(mMenu.findItem(2));
+
+ Assert.assertEquals(item3, mMenu.findItem(3));
+ Assert.assertEquals(item4, mMenu.findItem(4));
+ Assert.assertEquals(item5, mMenu.findItem(5));
+ mMenu.removeGroup(groupId);
+ Assert.assertNull(mMenu.findItem(3));
+ Assert.assertNull(mMenu.findItem(4));
+ Assert.assertNull(mMenu.findItem(5));
+
+ Assert.assertEquals(item6, mMenu.findItem(6));
+ mMenu.clear();
+ Assert.assertNull(mMenu.findItem(6));
+ }
+
+ private KeyEvent makeKeyEvent(int keyCode, int metaState) {
+ return new KeyEvent(0L, 0L, KeyEvent.ACTION_DOWN, keyCode, 0, metaState);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java
new file mode 100644
index 0000000..2f3df10
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/MonitorTest.java
@@ -0,0 +1,469 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class MonitorTest extends TestCase {
+
+ @MediumTest
+ public void testWaitArgumentsTest() throws Exception {
+ /* Try some valid arguments. These should all
+ * return very quickly.
+ */
+ try {
+ synchronized (this) {
+ /* millisecond version */
+ wait(1);
+ wait(10);
+
+ /* millisecond + nanosecond version */
+ wait(0, 1);
+ wait(0, 999999);
+ wait(1, 1);
+ wait(1, 999999);
+ }
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("good Object.wait() interrupted",
+ ex);
+ } catch (Exception ex) {
+ throw new RuntimeException("Unexpected exception when calling" +
+ "Object.wait() with good arguments", ex);
+ }
+
+ /* Try some invalid arguments.
+ */
+ boolean sawException = false;
+ try {
+ synchronized (this) {
+ wait(-1);
+ }
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("bad Object.wait() interrupted", ex);
+ } catch (IllegalArgumentException ex) {
+ sawException = true;
+ } catch (Exception ex) {
+ throw new RuntimeException("Unexpected exception when calling" +
+ "Object.wait() with bad arguments", ex);
+ }
+ if (!sawException) {
+ throw new RuntimeException("bad call to Object.wait() should " +
+ "have thrown IllegalArgumentException");
+ }
+
+ sawException = false;
+ try {
+ synchronized (this) {
+ wait(0, -1);
+ }
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("bad Object.wait() interrupted", ex);
+ } catch (IllegalArgumentException ex) {
+ sawException = true;
+ } catch (Exception ex) {
+ throw new RuntimeException("Unexpected exception when calling" +
+ "Object.wait() with bad arguments", ex);
+ }
+ if (!sawException) {
+ throw new RuntimeException("bad call to Object.wait() should " +
+ "have thrown IllegalArgumentException");
+ }
+
+ sawException = false;
+ try {
+ synchronized (this) {
+ /* The legal range of nanos is 0-999999. */
+ wait(0, 1000000);
+ }
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("bad Object.wait() interrupted", ex);
+ } catch (IllegalArgumentException ex) {
+ sawException = true;
+ } catch (Exception ex) {
+ throw new RuntimeException("Unexpected exception when calling" +
+ "Object.wait() with bad arguments", ex);
+ }
+ if (!sawException) {
+ throw new RuntimeException("bad call to Object.wait() should " +
+ "have thrown IllegalArgumentException");
+ }
+ }
+
+ private class Interrupter extends Thread {
+ Waiter waiter;
+
+ Interrupter(String name, Waiter waiter) {
+ super(name);
+ this.waiter = waiter;
+ }
+
+ public void run() {
+ try {
+ run_inner();
+ } catch (Throwable t) {
+ MonitorTest.errorException = t;
+ MonitorTest.testThread.interrupt();
+ }
+ }
+
+ void run_inner() {
+ waiter.spin = true;
+ // System.out.println("InterruptTest: starting waiter");
+ waiter.start();
+
+ try {
+ Thread.currentThread().sleep(500);
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("Test sleep interrupted.", ex);
+ }
+
+ /* Waiter is spinning, and its monitor should still be thin.
+ */
+ // System.out.println("Test interrupting waiter");
+ waiter.interrupt();
+ waiter.spin = false;
+
+ for (int i = 0; i < 3; i++) {
+ /* Wait for the waiter to start waiting.
+ */
+ synchronized (waiter.interrupterLock) {
+ try {
+ waiter.interrupterLock.wait();
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("Test wait interrupted.", ex);
+ }
+ }
+
+ /* Before interrupting, grab the waiter lock, which
+ * guarantees that the waiter is already sitting in wait().
+ */
+ synchronized (waiter) {
+ //System.out.println("Test interrupting waiter (" + i + ")");
+ waiter.interrupt();
+ }
+ }
+
+ // System.out.println("Test waiting for waiter to die.");
+ try {
+ waiter.join();
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("Test join interrupted.", ex);
+ }
+ // System.out.println("InterruptTest done.");
+ }
+ }
+
+ private class Waiter extends Thread {
+ Object interrupterLock = new Object();
+ Boolean spin = false;
+
+ Waiter(String name) {
+ super(name);
+ }
+
+ public void run() {
+ try {
+ run_inner();
+ } catch (Throwable t) {
+ MonitorTest.errorException = t;
+ MonitorTest.testThread.interrupt();
+ }
+ }
+
+ void run_inner() {
+ // System.out.println("Waiter spinning");
+ while (spin) {
+ // We're going to get interrupted while we spin.
+ }
+ if (interrupted()) {
+ // System.out.println("Waiter done spinning; interrupted.");
+ } else {
+ throw new RuntimeException("Thread not interrupted " +
+ "during spin");
+ }
+
+ synchronized (this) {
+ Boolean sawEx = false;
+
+ try {
+ synchronized (interrupterLock) {
+ interrupterLock.notify();
+ }
+ // System.out.println("Waiter calling wait()");
+ this.wait();
+ } catch (InterruptedException ex) {
+ sawEx = true;
+ // System.out.println("wait(): Waiter caught " + ex);
+ }
+ // System.out.println("wait() finished");
+
+ if (!sawEx) {
+ throw new RuntimeException("Thread not interrupted " +
+ "during wait()");
+ }
+ }
+ synchronized (this) {
+ Boolean sawEx = false;
+
+ try {
+ synchronized (interrupterLock) {
+ interrupterLock.notify();
+ }
+ // System.out.println("Waiter calling wait(1000)");
+ this.wait(1000);
+ } catch (InterruptedException ex) {
+ sawEx = true;
+ // System.out.println("wait(1000): Waiter caught " + ex);
+ }
+ // System.out.println("wait(1000) finished");
+
+ if (!sawEx) {
+ throw new RuntimeException("Thread not interrupted " +
+ "during wait(1000)");
+ }
+ }
+ synchronized (this) {
+ Boolean sawEx = false;
+
+ try {
+ synchronized (interrupterLock) {
+ interrupterLock.notify();
+ }
+ // System.out.println("Waiter calling wait(1000, 5000)");
+ this.wait(1000, 5000);
+ } catch (InterruptedException ex) {
+ sawEx = true;
+ // System.out.println("wait(1000, 5000): Waiter caught " + ex);
+ }
+ // System.out.println("wait(1000, 5000) finished");
+
+ if (!sawEx) {
+ throw new RuntimeException("Thread not interrupted " +
+ "during wait(1000, 5000)");
+ }
+ }
+
+ // System.out.println("Waiter returning");
+ }
+ }
+
+ private static Throwable errorException;
+ private static Thread testThread;
+
+ @MediumTest
+ public void testInterruptTest() throws Exception {
+
+
+ testThread = Thread.currentThread();
+ errorException = null;
+
+ Waiter waiter = new Waiter("InterruptTest Waiter");
+ Interrupter interrupter =
+ new Interrupter("InterruptTest Interrupter", waiter);
+ interrupter.start();
+
+ try {
+ interrupter.join();
+ waiter.join();
+ } catch (InterruptedException ex) {
+ throw new RuntimeException("Test join interrupted.", ex);
+ }
+
+ if (errorException != null) {
+ throw new RuntimeException("InterruptTest failed",
+ errorException);
+ }
+
+
+
+
+ }
+
+ private static void deepWait(int depth, Object lock) {
+ synchronized (lock) {
+ if (depth > 0) {
+ deepWait(depth - 1, lock);
+ } else {
+ String threadName = Thread.currentThread().getName();
+ try {
+ // System.out.println(threadName + " waiting");
+ lock.wait();
+ // System.out.println(threadName + " done waiting");
+ } catch (InterruptedException ex) {
+ // System.out.println(threadName + " interrupted.");
+ }
+ }
+ }
+ }
+
+ private class Worker extends Thread {
+ Object lock;
+ int id;
+
+ Worker(int id, Object lock) {
+ super("Worker(" + id + ")");
+ this.id = id;
+ this.lock = lock;
+ }
+
+ public void run() {
+ int iterations = 0;
+
+ while (MonitorTest.running) {
+ MonitorTest.deepWait(id, lock);
+ iterations++;
+ }
+ // System.out.println(getName() + " done after " + iterations + " iterations.");
+ }
+ }
+
+ private static Object commonLock = new Object();
+ private static Boolean running = false;
+
+
+ @LargeTest
+ public void testNestedMonitors() throws Exception {
+ final int NUM_WORKERS = 5;
+
+ Worker w[] = new Worker[NUM_WORKERS];
+ int i;
+
+ for (i = 0; i < NUM_WORKERS; i++) {
+ w[i] = new Worker(i * 2 - 1, new Object());
+ }
+
+ running = true;
+
+ // System.out.println("NestedMonitors: starting workers");
+ for (i = 0; i < NUM_WORKERS; i++) {
+ w[i].start();
+ }
+
+ try {
+ Thread.currentThread().sleep(1000);
+ } catch (InterruptedException ex) {
+ // System.out.println("Test sleep interrupted.");
+ }
+
+ for (i = 0; i < 100; i++) {
+ for (int j = 0; j < NUM_WORKERS; j++) {
+ synchronized (w[j].lock) {
+ w[j].lock.notify();
+ }
+ }
+ }
+
+ // System.out.println("NesterMonitors: stopping workers");
+ running = false;
+ for (i = 0; i < NUM_WORKERS; i++) {
+ synchronized (w[i].lock) {
+ w[i].lock.notifyAll();
+ }
+ }
+ }
+
+ private static class CompareAndExchange extends Thread {
+ static Object toggleLock = null;
+ static int toggle = -1;
+ static Boolean running = false;
+
+ public void run() {
+ toggleLock = new Object();
+ toggle = -1;
+
+ Worker w1 = new Worker(0, 1);
+ Worker w2 = new Worker(2, 3);
+ Worker w3 = new Worker(4, 5);
+ Worker w4 = new Worker(6, 7);
+
+ running = true;
+
+ // System.out.println("CompareAndExchange: starting workers");
+
+ w1.start();
+ w2.start();
+ w3.start();
+ w4.start();
+
+ try {
+ this.sleep(10000);
+ } catch (InterruptedException ex) {
+ // System.out.println(getName() + " interrupted.");
+ }
+
+ // System.out.println("MonitorTest: stopping workers");
+ running = false;
+
+ toggleLock = null;
+ }
+
+ class Worker extends Thread {
+ int i1;
+ int i2;
+
+ Worker(int i1, int i2) {
+ super("Worker(" + i1 + ", " + i2 + ")");
+ this.i1 = i1;
+ this.i2 = i2;
+ }
+
+ public void run() {
+ int iterations = 0;
+
+ /* Latch this because run() may set the static field to
+ * null at some point.
+ */
+ Object toggleLock = CompareAndExchange.toggleLock;
+
+ // System.out.println(getName() + " running");
+ try {
+ while (CompareAndExchange.running) {
+ synchronized (toggleLock) {
+ int test;
+ int check;
+
+ if (CompareAndExchange.toggle == i1) {
+ this.sleep(5 + i2);
+ CompareAndExchange.toggle = test = i2;
+ } else {
+ this.sleep(5 + i1);
+ CompareAndExchange.toggle = test = i1;
+ }
+ if ((check = CompareAndExchange.toggle) != test) {
+// System.out.println("Worker(" + i1 + ", " +
+// i2 + ") " + "test " + test +
+// " != toggle " + check);
+ throw new RuntimeException(
+ "locked value changed");
+ }
+ }
+
+ iterations++;
+ }
+ } catch (InterruptedException ex) {
+ // System.out.println(getName() + " interrupted.");
+ }
+
+// System.out.println(getName() + " done after " +
+// iterations + " iterations.");
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
new file mode 100644
index 0000000..3462f97
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTestSuite.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2005 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+import android.test.FrameworkTests;
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestSuite;
+import junit.framework.TestCase;
+
+public class NewDatabasePerformanceTestSuite extends TestSuite {
+ public static TestSuite suite() {
+ TestSuite suite =
+ new TestSuite(NewDatabasePerformanceTestSuite.class.getName());
+
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Insert1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertIndexed1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Select100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringComparison100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoin100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoinOneSide100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InnerJoinNoIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectSubQIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndexStringComparison100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectInteger100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectString100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIntegerIndex100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIndexString100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringStartsWith100.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteIndexed1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ Delete1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ DeleteIndexWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ UpdateIndexWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ UpdateWhere1000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertInteger10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertIntegerIndex10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertString10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ InsertStringIndexed10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringStartsWith10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringIndexedStartsWith10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectInteger10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectIntegerIndexed10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringContains10000.class);
+ suite.addTestSuite(NewDatabasePerformanceTests.
+ SelectStringIndexedContains10000.class);
+
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
new file mode 100644
index 0000000..8644fbb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/NewDatabasePerformanceTests.java
@@ -0,0 +1,1234 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentValues;
+import android.database.sqlite.SQLiteDatabase;
+import android.test.PerformanceTestCase;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.Random;
+
+/**
+ * Database Performance Tests
+ *
+ */
+
+public class NewDatabasePerformanceTests {
+
+ // Edit this to change the test run times. The original is 100.
+ final static int kMultiplier = 1;
+
+ public static class PerformanceBase extends TestCase
+ implements PerformanceTestCase {
+ protected static final int CURRENT_DATABASE_VERSION = 42;
+ protected SQLiteDatabase mDatabase;
+ protected File mDatabaseFile;
+
+ public void setUp() {
+ mDatabaseFile = new File("/sdcard", "perf_database_test.db");
+ if (mDatabaseFile.exists()) {
+ mDatabaseFile.delete();
+ }
+ mDatabase =
+ SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(),
+ null);
+ assertTrue(mDatabase != null);
+ mDatabase.setVersion(CURRENT_DATABASE_VERSION);
+ }
+
+ public void tearDown() {
+ mDatabase.close();
+ mDatabaseFile.delete();
+ }
+
+ public boolean isPerformanceOnly() {
+ return true;
+ }
+
+ // These tests can only be run once.
+ public int startPerformance(Intermediates intermediates) {
+ return 0;
+ }
+
+ public String numberName(int number) {
+ String result = "";
+
+ if (number >= 1000) {
+ result += numberName((number / 1000)) + " thousand";
+ number = (number % 1000);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number >= 100) {
+ result += ONES[(number / 100)] + " hundred";
+ number = (number % 100);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number >= 20) {
+ result += TENS[(number / 10)];
+ number = (number % 10);
+
+ if (number > 0) result += " ";
+ }
+
+ if (number > 0) {
+ result += ONES[number];
+ }
+
+ return result;
+ }
+ }
+
+ /**
+ * Test 1000 inserts.
+ */
+
+ public static class Insert1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+
+ private String[] statements = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ statements[i] =
+ "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')";
+ }
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.execSQL(statements[i]);
+ }
+ }
+ }
+
+ /**
+ * Test 1000 inserts into an indexed table.
+ */
+
+ public static class InsertIndexed1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+
+ private String[] statements = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ statements[i] =
+ "INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')";
+ }
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.execSQL(statements[i]);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs without an index
+ */
+
+ public static class Select100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on a string comparison
+ */
+
+ public static class SelectStringComparison100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "c LIKE '" + numberName(i) + "'";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs with an index
+ */
+
+ public static class SelectIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * INNER JOIN without an index
+ */
+
+ public static class InnerJoin100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * INNER JOIN without an index on one side
+ */
+
+ public static class InnerJoinOneSide100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.b = t2.b", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * INNER JOIN without an index on one side
+ */
+
+ public static class InnerJoinNoIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+ }
+
+ public void testRun() {
+ mDatabase.query("t1 INNER JOIN t2 ON t1.c = t2.c", COLUMNS, null,
+ null, null, null, null);
+ }
+ }
+
+ /**
+ * 100 SELECTs with subqueries. Subquery is using an index
+ */
+
+ public static class SelectSubQIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"t1.a"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase
+ .execSQL("CREATE TABLE t2(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ mDatabase.execSQL("CREATE INDEX i2b ON t2(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t2 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] =
+ "t1.b IN (SELECT t2.b FROM t2 WHERE t2.b >= " + lower
+ + " AND t2.b < " + upper + ")";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on string comparison with Index
+ */
+
+ public static class SelectIndexStringComparison100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"count(*)", "avg(b)"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "c LIKE '" + numberName(i) + "'";
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on integer
+ */
+
+ public static class SelectInteger100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"b"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String
+ */
+
+ public static class SelectString100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on integer with index
+ */
+
+ public static class SelectIntegerIndex100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"b"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b on t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String with index
+ */
+
+ public static class SelectIndexString100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t1", COLUMNS, null, null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 100 SELECTs on String with starts with
+ */
+
+ public static class SelectStringStartsWith100 extends PerformanceBase {
+ private static final int SIZE = 1 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "c LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase
+ .query("t1", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 Deletes on an indexed table
+ */
+
+ public static class DeleteIndexed1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3c ON t1(c)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 Deletes
+ */
+
+ public static class Delete1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private static final String[] COLUMNS = {"c"};
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", null, null);
+ }
+ }
+ }
+
+ /**
+ * 1000 DELETE's without an index with where clause
+ */
+
+ public static class DeleteWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 DELETE's with an index with where clause
+ */
+
+ public static class DeleteIndexWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.delete("t1", where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 update's with an index with where clause
+ */
+
+ public static class UpdateIndexWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1b ON t1(b)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ ContentValues b = new ContentValues(1);
+ b.put("b", upper);
+ mValues[i] = b;
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.update("t1", mValues[i], where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 1000 update's without an index with where clause
+ */
+
+ public static class UpdateWhere1000 extends PerformanceBase {
+ private static final int SIZE = 10 * kMultiplier;
+ private String[] where = new String[SIZE];
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER, b INTEGER, c VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t1 VALUES(" + i + "," + r + ",'"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "b >= " + lower + " AND b < " + upper;
+ ContentValues b = new ContentValues(1);
+ b.put("b", upper);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.update("t1", mValues[i], where[i], null);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for an integer
+ */
+
+ public static class InsertInteger10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", r);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for an integer -indexed table
+ */
+
+ public static class InsertIntegerIndex10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a INTEGER)");
+ mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", r);
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for a String
+ */
+
+ public static class InsertString10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", numberName(r));
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+ /**
+ * 10000 inserts for a String - indexed table
+ */
+
+ public static class InsertStringIndexed10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ ContentValues[] mValues = new ContentValues[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t1(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i1a ON t1(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ ContentValues b = new ContentValues(1);
+ b.put("a", numberName(r));
+ mValues[i] = b;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.insert("t1", null, mValues[i]);
+ }
+ }
+ }
+
+
+ /**
+ * 10000 selects for a String -starts with
+ */
+
+ public static class SelectStringStartsWith10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for a String - indexed table -starts with
+ */
+
+ public static class SelectStringIndexedStartsWith10000 extends
+ PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ where[i] = "a LIKE '" + numberName(r).substring(0, 1) + "*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for an integer -
+ */
+
+ public static class SelectInteger10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t4.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t4(a INTEGER)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "a >= " + lower + " AND a < " + upper;
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for an integer -indexed table
+ */
+
+ public static class SelectIntegerIndexed10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t4.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t4(a INTEGER)");
+ mDatabase.execSQL("CREATE INDEX i4a ON t4(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t4 VALUES(" + r + ")");
+
+ int lower = i * 100;
+ int upper = (i + 10) * 100;
+ where[i] = "a >= " + lower + " AND a < " + upper;
+ }
+
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t4", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+
+ /**
+ * 10000 selects for a String - contains 'e'
+ */
+
+ public static class SelectStringContains10000 extends PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "a LIKE '*e*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ /**
+ * 10000 selects for a String - contains 'e'-indexed table
+ */
+
+ public static class SelectStringIndexedContains10000 extends
+ PerformanceBase {
+ private static final int SIZE = 100 * kMultiplier;
+ private static final String[] COLUMNS = {"t3.a"};
+ private String[] where = new String[SIZE];
+
+ @Override
+ public void setUp() {
+ super.setUp();
+ Random random = new Random(42);
+
+ mDatabase
+ .execSQL("CREATE TABLE t3(a VARCHAR(100))");
+ mDatabase.execSQL("CREATE INDEX i3a ON t3(a)");
+
+ for (int i = 0; i < SIZE; i++) {
+ int r = random.nextInt(100000);
+ mDatabase.execSQL("INSERT INTO t3 VALUES('"
+ + numberName(r) + "')");
+ }
+
+ for (int i = 0; i < SIZE; i++) {
+ where[i] = "a LIKE '*e*'";
+
+ }
+ }
+
+ public void testRun() {
+ for (int i = 0; i < SIZE; i++) {
+ mDatabase.query("t3", COLUMNS, where[i], null, null, null, null);
+ }
+ }
+ }
+
+ public static final String[] ONES =
+ {"zero", "one", "two", "three", "four", "five", "six", "seven",
+ "eight", "nine", "ten", "eleven", "twelve", "thirteen",
+ "fourteen", "fifteen", "sixteen", "seventeen", "eighteen",
+ "nineteen"};
+
+ public static final String[] TENS =
+ {"", "ten", "twenty", "thirty", "forty", "fifty", "sixty",
+ "seventy", "eighty", "ninety"};
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java
new file mode 100644
index 0000000..d4d2a82
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ParentalControlTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.google.android.net.ParentalControl;
+import com.google.android.net.ParentalControlState;
+
+import android.os.SystemClock;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+import junit.framework.Assert;
+
+public class ParentalControlTest extends AndroidTestCase {
+
+ private boolean mOnResultCalled = false;
+
+ public class Callback implements ParentalControl.Callback {
+ public void onResult(ParentalControlState state) {
+ synchronized (ParentalControlTest.class) {
+ mOnResultCalled = true;
+ ParentalControlTest.class.notifyAll();
+ }
+ }
+ }
+
+ @SmallTest
+ public void testParentalControlCallback() {
+ synchronized (ParentalControlTest.class) {
+ ParentalControl.getParentalControlState(new Callback(), null);
+ try {
+ long start = SystemClock.uptimeMillis();
+ ParentalControlTest.class.wait(20 * 1000);
+ long end = SystemClock.uptimeMillis();
+ Log.d("AndroidTests", "ParentalControlTest callback took " + (end-start) + " ms.");
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ Assert.assertTrue(mOnResultCalled);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java
new file mode 100644
index 0000000..9e54540
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/PerformanceTests.java
@@ -0,0 +1,1223 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.os.Debug;
+import junit.framework.Assert;
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+import org.apache.harmony.dalvik.NativeTestTarget;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class PerformanceTests {
+ public static String[] children() {
+ return new String[] {
+ //StringEquals2.class.getName(),
+ //StringEquals10.class.getName(),
+ //StringEquals20.class.getName(),
+ //StringEquals200.class.getName(),
+ //StringEquals200U.class.getName(),
+ //StringCompareTo10.class.getName(),
+ //StringCompareTo200.class.getName(),
+ StringLength.class.getName(),
+ StringCrawl.class.getName(),
+ Ackermann.class.getName(),
+ AddTest.class.getName(),
+// AddMemberVariableTest.class.getName(),
+ ArrayListIterator.class.getName(),
+ BoundsCheckTest.class.getName(),
+// EmptyClassBaseTest.class.getName(),
+ EmptyJniStaticMethod0.class.getName(),
+ EmptyJniStaticMethod6.class.getName(),
+ EmptyJniStaticMethod6L.class.getName(),
+ FibonacciFast.class.getName(),
+ FibonacciSlow.class.getName(),
+// LoopTests.class.getName(),
+// HashMapTest.class.getName(),
+// InterfaceTests.class.getName(),
+ LocalVariableAccess.class.getName(),
+ MemeberVariableAccess.class.getName(),
+ NestedLoop.class.getName(),
+// StringConcatenationTests.class.getName(),
+// ArrayListBase.class.getName(),
+ SynchronizedGetAndSetInt.class.getName(),
+
+ /* this will not work on JamVM -- lacks atomic ops */
+ AtomicGetAndSetInt.class.getName(),
+ };
+ }
+
+ public static class SizeTest {
+ private int mSize;
+
+ public SizeTest(int size) {
+ mSize = size;
+ }
+
+ public int size() {
+ return mSize;
+ }
+ }
+
+ public static class LocalVariableAccess extends PerformanceTestBase {
+ private static final int ITERATIONS = 100000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 20);
+ return 0;
+ }
+
+ public void testRun() {
+ boolean variable = false;
+ boolean local = true;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable; // 5
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable; // 10
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable; // 15
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable;
+ local = variable; // 20
+ }
+ }
+ }
+
+ /* This test is intentionally misspelled. Please do not rename it. Thanks! */
+ public static class MemeberVariableAccess extends PerformanceTestBase {
+ private static final int ITERATIONS = 100000;
+
+ public volatile boolean mMember = false;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 20);
+ return 0;
+ }
+
+ public void testRun() {
+ boolean local = true;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember; // 5
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember; // 10
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember; // 15
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember;
+ local = mMember; // 20
+ }
+ }
+ }
+
+ public static class ArrayListIterator extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private ArrayList mList;
+ private String[] mKeys;
+ private Iterator mIterator;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mList = new ArrayList();
+ mKeys = new String[ITERATIONS];
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mKeys[i] = Integer.toString(i, 16);
+ mList.add(mKeys[i]);
+ }
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testRun() {
+ mIterator = mList.iterator();
+ while (mIterator.hasNext()) {
+ mIterator.next();
+ }
+ }
+ }
+
+ public static class Ackermann extends PerformanceTestBase {
+ public static final int ITERATIONS = 100;
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testRun() {
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ ackermann(3, 13);
+ }
+ }
+
+ private int ackermann(int m, int n) {
+ if (m == 0)
+ return n + 1;
+ if (n == 0)
+ return ackermann(m - 1, 1);
+ return ackermann(m, n - 1);
+ }
+ }
+
+ public static class FibonacciSlow extends PerformanceTestBase {
+ public void setUp() throws Exception {
+ super.setUp();
+ Assert.assertEquals(0, fibonacci(0));
+ Assert.assertEquals(1, fibonacci(1));
+ Assert.assertEquals(1, fibonacci(2));
+ Assert.assertEquals(2, fibonacci(3));
+ Assert.assertEquals(6765, fibonacci(20));
+ }
+
+ public void tearDown() {
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ return 0;
+ }
+
+ public void testRun() {
+ fibonacci(20);
+ }
+
+ private long fibonacci(long n) {
+ if (n == 0)
+ return 0;
+ if (n == 1)
+ return 1;
+ return fibonacci(n - 2) + fibonacci(n - 1);
+ }
+ }
+
+ public static class FibonacciFast extends PerformanceTestBase {
+ public void setUp() throws Exception {
+ super.setUp();
+ Assert.assertEquals(0, fibonacci(0));
+ Assert.assertEquals(1, fibonacci(1));
+ Assert.assertEquals(1, fibonacci(2));
+ Assert.assertEquals(2, fibonacci(3));
+ Assert.assertEquals(6765, fibonacci(20));
+ }
+
+ public void tearDown() {
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ return 0;
+ }
+
+ public void testRun() {
+ fibonacci(5000);
+ }
+
+ private long fibonacci(long n) {
+ if (n == 0)
+ return 0;
+ if (n == 1)
+ return 1;
+
+ int x = 0;
+ int y = 1;
+ for (int i = 0; i < n - 1; i++) {
+ y = y + x;
+ x = y - x;
+ }
+
+ return y;
+ }
+ }
+
+ public static class HashMapTest extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private HashMap mMap;
+ private String[] mKeys;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mMap = new HashMap();
+ mKeys = new String[ITERATIONS];
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mKeys[i] = Integer.toString(i, 16);
+ mMap.put(mKeys[i], i);
+ }
+ }
+
+ public void tearDown() {
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testHashMapContainsKey() {
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mMap.containsKey(mKeys[i]);
+ }
+ }
+
+ public void testHashMapIterator() {
+ Iterator iterator;
+
+ iterator = mMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ iterator.next();
+ }
+ }
+
+ public void testHashMapPut() {
+ HashMap map = new HashMap();
+ String[] keys = mKeys;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ map.put(keys[i], i);
+ }
+ }
+ }
+
+ interface IA {
+ void funcA0();
+ void funcA1();
+ void funcA2();
+ void funcA3();
+ }
+ interface IAB extends IA {
+ void funcAB0();
+ void funcAB1();
+ void funcAB2();
+ void funcAB3();
+ }
+ interface IABC extends IAB {
+ void funcABC0();
+ void funcABC1();
+ void funcABC2();
+ void funcABC3();
+ }
+ interface IB {
+ void funcB0();
+ void funcB1();
+ void funcB2();
+ void funcB3();
+ }
+ interface IC {
+ void funcC0();
+ void funcC1();
+ void funcC2();
+ void funcC3();
+ }
+
+ static class Alphabet implements Cloneable, IB, IABC, IC, Runnable {
+ public void funcA0() {
+ }
+ public void funcA1() {
+ }
+ public void funcA2() {
+ }
+ public void funcA3() {
+ }
+ public void funcAB0() {
+ }
+ public void funcAB1() {
+ }
+ public void funcAB2() {
+ }
+ public void funcAB3() {
+ }
+ public void funcABC0() {
+ }
+ public void funcABC1() {
+ }
+ public void funcABC2() {
+ }
+ public void funcABC3() {
+ }
+ public void funcB0() {
+ }
+ public void funcB1() {
+ }
+ public void funcB2() {
+ }
+ public void funcB3() {
+ }
+ public void funcC0() {
+ }
+ public void funcC1() {
+ }
+ public void funcC2() {
+ }
+ public void funcC3() {
+ }
+ public void run() {
+ }
+ };
+
+ public static class InterfaceTests extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ /* call method directly */
+ public void testInterfaceCalls0() {
+ Alphabet alpha = new Alphabet();
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ alpha.funcABC1();
+ }
+ }
+
+ /* call method through interface reference */
+ public void testInterfaceCalls1() {
+ Alphabet alpha = new Alphabet();
+ IABC iabc = alpha;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ iabc.funcABC1();
+ }
+ }
+
+ public void testInstanceOfTrivial() {
+ Alphabet alpha = new Alphabet();
+ IABC iabc = alpha;
+ boolean val;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ val = iabc instanceof Alphabet;
+ }
+ }
+
+ public void testInstanceOfInterface() {
+ Alphabet alpha = new Alphabet();
+ IABC iabc = alpha;
+ boolean val;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ val = iabc instanceof IA;
+ }
+ }
+
+ public void testInstanceOfNot() {
+ Alphabet alpha = new Alphabet();
+ IABC iabc = alpha;
+ boolean val;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ val = iabc instanceof EmptyInterface;
+ }
+ }
+ }
+
+ public static class NestedLoop extends PerformanceTestBase {
+ private static final int ITERATIONS = 10;
+ private static final int LOOPS = 5;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * LOOPS);
+ return 0;
+ }
+
+ public void testRun() {
+ int x = 0;
+ for (int a = 0; a < ITERATIONS; a++) {
+ for (int b = 0; b < ITERATIONS; b++) {
+ for (int c = 0; c < ITERATIONS; c++) {
+ for (int d = 0; d < ITERATIONS; d++) {
+ for (int e = 0; e < ITERATIONS; e++) {
+ x++;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public static class StringConcatenationTests extends PerformanceTestBase {
+ private static final int ITERATIONS = 1000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testStringConcatenation1() {
+ StringBuffer buffer = new StringBuffer();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ buffer.append("Hello World!\n");
+ }
+ buffer = null;
+ }
+
+ public void testStringConcatenation2() {
+ String string = "";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ string += "Hello World!\n";
+ }
+ string = null;
+ }
+ }
+
+ public static class StringLength extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ String testStr = TEST_STRING;
+ int length;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ length = testStr.length();
+ }
+ }
+ }
+
+ public static class EmptyJniStaticMethod0 extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ int a, b, c, d, e, f;
+
+ a = b = c = d = e = f = 0;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ }
+ }
+ }
+ public static class EmptyJniStaticMethod6 extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ int a, b, c, d, e, f;
+
+ a = b = c = d = e = f = 0;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ }
+ }
+ }
+ public static class EmptyJniStaticMethod6L extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ String a = null;
+ String[] b = null;
+ int[][] c = null;
+ Object d = null;
+ Object[] e = null;
+ Object[][][][] f = null;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6L(a, b, c, d, e, f);
+ }
+ }
+ }
+
+ public static class StringCrawl extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private static final String TEST_STRING = "This is the string we use for testing..."; // 40 chars
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * TEST_STRING.length());
+ return 0;
+ }
+
+ public void testRun() {
+ String testStr = TEST_STRING;
+ char ch;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ /* this is the wrong way to walk through a string */
+ for (int j = 0; j < testStr.length(); j++) {
+ ch = testStr.charAt(j);
+ }
+ }
+ }
+ }
+
+ public static class AddTest extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 20);
+ return 0;
+ }
+
+ public void testRun() {
+ int j = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ }
+ }
+ }
+
+ public static class AddMemberVariableTest extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private int j;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ j = 0;
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testAddMemberVariableTest() {
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ j++;
+ }
+ }
+
+ public void testAddMemberVariableInMethodTest() {
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ add();
+ add();
+ add();
+ add();
+ add();
+ add();
+ add();
+ add();
+ add();
+ add();
+ }
+ }
+
+ public void add() {
+ j++;
+ }
+ }
+
+ private interface EmptyInterface {
+ public void emptyVirtual();
+
+ }
+
+ private static class EmptyClass implements EmptyInterface {
+ public void emptyVirtual() {
+ }
+
+ public static void emptyStatic() {
+ }
+ }
+
+ public static class EmptyClassBaseTest extends PerformanceTestBase {
+ protected EmptyInterface mEmptyInterface;
+ protected EmptyClass mEmptyClass;
+
+ public void setUp() throws Exception {
+ super.setUp();
+ mEmptyClass = new EmptyClass();
+ mEmptyInterface = mEmptyClass;
+ }
+ private static final int ITERATIONS = 10000;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testEmptyVirtualMethod() {
+ //EmptyClass emtpyClass = mEmptyClass;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ mEmptyClass.emptyVirtual();
+ }
+ }
+
+ public void testEmptyVirtualMethodTestInLocal() {
+ EmptyClass empty = mEmptyClass;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ empty.emptyVirtual();
+ }
+ }
+
+ public void testEmptyStaticMethod () {
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ EmptyClass.emptyStatic();
+ }
+ }
+
+ public void testEmptyJniStaticMethod0() {
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ NativeTestTarget.emptyJniStaticMethod0();
+ }
+ }
+
+ public void testEmptyJniStaticMethod6() {
+ int a, b, c, d, e, f;
+
+ a = b = c = d = e = f = 0;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ NativeTestTarget.emptyJniStaticMethod6(a, b, c, d, e, f);
+ }
+ }
+
+ public void testEmptyInternalStaticMethod() {
+ /*
+ * The method called is a VM-internal method with no extra
+ * wrapping.
+ */
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ NativeTestTarget.emptyInternalStaticMethod();
+ }
+ }
+
+ public void testEmptyInlineStaticMethod() {
+ /*
+ * The method called is a VM-internal method that gets
+ * specially "inlined" in a bytecode transformation.
+ */
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ NativeTestTarget.emptyInlineMethod();
+ }
+ }
+
+ public void testEmptyInterfaceMethodTest() {
+ EmptyInterface emptyInterface = mEmptyInterface;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ emptyInterface.emptyVirtual();
+ }
+ }
+ }
+
+ public static class LoopTests extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ private SizeTest mSizeTest = new SizeTest(ITERATIONS);
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testForLoopTest() {
+ int i = 0;
+ for (; i < 10000; i++) {
+ }
+ }
+
+ public void testWhileLoopTest() {
+ int i = 0;
+
+ while (i < 10000) {
+ i++;
+ }
+ }
+
+ public void testForLoopSizeCalledInside() {
+ for (int i = 0; i < mSizeTest.size(); i++) {
+ }
+ }
+
+ public void testForLoopSizeCalledOutside() {
+ final int size = mSizeTest.size();
+ for (int i = 0; i < size; i++) {
+ }
+ }
+ }
+
+ public static class BoundsCheckTest extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ int[] data = new int[1];
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ data[0] = i;
+ }
+ }
+ }
+
+ public static class ArrayListBase extends PerformanceTestBase {
+ public void setUp() throws Exception {
+ super.setUp();
+ mList = new ArrayList();
+ mList.add(0);
+ mList.add(1);
+ mList.add(2);
+ mList.add(3);
+ mList.add(4);
+ mList.add(5);
+ mList.add(6);
+ mList.add(7);
+ mList.add(8);
+ mList.add(9);
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(100);
+ return 0;
+ }
+
+ ArrayList<Integer> mList;
+
+ public void testForArrayList() {
+ int i = 0;
+ int res = 0;
+ for (; i < 100; i++) {
+ for (int j = 0; j < mList.size(); j++) {
+ res += mList.get(j);
+ }
+ }
+ }
+
+ public void testForLocalArrayList() {
+ int i = 0;
+ int res = 0;
+ for (; i < 100; i++) {
+ final List<Integer> list = mList;
+ final int N = list.size();
+ for (int j = 0; j < N; j++) {
+ res += list.get(j);
+ }
+ }
+ }
+
+ public void testForEachArrayList() {
+ int i = 0;
+ int res = 0;
+ for (; i < 100; i++) {
+ for (Integer v : mList) {
+ res += v;
+ }
+ }
+ }
+ }
+
+ public static class SynchronizedGetAndSetInt extends PerformanceTestBase {
+ private static final int ITERATIONS = 100000;
+
+ public int mMember = 0;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testRun() {
+ int result = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ synchronized (this) {
+ result = mMember;
+ mMember = i;
+ }
+ }
+ }
+ }
+
+ public static class AtomicGetAndSetInt extends PerformanceTestBase {
+ private static final int ITERATIONS = 100000;
+
+ public AtomicInteger mMember = new AtomicInteger(0);
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testRun() {
+ int result = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = mMember.getAndSet(i);
+ }
+ }
+ }
+
+ public static abstract class StringEquals extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ protected String mString1, mString2;
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ String string1 = mString1;
+ String string2 = mString2;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ string1.equals(string2);
+ }
+ }
+ }
+
+ public static class StringEquals2 extends StringEquals {
+ public void setUp() throws Exception {
+ mString1 = "01";
+ mString2 = "0x";
+ }
+ }
+ public static class StringEquals10 extends StringEquals {
+ public void setUp() throws Exception {
+ mString1 = "0123456789";
+ mString2 = "012345678x";
+ }
+ }
+ public static class StringEquals20 extends StringEquals {
+ public void setUp() throws Exception {
+ mString1 = "01234567890123456789";
+ mString2 = "0123456789012345678x";
+ }
+ }
+
+ public static class StringEquals200 extends StringEquals {
+ public void setUp() throws Exception {
+ mString1 = "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789";
+ mString2 = "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "012345678901234567890123456789012345678x";
+ }
+ }
+ public static class StringEquals200U extends StringEquals {
+ /* make one of the strings non-word aligned (bad memcmp case) */
+ public void setUp() throws Exception {
+ String tmpStr;
+ mString1 = "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789";
+ tmpStr = "z0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "012345678901234567890123456789012345678x";
+ mString2 = tmpStr.substring(1);
+ }
+ }
+
+ public static abstract class StringCompareTo extends PerformanceTestBase {
+ private static final int ITERATIONS = 10000;
+
+ protected String mString1, mString2;
+
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS * 10);
+ return 0;
+ }
+
+ public void testRun() {
+ String string1 = mString1;
+ String string2 = mString2;
+
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ string1.compareTo(string2);
+ }
+ }
+ }
+ public static class StringCompareTo10 extends StringCompareTo {
+ public void setUp() throws Exception {
+ mString1 = "0123456789";
+ mString2 = "012345678x";
+ }
+ }
+ public static class StringCompareTo200 extends StringCompareTo {
+ public void setUp() throws Exception {
+ mString1 = "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789";
+ mString2 = "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "0123456789012345678901234567890123456789"
+ + "012345678901234567890123456789012345678x";
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java
new file mode 100644
index 0000000..8f55044
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/RegexTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.util.Regex;
+import junit.framework.TestCase;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class RegexTest extends TestCase {
+
+ @SmallTest
+ public void testTldPattern() throws Exception {
+ boolean t;
+
+ t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("com").matches();
+ assertTrue("Missed valid TLD", t);
+
+ t = Regex.TOP_LEVEL_DOMAIN_PATTERN.matcher("xer").matches();
+ assertFalse("Matched invalid TLD!", t);
+ }
+
+ @SmallTest
+ public void testUrlPattern() throws Exception {
+ boolean t;
+
+ t = Regex.WEB_URL_PATTERN.matcher("http://www.google.com").matches();
+ assertTrue("Valid URL", t);
+
+ t = Regex.WEB_URL_PATTERN.matcher("ftp://www.example.com").matches();
+ assertFalse("Matched invalid protocol", t);
+
+ t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080").matches();
+ assertTrue("Didn't match valid URL with port", t);
+
+ t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/?foo=bar").matches();
+ assertTrue("Didn't match valid URL with port and query args", t);
+
+ t = Regex.WEB_URL_PATTERN.matcher("http://www.example.com:8080/~user/?foo=bar").matches();
+ assertTrue("Didn't match valid URL with ~", t);
+ }
+
+ @SmallTest
+ public void testIpPattern() throws Exception {
+ boolean t;
+
+ t = Regex.IP_ADDRESS_PATTERN.matcher("172.29.86.3").matches();
+ assertTrue("Valid IP", t);
+
+ t = Regex.IP_ADDRESS_PATTERN.matcher("1234.4321.9.9").matches();
+ assertFalse("Invalid IP", t);
+ }
+
+ @SmallTest
+ public void testDomainPattern() throws Exception {
+ boolean t;
+
+ t = Regex.DOMAIN_NAME_PATTERN.matcher("mail.example.com").matches();
+ assertTrue("Valid domain", t);
+
+ t = Regex.DOMAIN_NAME_PATTERN.matcher("__+&42.xer").matches();
+ assertFalse("Invalid domain", t);
+ }
+
+ @SmallTest
+ public void testPhonePattern() throws Exception {
+ boolean t;
+
+ t = Regex.PHONE_PATTERN.matcher("(919) 555-1212").matches();
+ assertTrue("Valid phone", t);
+
+ t = Regex.PHONE_PATTERN.matcher("2334 9323/54321").matches();
+ assertFalse("Invalid phone", t);
+
+ String[] tests = {
+ "Me: 16505551212 this\n",
+ "Me: 6505551212 this\n",
+ "Me: 5551212 this\n",
+
+ "Me: 1-650-555-1212 this\n",
+ "Me: (650) 555-1212 this\n",
+ "Me: +1 (650) 555-1212 this\n",
+ "Me: +1-650-555-1212 this\n",
+ "Me: 650-555-1212 this\n",
+ "Me: 555-1212 this\n",
+
+ "Me: 1.650.555.1212 this\n",
+ "Me: (650) 555.1212 this\n",
+ "Me: +1 (650) 555.1212 this\n",
+ "Me: +1.650.555.1212 this\n",
+ "Me: 650.555.1212 this\n",
+ "Me: 555.1212 this\n",
+
+ "Me: 1 650 555 1212 this\n",
+ "Me: (650) 555 1212 this\n",
+ "Me: +1 (650) 555 1212 this\n",
+ "Me: +1 650 555 1212 this\n",
+ "Me: 650 555 1212 this\n",
+ "Me: 555 1212 this\n",
+ };
+
+ for (String test : tests) {
+ Matcher m = Regex.PHONE_PATTERN.matcher(test);
+
+ assertTrue("Valid phone " + test, m.find());
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
new file mode 100644
index 0000000..ce0b53d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SMSTest.java
@@ -0,0 +1,277 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.internal.telephony.gsm.GsmAlphabet;
+import com.android.internal.telephony.gsm.SmsHeader;
+import com.android.internal.util.HexDump;
+import android.telephony.gsm.SmsMessage;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.Iterator;
+
+public class SMSTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testOne() throws Exception {
+ String pdu = "07914151551512f2040B916105551511f100006060605130308A04D4F29C0E";
+
+ SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertEquals("+14155551212", sms.getServiceCenterAddress());
+ assertEquals("+16505551111", sms.getOriginatingAddress());
+ assertEquals("Test", sms.getMessageBody());
+ //assertTrue(sms.scTimeMillis == 1152223383000L);
+
+ pdu = "07914151551512f2040B916105551511f100036060924180008A0DA"
+ + "8695DAC2E8FE9296A794E07";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertEquals("+14155551212", sms.getServiceCenterAddress());
+ assertEquals("+16505551111", sms.getOriginatingAddress());
+ assertEquals("(Subject)Test", sms.getMessageBody());
+
+ /* lines[0] = "+CMT: ,45";
+ lines[1] = "07914140279510F6440A8111110301003BF56070624111958A8C0B05040B8423F"
+ + "000033702010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
+ + "6D65737361676500AF848D018BB4848C8298524D66616E304A6D7135514141416"
+ + "57341414141546741414E4E304141414141008D908918802B3136353032343836"
+ + "3137392F545950453D504C4D4E009646573A20008A808E0222C788058103093A7"
+ + "F836874";
+
+ sms = SMSMessage.createFromPdu(mContext, lines);
+ */
+
+ pdu = "07914140279510F6440A8111110301003BF56080207130138A8C0B05040B8423F"
+ + "000032A02010106276170706C69636174696F6E2F766E642E7761702E6D6D732D"
+ + "6D65737361676500AF848D0185B4848C8298524E453955304A6D7135514141426"
+ + "66C414141414D7741414236514141414141008D908918802B3135313232393737"
+ + "3638332F545950453D504C4D4E008A808E022B918805810306977F83687474703"
+ + "A2F2F36";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ SmsHeader header = sms.getUserDataHeader();
+ assertNotNull(header);
+
+ Iterator<SmsHeader.Element> elements = header.getElements().iterator();
+ assertNotNull(elements);
+
+
+ pdu = "07914140279510F6440A8111110301003BF56080207130238A3B0B05040B8423F"
+ + "000032A0202362E3130322E3137312E3135302F524E453955304A6D7135514141"
+ + "42666C414141414D774141423651414141414100";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ header = sms.getUserDataHeader();
+ assertNotNull(header);
+
+ elements = header.getElements().iterator();
+ assertNotNull(elements);
+
+ /*
+ * UCS-2 encoded SMS
+ */
+
+ pdu = "07912160130300F4040B914151245584F600087010807121352B10212200A900AE00680065006C006C006F";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+ assertEquals("\u2122\u00a9\u00aehello", sms.getMessageBody());
+
+ // Entire alphabet (minus the escape character)
+
+ /****
+ lines[0] = "+CMT: ";
+ lines[1] = "0001000A8114455245680000808080604028180E888462C168381E90886442A9582E988C06C0E9783EA09068442A994EA8946AC56AB95EB0986C46ABD96EB89C6EC7EBF97EC0A070482C1A8FC8A472C96C3A9FD0A8744AAD5AAFD8AC76CBED7ABFE0B0784C2E9BCFE8B47ACD6EBBDFF0B87C4EAFDBEFF8BC7ECFEFFBFF";
+ sms = SMSMessage.createFromPdu(mContext, lines);
+
+ System.out.println("full alphabet message body len: "
+ + sms.getMessageBody().length());
+
+ System.out.println("'" + sms.getMessageBody() +"'");
+
+ assertTrue(sms.getMessageBody().length() == 128);
+ ****/
+
+ /*
+ * Multi-part text SMS with data in septets
+ */
+ pdu = "07916163838408F6440B816105224431F700007060217175830AA0050003"
+ + "00020162B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+ + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+ + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+ + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562B1582C"
+ + "168BC562B1582C168BC562B1582C168BC562B1582C168BC562";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+ assertEquals(sms.getMessageBody(),
+ "1111111111111111111111111111111111111111"
+ + "1111111111111111111111111111111111111111"
+ + "1111111111111111111111111111111111111111"
+ + "111111111111111111111111111111111");
+
+ pdu = "07916163838408F6440B816105224431F700007060217185000A23050003"
+ + "00020262B1582C168BC96432994C2693C96432994C2693C96432990C";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+ assertEquals("1111111222222222222222222222", sms.getMessageBody());
+ }
+
+ @SmallTest
+ public void testCPHSVoiceMail() throws Exception {
+ // "set MWI flag"
+
+ String pdu = "07912160130310F20404D0110041006060627171118A0120";
+
+ SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertTrue(sms.isReplace());
+ assertEquals("_@", sms.getOriginatingAddress());
+ assertEquals(" ", sms.getMessageBody());
+ assertTrue(sms.isMWISetMessage());
+
+ // "clear mwi flag"
+
+ pdu = "07912160130310F20404D0100041006021924193352B0120";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertTrue(sms.isMWIClearMessage());
+
+ // "clear MWI flag"
+
+ pdu = "07912160130310F20404D0100041006060627161058A0120";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+// System.out.println("originating address: "
+// + (int) (sms.getOriginatingAddress().charAt(0)) + " "
+// + (int) (sms.getOriginatingAddress().charAt(1)));
+
+ assertTrue(sms.isReplace());
+ assertEquals("\u0394@", sms.getOriginatingAddress());
+ assertEquals(" ", sms.getMessageBody());
+ assertTrue(sms.isMWIClearMessage());
+ }
+
+ @SmallTest
+ public void testCingularVoiceMail() throws Exception {
+ // "set MWI flag"
+
+ String pdu = "07912180958750F84401800500C87020026195702B06040102000200";
+ SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertTrue(sms.isMWISetMessage());
+ assertTrue(sms.isMwiDontStore());
+
+ // "clear mwi flag"
+
+ pdu = "07912180958750F84401800500C07020027160112B06040102000000";
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertTrue(sms.isMWIClearMessage());
+ assertTrue(sms.isMwiDontStore());
+ }
+
+// public void testTwo() throws Exception {
+// // FIXME need an SMS-SUBMIT test
+//
+// System.out.println(
+// "SMS SUBMIT: " + SmsMessage.getSubmitPdu(null, "+14155551212", "test", false));
+// }
+
+ @SmallTest
+ public void testEmailGateway() throws Exception {
+ // email gateway sms test
+ String pdu = "07914151551512f204038105f300007011103164638a28e6f71b50c687db" +
+ "7076d9357eb7412f7a794e07cdeb6275794c07bde8e5391d247e93f3";
+
+ SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertEquals("+14155551212", sms.getServiceCenterAddress());
+ assertTrue(sms.isEmail());
+ assertEquals("foo@example.com", sms.getEmailFrom());
+ assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
+ assertEquals("test subject", sms.getPseudoSubject());
+ assertEquals("test body", sms.getDisplayMessageBody());
+ assertEquals("test body", sms.getEmailBody());
+
+ // email gateway sms test, including gsm extended character set.
+ pdu = "07914151551512f204038105f400007011103105458a29e6f71b50c687db" +
+ "7076d9357eb741af0d0a442fcfe9c23739bfe16d289bdee6b5f1813629";
+
+ sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertEquals("+14155551212", sms.getServiceCenterAddress());
+ assertTrue(sms.isEmail());
+ assertEquals("foo@example.com", sms.getDisplayOriginatingAddress());
+ assertEquals("foo@example.com", sms.getEmailFrom());
+ assertEquals("{ testBody[^~\\] }", sms.getDisplayMessageBody());
+ assertEquals("{ testBody[^~\\] }", sms.getEmailBody());
+ }
+
+ @SmallTest
+ public void testExtendedCharacterTable() throws Exception {
+ String pdu = "07914151551512f2040B916105551511f100006080615131728A44D4F29C0E2" +
+ "AE3E96537B94C068DD16179784C2FCB41F4B0985D06B958ADD00FB0E94536AF9749" +
+ "74DA6D281BA00E95E26D509B946FC3DBF87A25D56A04";
+
+ SmsMessage sms = SmsMessage.createFromPdu(HexDump.hexStringToByteArray(pdu));
+
+ assertEquals("+14155551212", sms.getServiceCenterAddress());
+ assertEquals("+16505551111", sms.getOriginatingAddress());
+ assertEquals("Test extended character table .,-!?@~_\\/&\"';^|:()<{}>[]=%*+#", sms.getMessageBody());
+ }
+
+ @SmallTest
+ public void testDecode() throws Exception {
+ byte[] septets = new byte[(7 * 128 + 7) / 8];
+
+ int bitOffset = 0;
+
+ for (int i = 0; i < 128; i++) {
+ int v;
+ if (i == 0x1b) {
+ // extended escape char
+ v = 0;
+ } else {
+ v = i;
+ }
+
+ int byteOffset = bitOffset / 8;
+ int shift = bitOffset % 8;
+
+ septets[byteOffset] |= v << shift;
+
+ if (shift > 1) {
+ septets[byteOffset + 1] = (byte) (v >> (8 - shift));
+ }
+
+ bitOffset += 7;
+ }
+
+ String decoded = GsmAlphabet.gsm7BitPackedToString(septets, 0, 128);
+ byte[] reEncoded = GsmAlphabet.stringToGsm7BitPacked(decoded);
+
+ // reEncoded has the count septets byte at the front
+ assertEquals(reEncoded.length, septets.length + 1);
+
+ for (int i = 0; i < septets.length; i++) {
+ assertEquals(reEncoded[i + 1], septets[i]);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
new file mode 100644
index 0000000..5d7349f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SSLClientSessionCacheFactoryTest.java
@@ -0,0 +1,54 @@
+package com.android.unit_tests;
+
+import com.google.android.net.SSLClientSessionCacheFactory;
+import com.android.internal.net.DbSSLSessionCache;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.provider.Settings;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+/**
+ * Unit test for {@link SSLClientSessionCacheFactory}.
+ */
+@MediumTest
+public final class SSLClientSessionCacheFactoryTest extends AndroidTestCase {
+
+ protected void tearDown() throws Exception {
+ setSslSessionCacheValue(getContext(), "");
+ super.tearDown();
+ }
+
+ private static void setSslSessionCacheValue(Context context, String value) {
+ ContentResolver resolver = context.getContentResolver();
+ Settings.Gservices.putString(resolver, Settings.Gservices.SSL_SESSION_CACHE, value);
+ }
+
+ private static SSLClientSessionCache getCache(Context context, String type) {
+ setSslSessionCacheValue(context, type);
+ return SSLClientSessionCacheFactory.getCache(context);
+ }
+
+ public void testGetDbCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "db");
+ assertNotNull(cache);
+ assertTrue(cache instanceof DbSSLSessionCache);
+ }
+
+ public void testGetFileCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "file");
+ assertNotNull(cache);
+ // yuck =)
+ assertEquals("org.apache.harmony.xnet.provider.jsse.FileClientSessionCache$Impl",
+ cache.getClass().getName());
+ }
+
+ public void testGetNoCache() throws Exception {
+ Context context = getContext();
+ SSLClientSessionCache cache = getCache(context, "none");
+ assertNull(cache);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java
new file mode 100644
index 0000000..9481180
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SSLTest.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.SSLCertificateSocketFactory;
+import android.test.suitebuilder.annotation.Suppress;
+import junit.framework.TestCase;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+//This test relies on network resources.
+@Suppress
+public class SSLTest extends TestCase {
+ public void testCertificate() throws Exception {
+ // test www.fortify.net/sslcheck.html
+ Socket ssl = SSLCertificateSocketFactory.getDefault().createSocket("www.fortify.net",443);
+ assertNotNull(ssl);
+
+ OutputStream out = ssl.getOutputStream();
+ assertNotNull(out);
+
+ InputStream in = ssl.getInputStream();
+ assertNotNull(in);
+
+ String get = "GET /sslcheck.html HTTP/1.1\r\nHost: 68.178.217.222\r\n\r\n";
+
+ // System.out.println("going for write...");
+ out.write(get.getBytes());
+
+ byte[] b = new byte[1024];
+ // System.out.println("going for read...");
+ int ret = in.read(b);
+
+ // System.out.println(new String(b));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java
new file mode 100644
index 0000000..d488a29
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SafeSaxTest.java
@@ -0,0 +1,539 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.graphics.Bitmap;
+import android.sax.Element;
+import android.sax.ElementListener;
+import android.sax.EndTextElementListener;
+import android.sax.RootElement;
+import android.sax.StartElementListener;
+import android.sax.TextElementListener;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.format.Time;
+import android.util.Log;
+import android.util.Xml;
+import com.android.internal.util.XmlUtils;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.helpers.DefaultHandler;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+public class SafeSaxTest extends AndroidTestCase {
+
+ private static final String TAG = SafeSaxTest.class.getName();
+
+ private static final String ATOM_NAMESPACE = "http://www.w3.org/2005/Atom";
+ private static final String MEDIA_NAMESPACE = "http://search.yahoo.com/mrss/";
+ private static final String YOUTUBE_NAMESPACE = "http://gdata.youtube.com/schemas/2007";
+ private static final String GDATA_NAMESPACE = "http://schemas.google.com/g/2005";
+
+ private static class ElementCounter implements ElementListener {
+ int starts = 0;
+ int ends = 0;
+
+ public void start(Attributes attributes) {
+ starts++;
+ }
+
+ public void end() {
+ ends++;
+ }
+ }
+
+ private static class TextElementCounter implements TextElementListener {
+ int starts = 0;
+ String bodies = "";
+
+ public void start(Attributes attributes) {
+ starts++;
+ }
+
+ public void end(String body) {
+ this.bodies += body;
+ }
+ }
+
+ @SmallTest
+ public void testListener() throws Exception {
+ String xml = "<feed xmlns='http://www.w3.org/2005/Atom'>\n"
+ + "<entry>\n"
+ + "<id>a</id>\n"
+ + "</entry>\n"
+ + "<entry>\n"
+ + "<id>b</id>\n"
+ + "</entry>\n"
+ + "</feed>\n";
+
+ RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
+ Element entry = root.requireChild(ATOM_NAMESPACE, "entry");
+ Element id = entry.requireChild(ATOM_NAMESPACE, "id");
+
+ ElementCounter rootCounter = new ElementCounter();
+ ElementCounter entryCounter = new ElementCounter();
+ TextElementCounter idCounter = new TextElementCounter();
+
+ root.setElementListener(rootCounter);
+ entry.setElementListener(entryCounter);
+ id.setTextElementListener(idCounter);
+
+ Xml.parse(xml, root.getContentHandler());
+
+ assertEquals(1, rootCounter.starts);
+ assertEquals(1, rootCounter.ends);
+ assertEquals(2, entryCounter.starts);
+ assertEquals(2, entryCounter.ends);
+ assertEquals(2, idCounter.starts);
+ assertEquals("ab", idCounter.bodies);
+ }
+
+ @SmallTest
+ public void testMissingRequiredChild() throws Exception {
+ String xml = "<feed></feed>";
+ RootElement root = new RootElement("feed");
+ root.requireChild("entry");
+
+ try {
+ Xml.parse(xml, root.getContentHandler());
+ fail("expected exception not thrown");
+ } catch (SAXException e) {
+ // Expected.
+ }
+ }
+
+ @SmallTest
+ public void testMixedContent() throws Exception {
+ String xml = "<feed><entry></entry></feed>";
+
+ RootElement root = new RootElement("feed");
+ root.setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ }
+ });
+
+ try {
+ Xml.parse(xml, root.getContentHandler());
+ fail("expected exception not thrown");
+ } catch (SAXException e) {
+ // Expected.
+ }
+ }
+
+ @LargeTest
+ public void testPerformance() throws Exception {
+ InputStream in = mContext.getResources().openRawResource(R.raw.youtube);
+ byte[] xmlBytes;
+ try {
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ byte[] buffer = new byte[1024];
+ int length;
+ while ((length = in.read(buffer)) != -1) {
+ out.write(buffer, 0, length);
+ }
+ xmlBytes = out.toByteArray();
+ } finally {
+ in.close();
+ }
+
+ Log.i("***", "File size: " + (xmlBytes.length / 1024) + "k");
+
+ VideoAdapter videoAdapter = new VideoAdapter();
+ ContentHandler handler = newContentHandler(videoAdapter);
+ for (int i = 0; i < 2; i++) {
+ pureSaxTest(new ByteArrayInputStream(xmlBytes));
+ saxyModelTest(new ByteArrayInputStream(xmlBytes));
+ saxyModelTest(new ByteArrayInputStream(xmlBytes), handler);
+ }
+ }
+
+ private static void pureSaxTest(InputStream inputStream) throws IOException, SAXException {
+ long start = System.currentTimeMillis();
+ VideoAdapter videoAdapter = new VideoAdapter();
+ Xml.parse(inputStream, Xml.Encoding.UTF_8, new YouTubeContentHandler(videoAdapter));
+ long elapsed = System.currentTimeMillis() - start;
+ Log.i(TAG, "pure SAX: " + elapsed + "ms");
+ }
+
+ private static void saxyModelTest(InputStream inputStream) throws IOException, SAXException {
+ long start = System.currentTimeMillis();
+ VideoAdapter videoAdapter = new VideoAdapter();
+ Xml.parse(inputStream, Xml.Encoding.UTF_8, newContentHandler(videoAdapter));
+ long elapsed = System.currentTimeMillis() - start;
+ Log.i(TAG, "Saxy Model: " + elapsed + "ms");
+ }
+
+ private static void saxyModelTest(InputStream inputStream, ContentHandler contentHandler)
+ throws IOException, SAXException {
+ long start = System.currentTimeMillis();
+ Xml.parse(inputStream, Xml.Encoding.UTF_8, contentHandler);
+ long elapsed = System.currentTimeMillis() - start;
+ Log.i(TAG, "Saxy Model (preloaded): " + elapsed + "ms");
+ }
+
+ private static class VideoAdapter {
+ public void addVideo(YouTubeVideo video) {
+ }
+ }
+
+ private static ContentHandler newContentHandler(VideoAdapter videoAdapter) {
+ return new HandlerFactory().newContentHandler(videoAdapter);
+ }
+
+ private static class HandlerFactory {
+ YouTubeVideo video;
+
+ public ContentHandler newContentHandler(VideoAdapter videoAdapter) {
+ RootElement root = new RootElement(ATOM_NAMESPACE, "feed");
+
+ final VideoListener videoListener = new VideoListener(videoAdapter);
+
+ Element entry = root.getChild(ATOM_NAMESPACE, "entry");
+
+ entry.setElementListener(videoListener);
+
+ entry.getChild(ATOM_NAMESPACE, "id")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.videoId = body;
+ }
+ });
+
+ entry.getChild(ATOM_NAMESPACE, "published")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ // TODO(tomtaylor): programmatically get the timezone
+ video.dateAdded = new Time(Time.TIMEZONE_UTC);
+ video.dateAdded.parse3339(body);
+ }
+ });
+
+ Element author = entry.getChild(ATOM_NAMESPACE, "author");
+ author.getChild(ATOM_NAMESPACE, "name")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.authorName = body;
+ }
+ });
+
+ Element mediaGroup = entry.getChild(MEDIA_NAMESPACE, "group");
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "thumbnail")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String url = attributes.getValue("", "url");
+ if (video.thumbnailUrl == null && url.length() > 0) {
+ video.thumbnailUrl = url;
+ }
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "content")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String url = attributes.getValue("", "url");
+ if (url != null) {
+ video.videoUrl = url;
+ }
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "player")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String url = attributes.getValue("", "url");
+ if (url != null) {
+ video.playbackUrl = url;
+ }
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "title")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.title = body;
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "category")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.category = body;
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "description")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.description = body;
+ }
+ });
+
+ mediaGroup.getChild(MEDIA_NAMESPACE, "keywords")
+ .setEndTextElementListener(new EndTextElementListener() {
+ public void end(String body) {
+ video.tags = body;
+ }
+ });
+
+ mediaGroup.getChild(YOUTUBE_NAMESPACE, "duration")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String seconds = attributes.getValue("", "seconds");
+ video.lengthInSeconds
+ = XmlUtils.convertValueToInt(seconds, 0);
+ }
+ });
+
+ mediaGroup.getChild(YOUTUBE_NAMESPACE, "statistics")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String viewCount = attributes.getValue("", "viewCount");
+ video.viewCount
+ = XmlUtils.convertValueToInt(viewCount, 0);
+ }
+ });
+
+ entry.getChild(GDATA_NAMESPACE, "rating")
+ .setStartElementListener(new StartElementListener() {
+ public void start(Attributes attributes) {
+ String average = attributes.getValue("", "average");
+ video.rating = average == null
+ ? 0.0f : Float.parseFloat(average);
+ }
+ });
+
+ return root.getContentHandler();
+ }
+
+ class VideoListener implements ElementListener {
+
+ final VideoAdapter videoAdapter;
+
+ public VideoListener(VideoAdapter videoAdapter) {
+ this.videoAdapter = videoAdapter;
+ }
+
+ public void start(Attributes attributes) {
+ video = new YouTubeVideo();
+ }
+
+ public void end() {
+ videoAdapter.addVideo(video);
+ video = null;
+ }
+ }
+ }
+
+ private static class YouTubeContentHandler extends DefaultHandler {
+
+ final VideoAdapter videoAdapter;
+
+ YouTubeVideo video = null;
+ StringBuilder builder = null;
+
+ public YouTubeContentHandler(VideoAdapter videoAdapter) {
+ this.videoAdapter = videoAdapter;
+ }
+
+ @Override
+ public void startElement(String uri, String localName, String qName,
+ Attributes attributes) throws SAXException {
+ if (uri.equals(ATOM_NAMESPACE)) {
+ if (localName.equals("entry")) {
+ video = new YouTubeVideo();
+ return;
+ }
+
+ if (video == null) {
+ return;
+ }
+
+ if (!localName.equals("id")
+ && !localName.equals("published")
+ && !localName.equals("name")) {
+ return;
+ }
+ this.builder = new StringBuilder();
+ return;
+
+ }
+
+ if (video == null) {
+ return;
+ }
+
+ if (uri.equals(MEDIA_NAMESPACE)) {
+ if (localName.equals("thumbnail")) {
+ String url = attributes.getValue("", "url");
+ if (video.thumbnailUrl == null && url.length() > 0) {
+ video.thumbnailUrl = url;
+ }
+ return;
+ }
+
+ if (localName.equals("content")) {
+ String url = attributes.getValue("", "url");
+ if (url != null) {
+ video.videoUrl = url;
+ }
+ return;
+ }
+
+ if (localName.equals("player")) {
+ String url = attributes.getValue("", "url");
+ if (url != null) {
+ video.playbackUrl = url;
+ }
+ return;
+ }
+
+ if (localName.equals("title")
+ || localName.equals("category")
+ || localName.equals("description")
+ || localName.equals("keywords")) {
+ this.builder = new StringBuilder();
+ return;
+ }
+
+ return;
+ }
+
+ if (uri.equals(YOUTUBE_NAMESPACE)) {
+ if (localName.equals("duration")) {
+ video.lengthInSeconds = XmlUtils.convertValueToInt(
+ attributes.getValue("", "seconds"), 0);
+ return;
+ }
+
+ if (localName.equals("statistics")) {
+ video.viewCount = XmlUtils.convertValueToInt(
+ attributes.getValue("", "viewCount"), 0);
+ return;
+ }
+
+ return;
+ }
+
+ if (uri.equals(GDATA_NAMESPACE)) {
+ if (localName.equals("rating")) {
+ String average = attributes.getValue("", "average");
+ video.rating = average == null
+ ? 0.0f : Float.parseFloat(average);
+ }
+ }
+ }
+
+ @Override
+ public void characters(char text[], int start, int length)
+ throws SAXException {
+ if (builder != null) {
+ builder.append(text, start, length);
+ }
+ }
+
+ String takeText() {
+ try {
+ return builder.toString();
+ } finally {
+ builder = null;
+ }
+ }
+
+ @Override
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException {
+ if (video == null) {
+ return;
+ }
+
+ if (uri.equals(ATOM_NAMESPACE)) {
+ if (localName.equals("published")) {
+ // TODO(tomtaylor): programmatically get the timezone
+ video.dateAdded = new Time(Time.TIMEZONE_UTC);
+ video.dateAdded.parse3339(takeText());
+ return;
+ }
+
+ if (localName.equals("name")) {
+ video.authorName = takeText();
+ return;
+ }
+
+ if (localName.equals("id")) {
+ video.videoId = takeText();
+ return;
+ }
+
+ if (localName.equals("entry")) {
+ // Add the video!
+ videoAdapter.addVideo(video);
+ video = null;
+ return;
+ }
+
+ return;
+ }
+
+ if (uri.equals(MEDIA_NAMESPACE)) {
+ if (localName.equals("description")) {
+ video.description = takeText();
+ return;
+ }
+
+ if (localName.equals("keywords")) {
+ video.tags = takeText();
+ return;
+ }
+
+ if (localName.equals("category")) {
+ video.category = takeText();
+ return;
+ }
+
+ if (localName.equals("title")) {
+ video.title = takeText();
+ }
+ }
+ }
+ }
+
+ private static class YouTubeVideo {
+ public String videoId; // the id used to lookup on YouTube
+ public String videoUrl; // the url to play the video
+ public String playbackUrl; // the url to share for users to play video
+ public String thumbnailUrl; // the url of the thumbnail image
+ public String title;
+ public Bitmap bitmap; // cached bitmap of the thumbnail
+ public int lengthInSeconds;
+ public int viewCount; // number of times the video has been viewed
+ public float rating; // ranges from 0.0 to 5.0
+ public Boolean triedToLoadThumbnail;
+ public String authorName;
+ public Time dateAdded;
+ public String category;
+ public String tags;
+ public String description;
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
new file mode 100644
index 0000000..09e3b02
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SearchManagerTest.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.android.unit_tests.activity.LocalActivity;
+
+import android.app.Activity;
+import android.app.ISearchManager;
+import android.app.SearchManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ResolveInfo;
+import android.content.res.Resources;
+import android.content.res.XmlResourceParser;
+import android.os.ServiceManager;
+import android.server.search.SearchableInfo;
+import android.server.search.SearchableInfo.ActionKeyInfo;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.MoreAsserts;
+import android.test.mock.MockContext;
+import android.test.mock.MockPackageManager;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.AndroidRuntimeException;
+import android.view.KeyEvent;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * To launch this test from the command line:
+ *
+ * adb shell am instrument -w \
+ * -e class com.android.unit_tests.SearchManagerTest \
+ * com.android.unit_tests/android.test.InstrumentationTestRunner
+ */
+public class SearchManagerTest extends ActivityInstrumentationTestCase<LocalActivity> {
+
+ // If non-zero, enable a set of tests that start and stop the search manager.
+ // This is currently disabled because it's causing an unwanted jump from the unit test
+ // activity into the contacts activity. We'll put this back after we disable that jump.
+ private static final int TEST_SEARCH_START = 0;
+
+ /*
+ * Bug list of test ideas.
+ *
+ * testSearchManagerInterfaceAvailable()
+ * Exercise the interface obtained
+ *
+ * testSearchManagerAvailable()
+ * Exercise the interface obtained
+ *
+ * testSearchManagerInvocations()
+ * FIX - make it work again
+ * stress test with a very long string
+ *
+ * SearchableInfo tests
+ * Mock the context so I can provide very specific input data
+ * Confirm OK with "zero" searchables
+ * Confirm "good" metadata read properly
+ * Confirm "bad" metadata skipped properly
+ * Confirm ordering of searchables
+ * Confirm "good" actionkeys
+ * confirm "bad" actionkeys are rejected
+ * confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+ * findActionKey works
+ * getIcon works
+ *
+ * SearchManager tests
+ * confirm proper identification of "default" activity based on policy, not hardcoded contacts
+ *
+ * SearchBar tests
+ * Maybe have to do with framework / unittest runner - need instrumented activity?
+ * How can we unit test the suggestions content providers?
+ * Should I write unit tests for any of them?
+ * Test scenarios:
+ * type-BACK (cancel)
+ * type-GO (send)
+ * type-navigate-click (suggestion)
+ * type-action
+ * type-navigate-action (suggestion)
+ */
+
+ /**
+ * Local copy of activity context
+ */
+ Context mContext;
+
+ public SearchManagerTest() {
+ super("com.android.unit_tests", LocalActivity.class);
+ }
+
+ /**
+ * Setup any common data for the upcoming tests.
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ Activity testActivity = getActivity();
+ mContext = (Context)testActivity;
+ }
+
+ /**
+ * The goal of this test is to confirm that we can obtain
+ * a search manager interface.
+ */
+ @MediumTest
+ public void testSearchManagerInterfaceAvailable() {
+ ISearchManager searchManager1 = ISearchManager.Stub.asInterface(
+ ServiceManager.getService(Context.SEARCH_SERVICE));
+ assertNotNull(searchManager1);
+ }
+
+ /**
+ * The goal of this test is to confirm that we can *only* obtain a search manager
+ * interface from an Activity context.
+ */
+ @MediumTest
+ public void testSearchManagerContextRestrictions() {
+ SearchManager searchManager1 = (SearchManager)
+ mContext.getSystemService(Context.SEARCH_SERVICE);
+ assertNotNull(searchManager1);
+
+ Context applicationContext = mContext.getApplicationContext();
+ // this should fail, because you can't get a SearchManager from a non-Activity context
+ try {
+ applicationContext.getSystemService(Context.SEARCH_SERVICE);
+ assertFalse("Shouldn't retrieve SearchManager from a non-Activity context", true);
+ } catch (AndroidRuntimeException e) {
+ // happy here - we should catch this.
+ }
+ }
+
+ /**
+ * The goal of this test is to confirm that we can obtain
+ * a search manager at any time, and that for any given context,
+ * it is a singleton.
+ */
+ @LargeTest
+ public void testSearchManagerAvailable() {
+ SearchManager searchManager1 = (SearchManager)
+ mContext.getSystemService(Context.SEARCH_SERVICE);
+ assertNotNull(searchManager1);
+ SearchManager searchManager2 = (SearchManager)
+ mContext.getSystemService(Context.SEARCH_SERVICE);
+ assertNotNull(searchManager2);
+ assertSame( searchManager1, searchManager2 );
+ }
+
+ /**
+ * The goal of this test is to confirm that we can start and then
+ * stop a simple search.
+ */
+
+ @MediumTest
+ public void testSearchManagerInvocations() {
+ SearchManager searchManager = (SearchManager)
+ mContext.getSystemService(Context.SEARCH_SERVICE);
+ assertNotNull(searchManager);
+
+ // TODO: make a real component name, or remove this need
+ final ComponentName cn = new ComponentName("", "");
+
+ if (TEST_SEARCH_START != 0) {
+ // These tests should simply run to completion w/o exceptions
+ searchManager.startSearch(null, false, cn, null, false);
+ searchManager.stopSearch();
+
+ searchManager.startSearch("", false, cn, null, false);
+ searchManager.stopSearch();
+
+ searchManager.startSearch("test search string", false, cn, null, false);
+ searchManager.stopSearch();
+
+ searchManager.startSearch("test search string", true, cn, null, false);
+ searchManager.stopSearch();
+ }
+ }
+
+ /**
+ * The goal of this test is to confirm proper operation of the
+ * SearchableInfo helper class.
+ *
+ * TODO: The metadata source needs to be mocked out because adding
+ * searchability metadata via this test is causing it to leak into the
+ * real system. So for now I'm just going to test for existence of the
+ * GoogleSearch app (which is searchable).
+ */
+ @LargeTest
+ public void testSearchableGoogleSearch() {
+ // test basic array & hashmap
+ SearchableInfo.buildSearchableList(mContext);
+
+ // test linkage from another activity
+ // TODO inject this via mocking into the package manager.
+ // TODO for now, just check for searchable GoogleSearch app (this isn't really a unit test)
+ ComponentName thisActivity = new ComponentName(
+ "com.android.googlesearch",
+ "com.android.googlesearch.GoogleSearch");
+
+ SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, thisActivity);
+ assertNotNull(si);
+ assertTrue(si.mSearchable);
+ assertEquals(thisActivity, si.mSearchActivity);
+
+ Context appContext = si.getActivityContext(mContext);
+ assertNotNull(appContext);
+ MoreAsserts.assertNotEqual(appContext, mContext);
+ assertEquals("Google Search", appContext.getString(si.getHintId()));
+ assertEquals("Google", appContext.getString(si.getLabelId()));
+ }
+
+ /**
+ * Test that non-searchable activities return no searchable info (this would typically
+ * trigger the use of the default searchable e.g. contacts)
+ */
+ @LargeTest
+ public void testNonSearchable() {
+ // test basic array & hashmap
+ SearchableInfo.buildSearchableList(mContext);
+
+ // confirm that we return null for non-searchy activities
+ ComponentName nonActivity = new ComponentName(
+ "com.android.unit_tests",
+ "com.android.unit_tests.NO_SEARCH_ACTIVITY");
+ SearchableInfo si = SearchableInfo.getSearchableInfo(mContext, nonActivity);
+ assertNull(si);
+ }
+
+ /**
+ * This is an attempt to run the searchable info list with a mocked context. Here are some
+ * things I'd like to test.
+ *
+ * Confirm OK with "zero" searchables
+ * Confirm "good" metadata read properly
+ * Confirm "bad" metadata skipped properly
+ * Confirm ordering of searchables
+ * Confirm "good" actionkeys
+ * confirm "bad" actionkeys are rejected
+ * confirm XML ordering enforced (will fail today - bug in SearchableInfo)
+ * findActionKey works
+ * getIcon works
+
+ */
+ @LargeTest
+ public void testSearchableMocked() {
+ MyMockPackageManager mockPM = new MyMockPackageManager(mContext.getPackageManager());
+ MyMockContext mockContext = new MyMockContext(mContext, mockPM);
+ ArrayList<SearchableInfo> searchables;
+ int count;
+
+ // build item list with real-world source data
+ mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_PASSTHROUGH);
+ SearchableInfo.buildSearchableList(mockContext);
+ // tests with "real" searchables (deprecate, this should be a unit test)
+ searchables = SearchableInfo.getSearchablesList();
+ count = searchables.size();
+ assertTrue(count >= 1); // this isn't really a unit test
+ checkSearchables(searchables);
+
+ // build item list with mocked search data
+ // this round of tests confirms good operations with "zero" searchables found
+ // This should return either a null pointer or an empty list
+ mockPM.setSearchablesMode(MyMockPackageManager.SEARCHABLES_MOCK_ZERO);
+ SearchableInfo.buildSearchableList(mockContext);
+ searchables = SearchableInfo.getSearchablesList();
+ if (searchables != null) {
+ count = searchables.size();
+ assertTrue(count == 0);
+ }
+ }
+
+ /**
+ * Generic health checker for an array of searchables.
+ *
+ * This is designed to pass for any semi-legal searchable, without knowing much about
+ * the format of the underlying data. It's fairly easy for a non-compliant application
+ * to provide meta-data that will pass here (e.g. a non-existent suggestions authority).
+ *
+ * @param searchables The list of searchables to examine.
+ */
+ private void checkSearchables(ArrayList<SearchableInfo> searchablesList) {
+ assertNotNull(searchablesList);
+ int count = searchablesList.size();
+ for (int ii = 0; ii < count; ii++) {
+ SearchableInfo si = searchablesList.get(ii);
+ assertNotNull(si);
+ assertTrue(si.mSearchable);
+ assertTrue(si.getLabelId() != 0); // This must be a useable string
+ assertNotEmpty(si.mSearchActivity.getClassName());
+ assertNotEmpty(si.mSearchActivity.getPackageName());
+ if (si.getSuggestAuthority() != null) {
+ // The suggestion fields are largely optional, so we'll just confirm basic health
+ assertNotEmpty(si.getSuggestAuthority());
+ assertNullOrNotEmpty(si.getSuggestPath());
+ assertNullOrNotEmpty(si.getSuggestSelection());
+ assertNullOrNotEmpty(si.getSuggestIntentAction());
+ assertNullOrNotEmpty(si.getSuggestIntentData());
+ }
+ /* Add a way to get the entire action key list, then explicitly test its elements */
+ /* For now, test the most common action key (CALL) */
+ ActionKeyInfo ai = si.findActionKey(KeyEvent.KEYCODE_CALL);
+ if (ai != null) {
+ assertEquals(ai.mKeyCode, KeyEvent.KEYCODE_CALL);
+ // one of these three fields must be non-null & non-empty
+ boolean m1 = (ai.mQueryActionMsg != null) && (ai.mQueryActionMsg.length() > 0);
+ boolean m2 = (ai.mSuggestActionMsg != null) && (ai.mSuggestActionMsg.length() > 0);
+ boolean m3 = (ai.mSuggestActionMsgColumn != null) &&
+ (ai.mSuggestActionMsgColumn.length() > 0);
+ assertTrue(m1 || m2 || m3);
+ }
+
+ /*
+ * Find ways to test these:
+ *
+ * private int mSearchMode
+ * private Drawable mIcon
+ */
+
+ /*
+ * Explicitly not tested here:
+ *
+ * Can be null, so not much to see:
+ * public String mSearchHint
+ * private String mZeroQueryBanner
+ *
+ * To be deprecated/removed, so don't bother:
+ * public boolean mFilterMode
+ * public boolean mQuickStart
+ * private boolean mIconResized
+ * private int mIconResizeWidth
+ * private int mIconResizeHeight
+ *
+ * All of these are "internal" working variables, not part of any contract
+ * private ActivityInfo mActivityInfo
+ * private Rect mTempRect
+ * private String mSuggestProviderPackage
+ * private String mCacheActivityContext
+ */
+ }
+ }
+
+ /**
+ * Combo assert for "string not null and not empty"
+ */
+ private void assertNotEmpty(final String s) {
+ assertNotNull(s);
+ MoreAsserts.assertNotEqual(s, "");
+ }
+
+ /**
+ * Combo assert for "string null or (not null and not empty)"
+ */
+ private void assertNullOrNotEmpty(final String s) {
+ if (s != null) {
+ MoreAsserts.assertNotEqual(s, "");
+ }
+ }
+
+ /**
+ * This is a mock for context. Used to perform a true unit test on SearchableInfo.
+ *
+ */
+ private class MyMockContext extends MockContext {
+
+ protected Context mRealContext;
+ protected PackageManager mPackageManager;
+
+ /**
+ * Constructor.
+ *
+ * @param realContext Please pass in a real context for some pass-throughs to function.
+ */
+ MyMockContext(Context realContext, PackageManager packageManager) {
+ mRealContext = realContext;
+ mPackageManager = packageManager;
+ }
+
+ /**
+ * Resources. Pass through for now.
+ */
+ @Override
+ public Resources getResources() {
+ return mRealContext.getResources();
+ }
+
+ /**
+ * Package manager. Pass through for now.
+ */
+ @Override
+ public PackageManager getPackageManager() {
+ return mPackageManager;
+ }
+
+ /**
+ * Package manager. Pass through for now.
+ */
+ @Override
+ public Context createPackageContext(String packageName, int flags)
+ throws PackageManager.NameNotFoundException {
+ return mRealContext.createPackageContext(packageName, flags);
+ }
+ }
+
+/**
+ * This is a mock for package manager. Used to perform a true unit test on SearchableInfo.
+ *
+ */
+ private class MyMockPackageManager extends MockPackageManager {
+
+ public final static int SEARCHABLES_PASSTHROUGH = 0;
+ public final static int SEARCHABLES_MOCK_ZERO = 1;
+ public final static int SEARCHABLES_MOCK_ONEGOOD = 2;
+ public final static int SEARCHABLES_MOCK_ONEGOOD_ONEBAD = 3;
+
+ protected PackageManager mRealPackageManager;
+ protected int mSearchablesMode;
+
+ public MyMockPackageManager(PackageManager realPM) {
+ mRealPackageManager = realPM;
+ mSearchablesMode = SEARCHABLES_PASSTHROUGH;
+ }
+
+ /**
+ * Set the mode for various tests.
+ */
+ public void setSearchablesMode(int newMode) {
+ switch (newMode) {
+ case SEARCHABLES_PASSTHROUGH:
+ case SEARCHABLES_MOCK_ZERO:
+ mSearchablesMode = newMode;
+ break;
+
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Find activities that support a given intent.
+ *
+ * Retrieve all activities that can be performed for the given intent.
+ *
+ * @param intent The desired intent as per resolveActivity().
+ * @param flags Additional option flags. The most important is
+ * MATCH_DEFAULT_ONLY, to limit the resolution to only
+ * those activities that support the CATEGORY_DEFAULT.
+ *
+ * @return A List<ResolveInfo> containing one entry for each matching
+ * Activity. These are ordered from best to worst match -- that
+ * is, the first item in the list is what is returned by
+ * resolveActivity(). If there are no matching activities, an empty
+ * list is returned.
+ */
+ @Override
+ public List<ResolveInfo> queryIntentActivities(Intent intent, int flags) {
+ assertNotNull(intent);
+ assertEquals(intent.getAction(), Intent.ACTION_SEARCH);
+ switch (mSearchablesMode) {
+ case SEARCHABLES_PASSTHROUGH:
+ return mRealPackageManager.queryIntentActivities(intent, flags);
+ case SEARCHABLES_MOCK_ZERO:
+ return null;
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Retrieve an XML file from a package. This is a low-level API used to
+ * retrieve XML meta data.
+ *
+ * @param packageName The name of the package that this xml is coming from.
+ * Can not be null.
+ * @param resid The resource identifier of the desired xml. Can not be 0.
+ * @param appInfo Overall information about <var>packageName</var>. This
+ * may be null, in which case the application information will be retrieved
+ * for you if needed; if you already have this information around, it can
+ * be much more efficient to supply it here.
+ *
+ * @return Returns an XmlPullParser allowing you to parse out the XML
+ * data. Returns null if the xml resource could not be found for any
+ * reason.
+ */
+ @Override
+ public XmlResourceParser getXml(String packageName, int resid, ApplicationInfo appInfo) {
+ assertNotNull(packageName);
+ MoreAsserts.assertNotEqual(packageName, "");
+ MoreAsserts.assertNotEqual(resid, 0);
+ switch (mSearchablesMode) {
+ case SEARCHABLES_PASSTHROUGH:
+ return mRealPackageManager.getXml(packageName, resid, appInfo);
+ case SEARCHABLES_MOCK_ZERO:
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ /**
+ * Find a single content provider by its base path name.
+ *
+ * @param name The name of the provider to find.
+ * @param flags Additional option flags. Currently should always be 0.
+ *
+ * @return ContentProviderInfo Information about the provider, if found,
+ * else null.
+ */
+ @Override
+ public ProviderInfo resolveContentProvider(String name, int flags) {
+ assertNotNull(name);
+ MoreAsserts.assertNotEqual(name, "");
+ assertEquals(flags, 0);
+ switch (mSearchablesMode) {
+ case SEARCHABLES_PASSTHROUGH:
+ return mRealPackageManager.resolveContentProvider(name, flags);
+ case SEARCHABLES_MOCK_ZERO:
+ default:
+ throw new UnsupportedOperationException();
+ }
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java
new file mode 100644
index 0000000..4b64144
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SerializationTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests serialization of user-level classes.
+ */
+public class SerializationTest extends TestCase {
+
+ static class MySerializable implements Serializable {}
+
+ @SmallTest
+ public void testSerialization() throws IOException, ClassNotFoundException {
+ ByteArrayOutputStream bout = new ByteArrayOutputStream();
+ ObjectOutputStream oout = new ObjectOutputStream(bout);
+ oout.writeObject(new MySerializable());
+ oout.close();
+
+ ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
+ Object o = new ObjectInputStream(bin).readObject();
+ assertTrue(o instanceof MySerializable);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java
new file mode 100644
index 0000000..8b1db97
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SettingsProviderTest.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentResolver;
+import android.content.ContentUris;
+import android.content.ContentValues;
+import android.content.Intent;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/** Unit test for SettingsProvider. */
+public class SettingsProviderTest extends AndroidTestCase {
+ @MediumTest
+ public void testNameValueCache() {
+ ContentResolver r = getContext().getContentResolver();
+ Settings.Gservices.putString(r, "test_service", "Value");
+ assertEquals("Value", Settings.Gservices.getString(r, "test_service"));
+
+ // Make sure the value can be overwritten.
+ Settings.Gservices.putString(r, "test_service", "New");
+ assertEquals("New", Settings.Gservices.getString(r, "test_service"));
+
+ // Also that delete works.
+ assertEquals(1, r.delete(Settings.Gservices.getUriFor("test_service"), null, null));
+ assertEquals(null, Settings.Gservices.getString(r, "test_service"));
+
+ // Try all the same things in the System table
+ Settings.System.putString(r, "test_setting", "Value");
+ assertEquals("Value", Settings.System.getString(r, "test_setting"));
+
+ Settings.System.putString(r, "test_setting", "New");
+ assertEquals("New", Settings.System.getString(r, "test_setting"));
+
+ assertEquals(1, r.delete(Settings.System.getUriFor("test_setting"), null, null));
+ assertEquals(null, Settings.System.getString(r, "test_setting"));
+ }
+
+ @MediumTest
+ public void testRowNameContentUri() {
+ ContentResolver r = getContext().getContentResolver();
+
+ assertEquals("content://settings/system/test_setting",
+ Settings.System.getUriFor("test_setting").toString());
+ assertEquals("content://settings/gservices/test_service",
+ Settings.Gservices.getUriFor("test_service").toString());
+
+ // These tables use the row name (not ID) as their content URI.
+ Uri tables[] = { Settings.System.CONTENT_URI, Settings.Gservices.CONTENT_URI };
+ for (Uri table : tables) {
+ ContentValues v = new ContentValues();
+ v.put(Settings.System.NAME, "test_key");
+ v.put(Settings.System.VALUE, "Test");
+ Uri uri = r.insert(table, v);
+ assertEquals(table.toString() + "/test_key", uri.toString());
+
+ // Query with a specific URI and no WHERE clause succeeds.
+ Cursor c = r.query(uri, null, null, null, null);
+ try {
+ assertTrue(c.moveToNext());
+ assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+ assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+ assertFalse(c.moveToNext());
+ } finally {
+ c.close();
+ }
+
+ // Query with a specific URI and a WHERE clause fails.
+ try {
+ r.query(uri, null, "1", null, null);
+ fail("UnsupportedOperationException expected");
+ } catch (UnsupportedOperationException e) {
+ if (!e.toString().contains("WHERE clause")) throw e;
+ }
+
+ // Query with a tablewide URI and a WHERE clause succeeds.
+ c = r.query(table, null, "name='test_key'", null, null);
+ try {
+ assertTrue(c.moveToNext());
+ assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+ assertEquals("Test", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+ assertFalse(c.moveToNext());
+ } finally {
+ c.close();
+ }
+
+ v = new ContentValues();
+ v.put(Settings.System.VALUE, "Toast");
+ assertEquals(1, r.update(uri, v, null, null));
+
+ c = r.query(uri, null, null, null, null);
+ try {
+ assertTrue(c.moveToNext());
+ assertEquals("test_key", c.getString(c.getColumnIndex(Settings.System.NAME)));
+ assertEquals("Toast", c.getString(c.getColumnIndex(Settings.System.VALUE)));
+ assertFalse(c.moveToNext());
+ } finally {
+ c.close();
+ }
+
+ assertEquals(1, r.delete(uri, null, null));
+ }
+
+ assertEquals(null, Settings.System.getString(r, "test_key"));
+ assertEquals(null, Settings.Gservices.getString(r, "test_key"));
+ }
+
+ @MediumTest
+ public void testRowNumberContentUri() {
+ ContentResolver r = getContext().getContentResolver();
+
+ // The bookmarks table (and everything else) uses standard row number content URIs.
+ Uri uri = Settings.Bookmarks.add(r, new Intent("TEST"),
+ "Test Title", "Test Folder", '*', 123);
+
+ assertTrue(ContentUris.parseId(uri) > 0);
+
+ assertEquals("TEST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction());
+
+ ContentValues v = new ContentValues();
+ v.put(Settings.Bookmarks.INTENT, "#Intent;action=TOAST;end");
+ assertEquals(1, r.update(uri, v, null, null));
+
+ assertEquals("TOAST", Settings.Bookmarks.getIntentForShortcut(r, '*').getAction());
+
+ assertEquals(1, r.delete(uri, null, null));
+
+ assertEquals(null, Settings.Bookmarks.getIntentForShortcut(r, '*'));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java
new file mode 100644
index 0000000..9758298
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SimplePullParserTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.google.android.util.SimplePullParser;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class SimplePullParserTest extends TestCase {
+ @SmallTest
+ public void testTwoLevels() throws Exception {
+ String xml = ""
+ + "<top a='1' b='hello'>\n"
+ + " <next c='2' d='there'/>\n"
+ + " <next c='3' d='bye'/>\n"
+ + "</top>";
+ SimplePullParser parser = new SimplePullParser(xml);
+ int depth0 = parser.getDepth();
+ assertEquals(0, depth0);
+ assertEquals("top", parser.nextTag(depth0));
+ assertEquals(1, parser.getIntAttribute(null, "a"));
+ assertEquals("hello", parser.getStringAttribute(null, "b"));
+
+ int depth1 = parser.getDepth();
+ assertEquals(1, depth1);
+ assertEquals("next", parser.nextTag(depth1));
+ assertEquals(2, parser.getIntAttribute(null, "c"));
+ assertEquals("there", parser.getStringAttribute(null, "d"));
+ assertEquals("next", parser.nextTag(depth1));
+ assertEquals(3, parser.getIntAttribute(null, "c"));
+ assertEquals("bye", parser.getStringAttribute(null, "d"));
+ assertNull(parser.nextTag(depth1));
+
+ assertNull(parser.nextTag(depth0));
+ }
+
+ @SmallTest
+ public void testAttributes() throws Exception {
+ String xml = "<top a='1' b='hello'/>";
+ SimplePullParser parser = new SimplePullParser(xml);
+ int depth = parser.getDepth();
+ parser.nextTag(depth);
+
+ assertEquals(2, parser.numAttributes());
+ assertEquals("a", parser.getAttributeName(0));
+ assertEquals("b", parser.getAttributeName(1));
+
+ assertEquals(1, parser.getIntAttribute(null, "a"));
+ assertEquals(5, parser.getIntAttribute(null, "c", 5));
+ assertEquals("hello", parser.getStringAttribute(null, "b"));
+ assertEquals("not", parser.getStringAttribute(null, "d", "not"));
+ }
+
+ @SmallTest
+ public void testRecovery() throws Exception {
+ String xml = ""
+ + "<top a='1' b='hello'>\n"
+ + " <middle c='2' d='there'>\n"
+ + " <inner/>\n"
+ + " <inner2/>\n"
+ + " <inner3/>\n"
+ + " </middle>\n"
+ + " <middle2/>\n"
+ + "</top>";
+ SimplePullParser parser = new SimplePullParser(xml);
+ assertEquals(0, parser.getDepth());
+ assertEquals("top", parser.nextTag(0));
+ assertEquals(1, parser.getDepth());
+ assertEquals("middle", parser.nextTag(1));
+ assertEquals(2, parser.getDepth());
+ assertEquals("inner", parser.nextTag(2));
+ // Now skip some elements.
+ assertEquals("middle2", parser.nextTag(1));
+ }
+
+ @SmallTest
+ public void testCdata() throws Exception {
+ StringBuilder cdataBuilder;
+ String xml = ""
+ + "<top>"
+ + "<![CDATA[data0]]>"
+ + "<next0/>"
+ + "<![CDATA[data1]]>"
+ + "<next1/>"
+ + "<![CDATA[data2]]>"
+ + "<next2/>"
+ + "<![CDATA[data3]]>"
+ + "<next3/>"
+ + "<![CDATA[data4]]>"
+ + "<next4/>"
+ + "<![CDATA[data5]]>"
+ + "</top>";
+ SimplePullParser parser = new SimplePullParser(xml);
+ assertEquals("top", parser.nextTag(0));
+
+ // We can ignore cdata by not passing a cdata builder.
+ assertEquals("next0", parser.nextTag(1));
+
+ // We can get the most recent cdata by passing an empty cdata builder.
+ cdataBuilder = new StringBuilder();
+ assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+ assertEquals("data1", cdataBuilder.toString());
+ assertEquals("next1", parser.nextTag(1));
+
+ // We can join multiple cdatas by reusing a builder.
+ cdataBuilder = new StringBuilder();
+ assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+ assertEquals("next2", parser.nextTag(1));
+ assertSame(SimplePullParser.TEXT_TAG, parser.nextTagOrText(1, cdataBuilder));
+ assertEquals("data2data3", cdataBuilder.toString());
+ assertEquals("next3", parser.nextTag(1));
+
+ // We can read all of the remaining cdata while ignoring any elements.
+ cdataBuilder = new StringBuilder();
+ parser.readRemainingText(1, cdataBuilder);
+ assertEquals("data4data5", cdataBuilder.toString());
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java
new file mode 100644
index 0000000..0e2f0c5
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SmsProviderTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.Telephony.Sms;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.GregorianCalendar;
+
+public class SmsProviderTest extends AndroidTestCase {
+
+ @LargeTest
+ public void testProvider() throws Exception {
+ // This test does the following
+ // 1. Insert 10 messages from the same number at different times.
+ //
+ // . Delete the messages and make sure that they were deleted.
+
+ long now = System.currentTimeMillis();
+
+ Uri[] urls = new Uri[10];
+ String[] dates = new String[]{
+ Long.toString(new GregorianCalendar(1970, 1, 1, 0, 0, 0).getTimeInMillis()),
+ Long.toString(new GregorianCalendar(1971, 2, 13, 16, 35, 3).getTimeInMillis()),
+ Long.toString(new GregorianCalendar(1978, 10, 22, 0, 1, 0).getTimeInMillis()),
+ Long.toString(new GregorianCalendar(1980, 1, 11, 10, 22, 30).getTimeInMillis()),
+ Long.toString(now - (5 * 24 * 60 * 60 * 1000)),
+ Long.toString(now - (2 * 24 * 60 * 60 * 1000)),
+ Long.toString(now - (5 * 60 * 60 * 1000)),
+ Long.toString(now - (30 * 60 * 1000)),
+ Long.toString(now - (5 * 60 * 1000)),
+ Long.toString(now)
+ };
+
+ ContentValues map = new ContentValues();
+ map.put("address", "+15045551337");
+ map.put("read", 0);
+
+ ContentResolver contentResolver = mContext.getContentResolver();
+
+ for (int i = 0; i < urls.length; i++) {
+ map.put("body", "Test " + i + " !");
+ map.put("date", dates[i]);
+ urls[i] = contentResolver.insert(Sms.Inbox.CONTENT_URI, map);
+ assertNotNull(urls[i]);
+ }
+
+ Cursor c = contentResolver.query(Sms.Inbox.CONTENT_URI, null, null, null, "date");
+
+ //DatabaseUtils.dumpCursor(c);
+
+ for (Uri url : urls) {
+ int count = contentResolver.delete(url, null, null);
+ assertEquals(1, count);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java
new file mode 100644
index 0000000..9e3f483
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/SpannedTest.java
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.graphics.Typeface;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.*;
+import android.text.style.*;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+/**
+ * SpannedTest tests some features of Spanned
+ */
+public class SpannedTest extends TestCase {
+ private int mExpect;
+
+ @SmallTest
+ public void testSpannableString() throws Exception {
+ checkPriority(new SpannableString("the quick brown fox"));
+ }
+
+ @SmallTest
+ public void testSpannableStringBuilder() throws Exception {
+ checkPriority2(new SpannableStringBuilder("the quick brown fox"));
+ }
+
+ @SmallTest
+ public void testAppend() throws Exception {
+ Object o = new Object();
+ SpannableString ss = new SpannableString("Test");
+ ss.setSpan(o, 0, ss.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ SpannableStringBuilder ssb = new SpannableStringBuilder();
+ ssb.append(ss);
+ assertEquals(0, ssb.getSpanStart(o));
+ assertEquals(4, ssb.getSpanEnd(o));
+ assertEquals(1, ssb.getSpans(0, 4, Object.class).length);
+
+ ssb.insert(0, ss);
+ assertEquals(4, ssb.getSpanStart(o));
+ assertEquals(8, ssb.getSpanEnd(o));
+ assertEquals(0, ssb.getSpans(0, 4, Object.class).length);
+ assertEquals(1, ssb.getSpans(4, 8, Object.class).length);
+ }
+
+ @SmallTest
+ public void testWrapParcel() {
+ SpannableString s = new SpannableString("Hello there world");
+ CharacterStyle mark = new StyleSpan(Typeface.BOLD);
+ s.setSpan(mark, 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ s.setSpan(CharacterStyle.wrap(mark), 3, 7,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ s.setSpan(new TextAppearanceSpan("mono", 0, -1, null, null), 7, 8,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ s.setSpan(CharacterStyle.wrap(new TypefaceSpan("mono")), 8, 9,
+ Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ Parcel p = Parcel.obtain();
+ TextUtils.writeToParcel(s, p, 0);
+ p.setDataPosition(0);
+
+ Spanned s2 = (Spanned) TextUtils.CHAR_SEQUENCE_CREATOR.
+ createFromParcel(p);
+ StyleSpan[] style;
+
+ style = s2.getSpans(1, 2, StyleSpan.class);
+ assertEquals(1, style.length);
+ assertEquals(1, s2.getSpanStart(style[0]));
+ assertEquals(2, s2.getSpanEnd(style[0]));
+
+ style = s2.getSpans(3, 7, StyleSpan.class);
+ assertEquals(1, style.length);
+ assertEquals(3, s2.getSpanStart(style[0]));
+ assertEquals(7, s2.getSpanEnd(style[0]));
+
+ TextAppearanceSpan[] appearance = s2.getSpans(7, 8,
+ TextAppearanceSpan.class);
+ assertEquals(1, appearance.length);
+ assertEquals(7, s2.getSpanStart(appearance[0]));
+ assertEquals(8, s2.getSpanEnd(appearance[0]));
+
+ TypefaceSpan[] tf = s2.getSpans(8, 9, TypefaceSpan.class);
+ assertEquals(1, tf.length);
+ assertEquals(8, s2.getSpanStart(tf[0]));
+ assertEquals(9, s2.getSpanEnd(tf[0]));
+ }
+
+ private void checkPriority(Spannable s) {
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (5 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (10 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (0 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (15 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (3 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (6 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE |
+ (0 << Spannable.SPAN_PRIORITY_SHIFT));
+
+ Object[] spans = s.getSpans(0, s.length(), Object.class);
+
+ for (int i = 0; i < spans.length - 1; i++) {
+ assertEquals((s.getSpanFlags(spans[i]) & Spanned.SPAN_PRIORITY) >=
+ (s.getSpanFlags(spans[i + 1]) & Spanned.SPAN_PRIORITY),
+ true);
+ }
+
+ mExpect = 0;
+
+ s.setSpan(new Watcher(2), 0, s.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+ (2 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Watcher(4), 0, s.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+ (4 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Watcher(1), 0, s.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+ (1 << Spannable.SPAN_PRIORITY_SHIFT));
+ s.setSpan(new Watcher(3), 0, s.length(),
+ Spannable.SPAN_INCLUSIVE_INCLUSIVE |
+ (3 << Spannable.SPAN_PRIORITY_SHIFT));
+
+ mExpect = 4;
+ s.setSpan(new Object(), 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ assertEquals(mExpect, 0);
+ }
+
+ private void checkPriority2(SpannableStringBuilder ssb) {
+ checkPriority(ssb);
+
+ mExpect = 4;
+ ssb.insert(3, "something");
+ assertEquals(mExpect, 0);
+ }
+
+ private class Watcher implements SpanWatcher, TextWatcher {
+ private int mSequence;
+
+ public Watcher(int sequence) {
+ mSequence = sequence;
+ }
+
+ public void onSpanChanged(Spannable b, Object o, int s, int e,
+ int st, int en) { }
+ public void onSpanRemoved(Spannable b, Object o, int s, int e) { }
+
+ public void onSpanAdded(Spannable b, Object o, int s, int e) {
+ if (mExpect != 0) {
+ assertEquals(mSequence, mExpect);
+ mExpect = mSequence - 1;
+ }
+ }
+
+ public void beforeTextChanged(CharSequence s, int start, int count,
+ int after) { }
+ public void onTextChanged(CharSequence s, int start, int before,
+ int count) {
+ if (mExpect != 0) {
+ assertEquals(mSequence, mExpect);
+ mExpect = mSequence - 1;
+ }
+ }
+
+ public void afterTextChanged(Editable s) { }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/StringTest.java b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java
new file mode 100644
index 0000000..dc40a0a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/StringTest.java
@@ -0,0 +1,951 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import java.util.Locale;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+public class StringTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ public static final String STATIC_STRING_01 = "Hello Android";
+ public static final String STATIC_STRING_02 =
+ "Remember, today is the tomorrow you worried about yesterday";
+ public static final char[] STATIC_CHAR_ARRAY =
+ {'N', 'A', 'N', 'D', 'R', 'O', 'I', 'D'};
+ public static StringBuffer STATIC_SBUF = new StringBuffer(STATIC_STRING_02);
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ /** Create an empty String object* */
+
+ public void testStringCreate() {
+ String rString;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ rString = new String();
+ }
+ }
+
+ /** Create an initialised String object* */
+
+ public void testStringCreate1() {
+ String rString, str = STATIC_STRING_01;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str);
+ rString = new String(str); // 10
+ }
+ }
+
+ /** equals() with for loop* */
+ public void testStringEquals() {
+ String mString = new String(STATIC_STRING_01);
+ String str = STATIC_STRING_01;
+ boolean result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ result = mString.equals(str);
+ }
+ }
+
+ /**
+ * ContentEquals- Comparing the content of a String with that of a String
+ * Buffer*
+ */
+
+ public void testStringContentEquals() {
+ StringBuffer sBuf = new StringBuffer(STATIC_STRING_01);
+ String str = STATIC_STRING_01;
+ boolean result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ result = str.contentEquals(sBuf);
+ }
+ }
+
+ /** Compare string objects lexicographically using compareTo() with for loop* */
+
+ public void testStringCompareTo() {
+ String str1 = new String(STATIC_STRING_01);
+ String str2 = STATIC_STRING_01;
+ int result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ result = str1.compareTo(str2);
+ }
+
+ }
+
+ /** Compare string objects using compareToIgnorecase() with for loop* */
+
+ public void testStringCompareToIgnoreCase() {
+ String mString = new String(STATIC_STRING_01);
+ String str2 = STATIC_STRING_01;
+ int result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ result = mString.compareToIgnoreCase(str2);
+ }
+ }
+
+ /** startsWith * */
+
+ public void testStringstartsWith() {
+ boolean result;
+ String str1 = STATIC_STRING_02, str2 = "Rem";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ result = str1.startsWith(str2);
+ }
+ }
+
+ /** startsWith(String seq, int begin) * */
+
+ public void testStringstartsWith1() {
+ String str1 = STATIC_STRING_02, str2 = "tom";
+ int pos = 10;
+ boolean result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ result = str1.startsWith(str2, pos);
+ }
+ }
+
+ /** endsWith * */
+
+ public void testStringendsWith() {
+ String str = STATIC_STRING_02, str1 = "day";
+ boolean result;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ result = str.endsWith(str1);
+ }
+ }
+
+ /**
+ * indexOf to determine whether a string contains a substring
+ */
+ public void testStringindexOf() {
+ boolean result;
+ String str = STATIC_STRING_02, str1 = "tomo";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ result = str.indexOf(str1) > 0;
+ }
+ }
+
+ /** indexOf()* */
+
+ public void testStringindexOf1() {
+ int index;
+ String str = STATIC_STRING_02;
+ char c = 't';
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ index = str.indexOf(c);
+ }
+
+ }
+
+ /** indexOf(char c, int start)* */
+ public void testStringindexOf2() {
+ int index, pos = 12;
+ String str = STATIC_STRING_02, str1 = "tom";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ index = str.indexOf(str1, pos);
+ }
+ }
+
+ /** lastIndexOf()* */
+
+ public void testStringlastIndexOf() {
+ int index;
+ char c = 't';
+ String str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ index = str.lastIndexOf(c);
+ }
+ }
+
+ /** lastIndexOf()* */
+
+ public void testStringlastIndexOf1() {
+ int index, pos = 36;
+ String str = STATIC_STRING_02, str1 = "tom";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ index = str.lastIndexOf(str1, pos);
+ }
+ }
+
+ /**
+ * contains() to determine whether a string contains a substring
+ */
+
+ public void testStringcontains() {
+ boolean result;
+ String str = STATIC_STRING_02, str1 = "tomo";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ result = str.contains(str1);
+ }
+ }
+
+ /** substring(int start) */
+
+ public void testStringsubstring() {
+ String rString;
+ String str = STATIC_STRING_02;
+ int index = 10;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ rString = str.substring(index);
+ }
+ }
+
+ /** substring(int start, int end) in a for loop* */
+
+ public void testStringsubstring1() {
+ String rString;
+ String str = STATIC_STRING_02;
+ int start = 10, end = 48;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ rString = str.substring(start, end);
+ }
+ }
+
+ /**
+ * valueOf(char[] cArray) String representation of a character array
+ */
+ public void testStringvalueOf() {
+ String rString;
+ char[] cArray = STATIC_CHAR_ARRAY;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ rString = String.valueOf(cArray);
+ }
+ }
+
+ /** valueOf(char[] cArray, int offset, int count)* */
+
+ public void testStringvalueOf1() {
+ String rString;
+ char[] cArray = STATIC_CHAR_ARRAY;
+ int start = 1, end = 7;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ rString = String.valueOf(cArray, start, end);
+ }
+ }
+
+ /** Convert a string to a char Array* */
+
+ public void testStringtoCharArray() {
+ char[] cArray;
+ String str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ cArray = str.toCharArray();
+ }
+ }
+
+ /** length()* */
+
+ public void testStringlength() {
+ int len;
+ String str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ len = str.length();
+ }
+ }
+
+ /** hashcode()* */
+
+ public void testStringhashCode() {
+ int index;
+ String str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ index = str.hashCode();
+ }
+ }
+
+ /** replace()* */
+
+ public void testStringreplace() {
+ String rString;
+ String str = STATIC_STRING_02;
+ char c1 = ' ', c2 = ' ';
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ rString = str.replace(c1, c2);
+ }
+ }
+
+ public void testStringreplaceAll() {
+ String rString;
+ String str = STATIC_STRING_02, str1 = " ", str2 = "/";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ rString = str.replaceAll(str1, str2);
+ }
+ }
+
+ /** Convert a StringBuffer to a String* */
+
+ public void testStringtoString() {
+ StringBuffer sBuf = new StringBuffer(STATIC_STRING_02);
+
+ String rString;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ rString = sBuf.toString();
+ }
+ }
+
+ /** Split a string into an array of strings* */
+
+ public void testStringsplit() {
+ String[] strings;
+ String str1 = STATIC_STRING_02, str = " ";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+ strings = str1.split(str);
+
+ }
+ }
+
+ /** Split a string into an array of strings* */
+
+ public void testStringsplit1() {
+ String str = STATIC_STRING_02, str1 = " ";
+ String[] strings;
+ int pos = 8;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ strings = str.split(str1, pos);
+ }
+ }
+
+ public void testStringgetBytes() {
+ byte[] bytes;
+ String str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ bytes = str.getBytes();
+ }
+ }
+
+ /** copyValueOf(char[] data) * */
+
+ public void testStringcopyValueOf() {
+ String rString;
+ char[] cArray = STATIC_CHAR_ARRAY;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ rString = String.copyValueOf(cArray);
+ }
+ }
+
+ /** copyValueOf(char[] data, int index, int count)* */
+
+ public void testStringcopyValueOf1() {
+ String rString;
+ int start = 1, end = 7;
+ char[] cArray = STATIC_CHAR_ARRAY;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ rString = String.copyValueOf(cArray, start, end);
+ }
+ }
+
+ /** trim()* */
+
+ public void testStringtrim() {
+ String mString =
+ new String(
+ " HELLO ANDROID ");
+ String rString;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ rString = mString.trim();
+ }
+ }
+
+ /** getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)* */
+
+ public void testStringgetChars() {
+ char[] cArray = STATIC_CHAR_ARRAY;
+ String str = STATIC_STRING_01;
+ int value1 = 7, value2 = 12, value3 = 1;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ str.getChars(value1, value2, cArray, value3);
+ }
+ }
+
+ /** toUpperCase()* */
+
+ public void testStringtoUpperCase() {
+ String rString, str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ rString = str.toUpperCase();
+ }
+ }
+
+ /** toUpperCase() with locale* */
+
+ public void testStringtoUpperCase1() {
+ Locale locale = new Locale("tr");
+ String str = STATIC_STRING_02;
+ String rString;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ rString = str.toUpperCase(locale);
+ }
+ }
+
+ /** toLowerCase* */
+
+ public void StringtoLowerCase() {
+ String rString, str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ rString = str.toLowerCase();
+ }
+ }
+
+ /** toLowerCase with locale* */
+
+ public void testStringtoLowerCase1() {
+ Locale locale = new Locale("tr");
+ String rString, str = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ rString = str.toLowerCase(locale);
+ }
+ }
+
+ /** charAt()* */
+
+ public void testStringcharAt() {
+ String str = STATIC_STRING_02;
+ int index, pos = 21;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ index = str.charAt(pos);
+ }
+ }
+
+ public void testStringConcat() {
+ String mString, str1 = STATIC_STRING_01, str2 = STATIC_STRING_02;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ mString = str1.concat(str2);
+ }
+ }
+
+ public void testStringBufferAppend() {
+ StringBuffer sBuf = new StringBuffer(" ");
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ sBuf.append(i);
+ }
+ }
+
+ public void testStringBufferInsert() {
+ StringBuffer sBuf = new StringBuffer(" ");
+ int index = sBuf.length();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ sBuf.insert(index, i);
+ }
+ }
+
+ public void testStringBufferReverse() {
+ StringBuffer sBuf = STATIC_SBUF;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ sBuf.reverse();
+ }
+ }
+
+ public void testStringBufferSubstring() {
+ StringBuffer sBuf = STATIC_SBUF;
+ String rString;
+ int index = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ rString = sBuf.substring(index);
+ }
+ }
+
+ public void testStringBufferSubstring1() {
+ StringBuffer sBuf = STATIC_SBUF;
+ String rString;
+ int start = 5, end = 25;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ rString = sBuf.substring(start, end);
+ }
+ }
+
+ public void testStringBufferReplace() {
+ StringBuffer sBuf = STATIC_SBUF;
+ int start = 3, end = 6;
+ String str = "ind";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ sBuf.replace(start, end, str);
+ }
+ }
+
+ public void testStringBufferIndexOf() {
+ StringBuffer sBuf = STATIC_SBUF;
+ String str = "t";
+ int index;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ index = sBuf.indexOf(str);
+ }
+ }
+
+ public void testStringBufferIndexOf1() {
+ StringBuffer sBuf = STATIC_SBUF;
+ String str = "tom";
+ int index, pos = 12;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ index = sBuf.indexOf(str, pos);
+ }
+
+ }
+
+ public void testStringBufferLastIndexOf() {
+ StringBuffer sBuf = STATIC_SBUF;
+ String str = "t";
+ int index;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ index = sBuf.lastIndexOf(str);
+ }
+ }
+
+ public void testStringBufferLastIndexOf1() {
+ StringBuffer sBuf = STATIC_SBUF;
+ int index, pos = 36;
+ String str = "tom";
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ index = sBuf.lastIndexOf(str, pos);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java
new file mode 100644
index 0000000..9b5e655
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpClient.java
@@ -0,0 +1,116 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpClient.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+import java.io.IOException;
+
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpClientConnection;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpVersion;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.DefaultedHttpParams;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.ExecutionContext;
+import org.apache.http.protocol.HttpRequestExecutor;
+import org.apache.http.protocol.RequestConnControl;
+import org.apache.http.protocol.RequestContent;
+import org.apache.http.protocol.RequestExpectContinue;
+import org.apache.http.protocol.RequestTargetHost;
+import org.apache.http.protocol.RequestUserAgent;
+
+public class TestHttpClient {
+
+ private final HttpParams params;
+ private final BasicHttpProcessor httpproc;
+ private final HttpRequestExecutor httpexecutor;
+ private final ConnectionReuseStrategy connStrategy;
+ private final HttpContext context;
+
+ public TestHttpClient() {
+ super();
+ this.params = new BasicHttpParams();
+ this.params
+ .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 5000)
+ .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+ .setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1)
+ .setParameter(CoreProtocolPNames.USER_AGENT, "TEST-CLIENT/1.1");
+
+ this.httpproc = new BasicHttpProcessor();
+ // Required protocol interceptors
+ this.httpproc.addInterceptor(new RequestContent());
+ this.httpproc.addInterceptor(new RequestTargetHost());
+ // Recommended protocol interceptors
+ this.httpproc.addInterceptor(new RequestConnControl());
+ this.httpproc.addInterceptor(new RequestUserAgent());
+ this.httpproc.addInterceptor(new RequestExpectContinue());
+
+ this.httpexecutor = new HttpRequestExecutor();
+ this.connStrategy = new DefaultConnectionReuseStrategy();
+ this.context = new BasicHttpContext(null);
+ }
+
+ public HttpParams getParams() {
+ return this.params;
+ }
+
+ public HttpResponse execute(
+ final HttpRequest request,
+ final HttpHost targetHost,
+ final HttpClientConnection conn) throws HttpException, IOException {
+ this.context.setAttribute(ExecutionContext.HTTP_REQUEST, request);
+ this.context.setAttribute(ExecutionContext.HTTP_TARGET_HOST, targetHost);
+ this.context.setAttribute(ExecutionContext.HTTP_CONNECTION, conn);
+ request.setParams(
+ new DefaultedHttpParams(request.getParams(), this.params));
+ this.httpexecutor.preProcess(request, this.httpproc, this.context);
+ HttpResponse response = this.httpexecutor.execute(request, conn, this.context);
+ response.setParams(
+ new DefaultedHttpParams(response.getParams(), this.params));
+ this.httpexecutor.postProcess(response, this.httpproc, this.context);
+ return response;
+ }
+
+ public boolean keepAlive(final HttpResponse response) {
+ return this.connStrategy.keepAlive(response, this.context);
+ }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java
new file mode 100644
index 0000000..aae21b3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpServer.java
@@ -0,0 +1,207 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/mockup/TestHttpServer.java $
+ * $Revision: 576077 $
+ * $Date: 2007-09-16 04:50:22 -0700 (Sun, 16 Sep 2007) $
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+
+import java.io.IOException;
+import java.io.InterruptedIOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+import org.apache.http.ConnectionClosedException;
+import org.apache.http.ConnectionReuseStrategy;
+import org.apache.http.HttpException;
+import org.apache.http.HttpResponseFactory;
+import org.apache.http.HttpServerConnection;
+import org.apache.http.impl.DefaultConnectionReuseStrategy;
+import org.apache.http.impl.DefaultHttpResponseFactory;
+import org.apache.http.impl.DefaultHttpServerConnection;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.CoreConnectionPNames;
+import org.apache.http.params.HttpParams;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.BasicHttpProcessor;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.protocol.BasicHttpContext;
+import org.apache.http.protocol.HttpExpectationVerifier;
+import org.apache.http.protocol.HttpRequestHandler;
+import org.apache.http.protocol.HttpRequestHandlerRegistry;
+import org.apache.http.protocol.HttpService;
+import org.apache.http.protocol.ResponseConnControl;
+import org.apache.http.protocol.ResponseContent;
+import org.apache.http.protocol.ResponseDate;
+import org.apache.http.protocol.ResponseServer;
+
+public class TestHttpServer {
+
+ private final HttpParams params;
+ private final BasicHttpProcessor httpproc;
+ private final ConnectionReuseStrategy connStrategy;
+ private final HttpResponseFactory responseFactory;
+ private final HttpRequestHandlerRegistry reqistry;
+ private final ServerSocket serversocket;
+
+ private HttpExpectationVerifier expectationVerifier;
+
+ private Thread listener;
+ private volatile boolean shutdown;
+
+ public TestHttpServer() throws IOException {
+ super();
+ this.params = new BasicHttpParams();
+ this.params
+ .setIntParameter(CoreConnectionPNames.SO_TIMEOUT, 20000)
+ .setIntParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 8 * 1024)
+ .setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, false)
+ .setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, true)
+ .setParameter(CoreProtocolPNames.ORIGIN_SERVER, "TEST-SERVER/1.1");
+ this.httpproc = new BasicHttpProcessor();
+ this.httpproc.addInterceptor(new ResponseDate());
+ this.httpproc.addInterceptor(new ResponseServer());
+ this.httpproc.addInterceptor(new ResponseContent());
+ this.httpproc.addInterceptor(new ResponseConnControl());
+ this.connStrategy = new DefaultConnectionReuseStrategy();
+ this.responseFactory = new DefaultHttpResponseFactory();
+ this.reqistry = new HttpRequestHandlerRegistry();
+ this.serversocket = new ServerSocket(0);
+ }
+
+ public void registerHandler(
+ final String pattern,
+ final HttpRequestHandler handler) {
+ this.reqistry.register(pattern, handler);
+ }
+
+ public void setExpectationVerifier(final HttpExpectationVerifier expectationVerifier) {
+ this.expectationVerifier = expectationVerifier;
+ }
+
+ private HttpServerConnection acceptConnection() throws IOException {
+ Socket socket = this.serversocket.accept();
+ DefaultHttpServerConnection conn = new DefaultHttpServerConnection();
+ conn.bind(socket, this.params);
+ return conn;
+ }
+
+ public int getPort() {
+ return this.serversocket.getLocalPort();
+ }
+
+ public InetAddress getInetAddress() {
+ return this.serversocket.getInetAddress();
+ }
+
+ public void start() {
+ if (this.listener != null) {
+ throw new IllegalStateException("Listener already running");
+ }
+ this.listener = new Thread(new Runnable() {
+
+ public void run() {
+ while (!shutdown && !Thread.interrupted()) {
+ try {
+ // Set up HTTP connection
+ HttpServerConnection conn = acceptConnection();
+ // Set up the HTTP service
+ HttpService httpService = new HttpService(
+ httpproc,
+ connStrategy,
+ responseFactory);
+ httpService.setParams(params);
+ httpService.setExpectationVerifier(expectationVerifier);
+ httpService.setHandlerResolver(reqistry);
+
+ // Start worker thread
+ Thread t = new WorkerThread(httpService, conn);
+ t.setDaemon(true);
+ t.start();
+ } catch (InterruptedIOException ex) {
+ break;
+ } catch (IOException e) {
+ break;
+ }
+ }
+ }
+
+ });
+ this.listener.start();
+ }
+
+ public void shutdown() {
+ if (this.shutdown) {
+ return;
+ }
+ this.shutdown = true;
+ try {
+ this.serversocket.close();
+ } catch (IOException ignore) {}
+ this.listener.interrupt();
+ try {
+ this.listener.join(1000);
+ } catch (InterruptedException ignore) {}
+ }
+
+ static class WorkerThread extends Thread {
+
+ private final HttpService httpservice;
+ private final HttpServerConnection conn;
+
+ public WorkerThread(
+ final HttpService httpservice,
+ final HttpServerConnection conn) {
+ super();
+ this.httpservice = httpservice;
+ this.conn = conn;
+ }
+
+ public void run() {
+ HttpContext context = new BasicHttpContext(null);
+ try {
+ while (!Thread.interrupted() && this.conn.isOpen()) {
+ this.httpservice.handleRequest(this.conn, context);
+ }
+ } catch (ConnectionClosedException ex) {
+ } catch (IOException ex) {
+ System.err.println("I/O error: " + ex.getMessage());
+ } catch (HttpException ex) {
+ System.err.println("Unrecoverable HTTP protocol violation: " + ex.getMessage());
+ } finally {
+ try {
+ this.conn.shutdown();
+ } catch (IOException ignore) {}
+ }
+ }
+
+ }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java
new file mode 100644
index 0000000..6b57d13
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TestHttpService.java
@@ -0,0 +1,608 @@
+/*
+ * $HeadURL: http://svn.apache.org/repos/asf/jakarta/httpcomponents/httpcore/tags/4.0-alpha6/module-main/src/test/java/org/apache/http/protocol/TestHttpServiceAndExecutor.java $
+ * $Revision: 576073 $
+ * $Date: 2007-09-16 03:53:13 -0700 (Sun, 16 Sep 2007) $
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation. For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package com.android.unit_tests;
+
+import org.apache.http.protocol.HttpExpectationVerifier;
+import org.apache.http.protocol.HttpRequestHandler;
+import android.test.PerformanceTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import junit.framework.TestCase;
+
+import org.apache.http.Header;
+import org.apache.http.HttpConnectionMetrics;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpEntityEnclosingRequest;
+import org.apache.http.HttpException;
+import org.apache.http.HttpHost;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.HttpStatus;
+import org.apache.http.HttpVersion;
+import org.apache.http.entity.ByteArrayEntity;
+import org.apache.http.entity.StringEntity;
+import org.apache.http.impl.DefaultHttpClientConnection;
+import org.apache.http.message.BasicHttpEntityEnclosingRequest;
+import org.apache.http.message.BasicHttpRequest;
+import org.apache.http.params.CoreProtocolPNames;
+import org.apache.http.protocol.HttpContext;
+import org.apache.http.util.EncodingUtils;
+import org.apache.http.util.EntityUtils;
+
+
+import java.io.IOException;
+import java.net.Socket;
+import java.net.URI;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+public class TestHttpService extends TestCase implements PerformanceTestCase {
+
+ public boolean isPerformanceOnly() {
+ // TODO Auto-generated method stub
+ return false;
+ }
+
+ public int startPerformance(Intermediates intermediates) {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ private TestHttpServer server;
+ private TestHttpClient client;
+
+ protected void setUp() throws Exception {
+ this.server = new TestHttpServer();
+ this.client = new TestHttpClient();
+ }
+
+ protected void tearDown() throws Exception {
+ if (server != null) {
+ this.server.shutdown();
+ }
+ }
+
+ /**
+ * This test case executes a series of simple GET requests
+ */
+ @LargeTest
+ public void testSimpleBasicHttpRequests() throws Exception {
+
+ int reqNo = 20;
+
+ Random rnd = new Random();
+
+ // Prepare some random data
+ final List testData = new ArrayList(reqNo);
+ for (int i = 0; i < reqNo; i++) {
+ int size = rnd.nextInt(5000);
+ byte[] data = new byte[size];
+ rnd.nextBytes(data);
+ testData.add(data);
+ }
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ String s = request.getRequestLine().getUri();
+ if (s.startsWith("/?")) {
+ s = s.substring(2);
+ }
+ int index = Integer.parseInt(s);
+ byte[] data = (byte []) testData.get(index);
+ ByteArrayEntity entity = new ByteArrayEntity(data);
+ response.setEntity(entity);
+ }
+
+ });
+
+ this.server.start();
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpRequest get = new BasicHttpRequest("GET", "/?" + r);
+ HttpResponse response = this.client.execute(get, host, conn);
+ byte[] received = EntityUtils.toByteArray(response.getEntity());
+ byte[] expected = (byte[]) testData.get(r);
+
+ assertEquals(expected.length, received.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], received[i]);
+ }
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+ /**
+ * This test case executes a series of simple POST requests with content length
+ * delimited content.
+ */
+ @LargeTest
+ public void testSimpleHttpPostsWithContentLength() throws Exception {
+
+ int reqNo = 20;
+
+ Random rnd = new Random();
+
+ // Prepare some random data
+ List testData = new ArrayList(reqNo);
+ for (int i = 0; i < reqNo; i++) {
+ int size = rnd.nextInt(5000);
+ byte[] data = new byte[size];
+ rnd.nextBytes(data);
+ testData.add(data);
+ }
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+ byte[] data = EntityUtils.toByteArray(incoming);
+
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(false);
+ response.setEntity(outgoing);
+ } else {
+ StringEntity outgoing = new StringEntity("No content");
+ response.setEntity(outgoing);
+ }
+ }
+
+ });
+
+ this.server.start();
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+ byte[] data = (byte[]) testData.get(r);
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ post.setEntity(outgoing);
+
+ HttpResponse response = this.client.execute(post, host, conn);
+ byte[] received = EntityUtils.toByteArray(response.getEntity());
+ byte[] expected = (byte[]) testData.get(r);
+
+ assertEquals(expected.length, received.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], received[i]);
+ }
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+ /**
+ * This test case executes a series of simple POST requests with chunk
+ * coded content content.
+ */
+ @LargeTest
+ public void testSimpleHttpPostsChunked() throws Exception {
+
+ int reqNo = 20;
+
+ Random rnd = new Random();
+
+ // Prepare some random data
+ List testData = new ArrayList(reqNo);
+ for (int i = 0; i < reqNo; i++) {
+ int size = rnd.nextInt(20000);
+ byte[] data = new byte[size];
+ rnd.nextBytes(data);
+ testData.add(data);
+ }
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+ byte[] data = EntityUtils.toByteArray(incoming);
+
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(true);
+ response.setEntity(outgoing);
+ } else {
+ StringEntity outgoing = new StringEntity("No content");
+ response.setEntity(outgoing);
+ }
+ }
+
+ });
+
+ this.server.start();
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+ byte[] data = (byte[]) testData.get(r);
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(true);
+ post.setEntity(outgoing);
+
+ HttpResponse response = this.client.execute(post, host, conn);
+ byte[] received = EntityUtils.toByteArray(response.getEntity());
+ byte[] expected = (byte[]) testData.get(r);
+
+ assertEquals(expected.length, received.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], received[i]);
+ }
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+ /**
+ * This test case executes a series of simple HTTP/1.0 POST requests.
+ */
+ @LargeTest
+ public void testSimpleHttpPostsHTTP10() throws Exception {
+
+ int reqNo = 20;
+
+ Random rnd = new Random();
+
+ // Prepare some random data
+ List testData = new ArrayList(reqNo);
+ for (int i = 0; i < reqNo; i++) {
+ int size = rnd.nextInt(5000);
+ byte[] data = new byte[size];
+ rnd.nextBytes(data);
+ testData.add(data);
+ }
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+ byte[] data = EntityUtils.toByteArray(incoming);
+
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(false);
+ response.setEntity(outgoing);
+ } else {
+ StringEntity outgoing = new StringEntity("No content");
+ response.setEntity(outgoing);
+ }
+ }
+
+ });
+
+ this.server.start();
+
+ // Set protocol level to HTTP/1.0
+ this.client.getParams().setParameter(
+ CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_0);
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+ byte[] data = (byte[]) testData.get(r);
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ post.setEntity(outgoing);
+
+ HttpResponse response = this.client.execute(post, host, conn);
+ assertEquals(HttpVersion.HTTP_1_0, response.getStatusLine().getProtocolVersion());
+ byte[] received = EntityUtils.toByteArray(response.getEntity());
+ byte[] expected = (byte[]) testData.get(r);
+
+ assertEquals(expected.length, received.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], received[i]);
+ }
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+ /**
+ * This test case executes a series of simple POST requests using
+ * the 'expect: continue' handshake.
+ */
+ @LargeTest
+ public void testHttpPostsWithExpectContinue() throws Exception {
+
+ int reqNo = 20;
+
+ Random rnd = new Random();
+
+ // Prepare some random data
+ List testData = new ArrayList(reqNo);
+ for (int i = 0; i < reqNo; i++) {
+ int size = rnd.nextInt(5000);
+ byte[] data = new byte[size];
+ rnd.nextBytes(data);
+ testData.add(data);
+ }
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ if (request instanceof HttpEntityEnclosingRequest) {
+ HttpEntity incoming = ((HttpEntityEnclosingRequest) request).getEntity();
+ byte[] data = EntityUtils.toByteArray(incoming);
+
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(true);
+ response.setEntity(outgoing);
+ } else {
+ StringEntity outgoing = new StringEntity("No content");
+ response.setEntity(outgoing);
+ }
+ }
+
+ });
+
+ this.server.start();
+
+ // Activate 'expect: continue' handshake
+ this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+ byte[] data = (byte[]) testData.get(r);
+ ByteArrayEntity outgoing = new ByteArrayEntity(data);
+ outgoing.setChunked(true);
+ post.setEntity(outgoing);
+
+ HttpResponse response = this.client.execute(post, host, conn);
+ byte[] received = EntityUtils.toByteArray(response.getEntity());
+ byte[] expected = (byte[]) testData.get(r);
+
+ assertEquals(expected.length, received.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals(expected[i], received[i]);
+ }
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+
+ /**
+ * This test case executes a series of simple POST requests that do not
+ * meet the target server expectations.
+ */
+ @LargeTest
+ public void testHttpPostsWithExpectationVerification() throws Exception {
+
+ int reqNo = 3;
+
+ // Initialize the server-side request handler
+ this.server.registerHandler("*", new HttpRequestHandler() {
+
+ public void handle(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException, IOException {
+
+ StringEntity outgoing = new StringEntity("No content");
+ response.setEntity(outgoing);
+ }
+
+ });
+
+ this.server.setExpectationVerifier(new HttpExpectationVerifier() {
+
+ public void verify(
+ final HttpRequest request,
+ final HttpResponse response,
+ final HttpContext context) throws HttpException {
+ Header someheader = request.getFirstHeader("Secret");
+ if (someheader != null) {
+ int secretNumber;
+ try {
+ secretNumber = Integer.parseInt(someheader.getValue());
+ } catch (NumberFormatException ex) {
+ response.setStatusCode(HttpStatus.SC_BAD_REQUEST);
+ return;
+ }
+ if (secretNumber < 2) {
+ response.setStatusCode(HttpStatus.SC_EXPECTATION_FAILED);
+ ByteArrayEntity outgoing = new ByteArrayEntity(
+ EncodingUtils.getAsciiBytes("Wrong secret number"));
+ response.setEntity(outgoing);
+ }
+ }
+ }
+
+ });
+
+ this.server.start();
+
+ // Activate 'expect: continue' handshake
+ this.client.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, true);
+
+ DefaultHttpClientConnection conn = new DefaultHttpClientConnection();
+ HttpHost host = new HttpHost("localhost", this.server.getPort());
+
+ try {
+ for (int r = 0; r < reqNo; r++) {
+ if (!conn.isOpen()) {
+ Socket socket = new Socket(host.getHostName(), host.getPort());
+ conn.bind(socket, this.client.getParams());
+ }
+
+ BasicHttpEntityEnclosingRequest post = new BasicHttpEntityEnclosingRequest("POST", "/");
+ post.addHeader("Secret", Integer.toString(r));
+ ByteArrayEntity outgoing = new ByteArrayEntity(
+ EncodingUtils.getAsciiBytes("No content"));
+ post.setEntity(outgoing);
+
+ HttpResponse response = this.client.execute(post, host, conn);
+
+ HttpEntity entity = response.getEntity();
+ assertNotNull(entity);
+ entity.consumeContent();
+
+ if (r < 2) {
+ assertEquals(HttpStatus.SC_EXPECTATION_FAILED, response.getStatusLine().getStatusCode());
+ } else {
+ assertEquals(HttpStatus.SC_OK, response.getStatusLine().getStatusCode());
+ }
+
+ if (!this.client.keepAlive(response)) {
+ conn.close();
+ }
+ }
+ //Verify the connection metrics
+ HttpConnectionMetrics cm = conn.getMetrics();
+ assertEquals(reqNo, cm.getRequestCount());
+ assertEquals(reqNo, cm.getResponseCount());
+ } finally {
+ conn.close();
+ this.server.shutdown();
+ }
+ }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java
new file mode 100644
index 0000000..8cfcd5e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextLayoutTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.DynamicLayout;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
+import junit.framework.TestCase;
+
+
+public class TextLayoutTest extends TestCase {
+
+ protected String mString;
+ protected TextPaint mPaint;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mString = "The quick brown fox";
+ mPaint = new TextPaint();
+ }
+
+ @SmallTest
+ public void testStaticLayout() throws Exception {
+ Layout l = new StaticLayout(mString, mPaint, 200,
+ Layout.Alignment.ALIGN_NORMAL, 1, 0,
+ true);
+ }
+
+ @SmallTest
+ public void testDynamicLayoutTest() throws Exception {
+ Layout l = new DynamicLayout(mString, mPaint, 200,
+ Layout.Alignment.ALIGN_NORMAL, 1, 0,
+ true);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
new file mode 100644
index 0000000..51e841c
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextUtilsTest.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.graphics.Paint;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.Spanned;
+import android.text.SpannedString;
+import android.text.TextPaint;
+import android.text.TextUtils;
+import android.text.style.StyleSpan;
+import android.text.util.Rfc822Validator;
+import android.test.MoreAsserts;
+
+import junit.framework.TestCase;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * TextUtilsTest tests {@link TextUtils}.
+ */
+public class TextUtilsTest extends TestCase {
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ assertEquals("", TextUtils.concat());
+ assertEquals("foo", TextUtils.concat("foo"));
+ assertEquals("foobar", TextUtils.concat("foo", "bar"));
+ assertEquals("foobarbaz", TextUtils.concat("foo", "bar", "baz"));
+
+ SpannableString foo = new SpannableString("foo");
+ foo.setSpan("foo", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+ SpannableString bar = new SpannableString("bar");
+ bar.setSpan("bar", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+ SpannableString baz = new SpannableString("baz");
+ baz.setSpan("baz", 1, 2, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
+
+ assertEquals("foo", TextUtils.concat(foo).toString());
+ assertEquals("foobar", TextUtils.concat(foo, bar).toString());
+ assertEquals("foobarbaz", TextUtils.concat(foo, bar, baz).toString());
+
+ assertEquals(1, ((Spanned) TextUtils.concat(foo)).getSpanStart("foo"));
+
+ assertEquals(1, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("foo"));
+ assertEquals(4, ((Spanned) TextUtils.concat(foo, bar)).getSpanStart("bar"));
+
+ assertEquals(1, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("foo"));
+ assertEquals(4, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("bar"));
+ assertEquals(7, ((Spanned) TextUtils.concat(foo, bar, baz)).getSpanStart("baz"));
+
+ assertTrue(TextUtils.concat("foo", "bar") instanceof String);
+ assertTrue(TextUtils.concat(foo, bar) instanceof SpannedString);
+ }
+
+ @SmallTest
+ public void testTemplateString() throws Exception {
+ CharSequence result;
+
+ result = TextUtils.expandTemplate("This is a ^1 of the ^2 broadcast ^3.",
+ "test", "emergency", "system");
+ assertEquals("This is a test of the emergency broadcast system.",
+ result.toString());
+
+ result = TextUtils.expandTemplate("^^^1^^^2^3^a^1^^b^^^c",
+ "one", "two", "three");
+ assertEquals("^one^twothree^aone^b^^c",
+ result.toString());
+
+ result = TextUtils.expandTemplate("^");
+ assertEquals("^", result.toString());
+
+ result = TextUtils.expandTemplate("^^");
+ assertEquals("^", result.toString());
+
+ result = TextUtils.expandTemplate("^^^");
+ assertEquals("^^", result.toString());
+
+ result = TextUtils.expandTemplate("shorter ^1 values ^2.", "a", "");
+ assertEquals("shorter a values .", result.toString());
+
+ try {
+ TextUtils.expandTemplate("Only ^1 value given, but ^2 used.", "foo");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ try {
+ TextUtils.expandTemplate("^1 value given, and ^0 used.", "foo");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ result = TextUtils.expandTemplate("^1 value given, and ^9 used.",
+ "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine");
+ assertEquals("one value given, and nine used.", result.toString());
+
+ try {
+ TextUtils.expandTemplate("^1 value given, and ^10 used.",
+ "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten");
+ fail();
+ } catch (IllegalArgumentException e) {
+ }
+
+ // putting carets in the values: expansion is not recursive.
+
+ result = TextUtils.expandTemplate("^2", "foo", "^^");
+ assertEquals("^^", result.toString());
+
+ result = TextUtils.expandTemplate("^^2", "foo", "1");
+ assertEquals("^2", result.toString());
+
+ result = TextUtils.expandTemplate("^1", "value with ^2 in it", "foo");
+ assertEquals("value with ^2 in it", result.toString());
+ }
+
+ /** Fail unless text+spans contains a span 'spanName' with the given start and end. */
+ private void checkContains(Spanned text, String[] spans, String spanName,
+ int start, int end) throws Exception {
+ for (String i: spans) {
+ if (i.equals(spanName)) {
+ assertEquals(start, text.getSpanStart(i));
+ assertEquals(end, text.getSpanEnd(i));
+ return;
+ }
+ }
+ fail();
+ }
+
+ @SmallTest
+ public void testTemplateSpan() throws Exception {
+ SpannableString template;
+ Spanned result;
+ String[] spans;
+
+ // ordinary replacement
+
+ template = new SpannableString("a^1b");
+ template.setSpan("before", 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ template.setSpan("during", 1, 3, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ template.setSpan("after", 3, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ template.setSpan("during+after", 1, 4, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+
+ result = (Spanned) TextUtils.expandTemplate(template, "foo");
+ assertEquals(5, result.length());
+ spans = result.getSpans(0, result.length(), String.class);
+
+ // value is one character longer, so span endpoints should change.
+ assertEquals(4, spans.length);
+ checkContains(result, spans, "before", 0, 1);
+ checkContains(result, spans, "during", 1, 4);
+ checkContains(result, spans, "after", 4, 5);
+ checkContains(result, spans, "during+after", 1, 5);
+
+
+ // replacement with empty string
+
+ result = (Spanned) TextUtils.expandTemplate(template, "");
+ assertEquals(2, result.length());
+ spans = result.getSpans(0, result.length(), String.class);
+
+ // the "during" span should disappear.
+ assertEquals(3, spans.length);
+ checkContains(result, spans, "before", 0, 1);
+ checkContains(result, spans, "after", 1, 2);
+ checkContains(result, spans, "during+after", 1, 2);
+ }
+
+ @SmallTest
+ public void testStringSplitterSimple() {
+ stringSplitterTestHelper("a,b,cde", new String[] {"a", "b", "cde"});
+ }
+
+ @SmallTest
+ public void testStringSplitterEmpty() {
+ stringSplitterTestHelper("", new String[] {});
+ }
+
+ @SmallTest
+ public void testStringSplitterWithLeadingEmptyString() {
+ stringSplitterTestHelper(",a,b,cde", new String[] {"", "a", "b", "cde"});
+ }
+
+ @SmallTest
+ public void testStringSplitterWithInternalEmptyString() {
+ stringSplitterTestHelper("a,b,,cde", new String[] {"a", "b", "", "cde"});
+ }
+
+ @SmallTest
+ public void testStringSplitterWithTrailingEmptyString() {
+ // A single trailing emtpy string should be ignored.
+ stringSplitterTestHelper("a,b,cde,", new String[] {"a", "b", "cde"});
+ }
+
+ private void stringSplitterTestHelper(String string, String[] expectedStrings) {
+ TextUtils.StringSplitter splitter = new TextUtils.SimpleStringSplitter(',');
+ splitter.setString(string);
+ List<String> strings = Lists.newArrayList();
+ for (String s : splitter) {
+ strings.add(s);
+ }
+ MoreAsserts.assertEquals(expectedStrings, strings.toArray(new String[]{}));
+ }
+
+ @SmallTest
+ public void testTrim() {
+ String[] strings = { "abc", " abc", " abc", "abc ", "abc ",
+ " abc ", " abc ", "\nabc\n", "\nabc", "abc\n" };
+
+ for (String s : strings) {
+ assertEquals(s.trim().length(), TextUtils.getTrimmedLength(s));
+ }
+ }
+
+ //==============================================================================================
+ // Email validator
+ //==============================================================================================
+
+ @SmallTest
+ public void testEmailValidator() {
+ Rfc822Validator validator = new Rfc822Validator("gmail.com");
+ String[] validEmails = new String[] {
+ "a@b.com", "a@b.fr", "a+b@c.com", "a@b.info",
+ };
+
+ for (String email : validEmails) {
+ assertTrue(email + " should be a valid email address", validator.isValid(email));
+ }
+
+ String[] invalidEmails = new String[] {
+ "a", "a@b", "a b", "a@b.12"
+ };
+
+ for (String email : invalidEmails) {
+ assertFalse(email + " should not be a valid email address", validator.isValid(email));
+ }
+
+ Map<String, String> fixes = Maps.newHashMap();
+ fixes.put("a", "<a@gmail.com>");
+ fixes.put("a b", "<ab@gmail.com>");
+ fixes.put("a@b", "<a@b>");
+
+ for (Map.Entry<String, String> e : fixes.entrySet()) {
+ assertEquals(e.getValue(), validator.fixText(e.getKey()).toString());
+ }
+ }
+
+ @LargeTest
+ public void testEllipsize() {
+ CharSequence s1 = "The quick brown fox jumps over \u00FEhe lazy dog.";
+ CharSequence s2 = new Wrapper(s1);
+ Spannable s3 = new SpannableString(s1);
+ s3.setSpan(new StyleSpan(0), 5, 10, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
+ TextPaint p = new TextPaint();
+
+ for (int i = 0; i < 100; i++) {
+ for (int j = 0; j < 3; j++) {
+ TextUtils.TruncateAt kind = null;
+
+ switch (j) {
+ case 0:
+ kind = TextUtils.TruncateAt.START;
+ break;
+
+ case 1:
+ kind = TextUtils.TruncateAt.END;
+ break;
+
+ case 2:
+ kind = TextUtils.TruncateAt.MIDDLE;
+ break;
+ }
+
+ String out1 = TextUtils.ellipsize(s1, p, i, kind).toString();
+ String out2 = TextUtils.ellipsize(s2, p, i, kind).toString();
+ String out3 = TextUtils.ellipsize(s3, p, i, kind).toString();
+
+ String keep1 = TextUtils.ellipsize(s1, p, i, kind, true, null).toString();
+ String keep2 = TextUtils.ellipsize(s2, p, i, kind, true, null).toString();
+ String keep3 = TextUtils.ellipsize(s3, p, i, kind, true, null).toString();
+
+ String trim1 = keep1.replace("\uFEFF", "");
+
+ // Are all normal output strings identical?
+ assertEquals("wid " + i + " pass " + j, out1, out2);
+ assertEquals("wid " + i + " pass " + j, out2, out3);
+
+ // Are preserved output strings identical?
+ assertEquals("wid " + i + " pass " + j, keep1, keep2);
+ assertEquals("wid " + i + " pass " + j, keep2, keep3);
+
+ // Does trimming padding from preserved yield normal?
+ assertEquals("wid " + i + " pass " + j, out1, trim1);
+
+ // Did preserved output strings preserve length?
+ assertEquals("wid " + i + " pass " + j, keep1.length(), s1.length());
+
+ // Does the output string actually fit in the space?
+ assertTrue("wid " + i + " pass " + j, p.measureText(out1) <= i);
+
+ // Is the padded output the same width as trimmed output?
+ assertTrue("wid " + i + " pass " + j, p.measureText(keep1) == p.measureText(out1));
+ }
+ }
+ }
+
+ /**
+ * CharSequence wrapper for testing the cases where text is copied into
+ * a char array instead of working from a String or a Spanned.
+ */
+ private static class Wrapper implements CharSequence {
+ private CharSequence mString;
+
+ public Wrapper(CharSequence s) {
+ mString = s;
+ }
+
+ public int length() {
+ return mString.length();
+ }
+
+ public char charAt(int off) {
+ return mString.charAt(off);
+ }
+
+ public String toString() {
+ return mString.toString();
+ }
+
+ public CharSequence subSequence(int start, int end) {
+ return new Wrapper(mString.subSequence(start, end));
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java
new file mode 100644
index 0000000..6fa8f4f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewPerformanceTest.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannedString;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+public class TextViewPerformanceTest extends AndroidTestCase {
+
+ private String mString = "The quick brown fox";
+ private Canvas mCanvas;
+ private PerformanceTextView mTextView;
+ private Paint mPaint;
+ private PerformanceLabelView mLabelView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ Bitmap mBitmap = Bitmap.createBitmap(320, 240, Bitmap.Config.RGB_565);
+ mCanvas = new Canvas(mBitmap);
+
+ ViewGroup.LayoutParams p = new ViewGroup.LayoutParams(320, 240);
+
+ mLabelView = new PerformanceLabelView(mContext);
+ mLabelView.setText(mString);
+ mLabelView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
+ mLabelView.mySetFrame(320, 240);
+ mLabelView.setLayoutParams(p);
+ mLabelView.myDraw(mCanvas);
+
+ mPaint = new Paint();
+ mCanvas.save();
+ mTextView = new PerformanceTextView(mContext);
+ mTextView.setLayoutParams(p);
+ mTextView.setText(mString);
+ mTextView.mySetFrame(320, 240);
+ mTextView.measure(View.MeasureSpec.AT_MOST | 320, View.MeasureSpec.AT_MOST | 240);
+ }
+
+ @MediumTest
+ public void testDrawTextViewLine() throws Exception {
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ }
+
+ @SmallTest
+ public void testSpan() throws Exception {
+ CharSequence charSeq = new SpannedString(mString);
+ mTextView.setText(charSeq);
+
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ mTextView.myDraw(mCanvas);
+ }
+
+ @SmallTest
+ public void testCanvasDrawText() throws Exception {
+ mCanvas.drawText(mString, 30, 30, mPaint);
+ }
+
+ @SmallTest
+ public void testLabelViewDraw() throws Exception {
+ mLabelView.myDraw(mCanvas);
+ }
+
+ private class PerformanceTextView extends TextView {
+ public PerformanceTextView(Context context) {
+ super(context);
+ }
+
+ final void myDraw(Canvas c) {
+ super.onDraw(c);
+ }
+
+ final void mySetFrame(int w, int h) {
+ super.setFrame(0, 0, w, h);
+ }
+ }
+
+ private class PerformanceLabelView extends LabelView {
+ public PerformanceLabelView(Context context) {
+ super(context);
+ }
+
+ final void myDraw(Canvas c) {
+ super.onDraw(c);
+ }
+
+ final void mySetFrame(int w, int h) {
+ super.setFrame(0, 0, w, h);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java
new file mode 100644
index 0000000..8e49118
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TextViewTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.GetChars;
+import android.widget.TextView;
+
+/**
+ * TextViewTest tests {@link TextView}.
+ */
+public class TextViewTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testArray() throws Exception {
+ TextView tv = new TextView(mContext);
+
+ char[] c = new char[] { 'H', 'e', 'l', 'l', 'o', ' ',
+ 'W', 'o', 'r', 'l', 'd', '!' };
+
+ tv.setText(c, 1, 4);
+ CharSequence oldText = tv.getText();
+
+ tv.setText(c, 4, 5);
+ CharSequence newText = tv.getText();
+
+ assertTrue(newText == oldText);
+
+ assertEquals(5, newText.length());
+ assertEquals('o', newText.charAt(0));
+ assertEquals("o Wor", newText.toString());
+
+ assertEquals(" Wo", newText.subSequence(1, 4));
+
+ char[] c2 = new char[7];
+ ((GetChars) newText).getChars(1, 4, c2, 2);
+ assertEquals('\0', c2[1]);
+ assertEquals(' ', c2[2]);
+ assertEquals('W', c2[3]);
+ assertEquals('o', c2[4]);
+ assertEquals('\0', c2[5]);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java
new file mode 100644
index 0000000..220bc99e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/ThreadBitmapTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+import android.graphics.Bitmap;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class ThreadBitmapTest extends TestCase {
+
+ @Override
+ protected void setUp() throws Exception {
+ }
+
+ @LargeTest
+ public void testCreation() {
+ for (int i = 0; i < 200; i++) {
+
+ new MThread().start();
+ }
+ }
+
+ class MThread extends Thread {
+ public Bitmap b;
+
+ public MThread() {
+ b = Bitmap.createBitmap(300, 300, Bitmap.Config.RGB_565);
+ }
+
+ public void run() {}
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java
new file mode 100644
index 0000000..110caa4
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TimeTest.java
@@ -0,0 +1,525 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.format.Time;
+import android.util.Log;
+
+import junit.framework.TestCase;
+
+public class TimeTest extends TestCase {
+
+ @SmallTest
+ public void testNormalize0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.parse("20060432T010203");
+ t.normalize(false /* use isDst */);
+// System.out.println("got: " + t.year + '-'
+// + t.month + '-' + t.monthDay
+// + ' ' + t.hour + ':' + t.minute
+// + ':' + t.second
+// + "( " + t.isDst + ',' + t.gmtoff
+// + ',' + t.weekDay
+// + ',' + t.yearDay + ')');
+ }
+
+ private static class DateTest {
+ public int year1;
+ public int month1;
+ public int day1;
+ public int hour1;
+ public int minute1;
+ public int dst1;
+
+ public int offset;
+
+ public int year2;
+ public int month2;
+ public int day2;
+ public int hour2;
+ public int minute2;
+ public int dst2;
+
+ public DateTest(int year1, int month1, int day1, int hour1, int minute1, int dst1,
+ int offset, int year2, int month2, int day2, int hour2, int minute2,
+ int dst2) {
+ this.year1 = year1;
+ this.month1 = month1;
+ this.day1 = day1;
+ this.hour1 = hour1;
+ this.minute1 = minute1;
+ this.dst1 = dst1;
+ this.offset = offset;
+ this.year2 = year2;
+ this.month2 = month2;
+ this.day2 = day2;
+ this.hour2 = hour2;
+ this.minute2 = minute2;
+ this.dst2 = dst2;
+ }
+
+ public DateTest(int year1, int month1, int day1, int hour1, int minute1,
+ int offset, int year2, int month2, int day2, int hour2, int minute2) {
+ this.year1 = year1;
+ this.month1 = month1;
+ this.day1 = day1;
+ this.hour1 = hour1;
+ this.minute1 = minute1;
+ this.dst1 = -1;
+ this.offset = offset;
+ this.year2 = year2;
+ this.month2 = month2;
+ this.day2 = day2;
+ this.hour2 = hour2;
+ this.minute2 = minute2;
+ this.dst2 = -1;
+ }
+ }
+
+ // These tests assume that DST changes on Nov 4, 2007 at 2am (to 1am).
+
+ // The "offset" field in "dayTests" represents days.
+ // Use normalize(true) with these tests to change the date by 1 day.
+ private DateTest[] dayTests = {
+ // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
+
+ // Nov 4, 12am + 0 day = Nov 4, 12am
+ // Nov 5, 12am + 0 day = Nov 5, 12am
+ new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
+ new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
+
+ // Nov 3, 12am + 1 day = Nov 4, 12am
+ // Nov 4, 12am + 1 day = Nov 5, 12am
+ // Nov 5, 12am + 1 day = Nov 6, 12am
+ new DateTest(2007, 10, 3, 0, 0, 1, 2007, 10, 4, 0, 0),
+ new DateTest(2007, 10, 4, 0, 0, 1, 2007, 10, 5, 0, 0),
+ new DateTest(2007, 10, 5, 0, 0, 1, 2007, 10, 6, 0, 0),
+
+ // Nov 3, 1am + 1 day = Nov 4, 1am
+ // Nov 4, 1am + 1 day = Nov 5, 1am
+ // Nov 5, 1am + 1 day = Nov 6, 1am
+ new DateTest(2007, 10, 3, 1, 0, 1, 2007, 10, 4, 1, 0),
+ new DateTest(2007, 10, 4, 1, 0, 1, 2007, 10, 5, 1, 0),
+ new DateTest(2007, 10, 5, 1, 0, 1, 2007, 10, 6, 1, 0),
+
+ // Nov 3, 2am + 1 day = Nov 4, 2am
+ // Nov 4, 2am + 1 day = Nov 5, 2am
+ // Nov 5, 2am + 1 day = Nov 6, 2am
+ new DateTest(2007, 10, 3, 2, 0, 1, 2007, 10, 4, 2, 0),
+ new DateTest(2007, 10, 4, 2, 0, 1, 2007, 10, 5, 2, 0),
+ new DateTest(2007, 10, 5, 2, 0, 1, 2007, 10, 6, 2, 0),
+ };
+
+ // The "offset" field in "minuteTests" represents minutes.
+ // Use normalize(false) with these tests.
+ private DateTest[] minuteTests = {
+ // The month numbers are 0-relative, so Jan=0, Feb=1,...Dec=11
+
+ // Nov 4, 12am + 0 minutes = Nov 4, 12am
+ // Nov 5, 12am + 0 minutes = Nov 5, 12am
+ new DateTest(2007, 10, 4, 0, 0, 0, 2007, 10, 4, 0, 0),
+ new DateTest(2007, 10, 5, 0, 0, 0, 2007, 10, 5, 0, 0),
+
+ // Nov 3, 12am + 60 minutes = Nov 3, 1am
+ // Nov 4, 12am + 60 minutes = Nov 4, 1am
+ // Nov 5, 12am + 60 minutes = Nov 5, 1am
+ new DateTest(2007, 10, 3, 0, 0, 60, 2007, 10, 3, 1, 0),
+ new DateTest(2007, 10, 4, 0, 0, 60, 2007, 10, 4, 1, 0),
+ new DateTest(2007, 10, 5, 0, 0, 60, 2007, 10, 5, 1, 0),
+
+ // Nov 3, 1am + 60 minutes = Nov 3, 2am
+ // Nov 4, 1am (PDT) + 30 minutes = Nov 4, 1:30am (PDT)
+ // Nov 4, 1am (PDT) + 60 minutes = Nov 4, 1am (PST)
+ new DateTest(2007, 10, 3, 1, 0, 60, 2007, 10, 3, 2, 0),
+ new DateTest(2007, 10, 4, 1, 0, 1, 30, 2007, 10, 4, 1, 30, 1),
+ new DateTest(2007, 10, 4, 1, 0, 1, 60, 2007, 10, 4, 1, 0, 0),
+
+ // Nov 4, 1:30am (PDT) + 15 minutes = Nov 4, 1:45am (PDT)
+ // Nov 4, 1:30am (PDT) + 30 minutes = Nov 4, 1:00am (PST)
+ // Nov 4, 1:30am (PDT) + 60 minutes = Nov 4, 1:30am (PST)
+ new DateTest(2007, 10, 4, 1, 30, 1, 15, 2007, 10, 4, 1, 45, 1),
+ new DateTest(2007, 10, 4, 1, 30, 1, 30, 2007, 10, 4, 1, 0, 0),
+ new DateTest(2007, 10, 4, 1, 30, 1, 60, 2007, 10, 4, 1, 30, 0),
+
+ // Nov 4, 1:30am (PST) + 15 minutes = Nov 4, 1:45am (PST)
+ // Nov 4, 1:30am (PST) + 30 minutes = Nov 4, 2:00am (PST)
+ // Nov 5, 1am + 60 minutes = Nov 5, 2am
+ new DateTest(2007, 10, 4, 1, 30, 0, 15, 2007, 10, 4, 1, 45, 0),
+ new DateTest(2007, 10, 4, 1, 30, 0, 30, 2007, 10, 4, 2, 0, 0),
+ new DateTest(2007, 10, 5, 1, 0, 60, 2007, 10, 5, 2, 0),
+
+ // Nov 3, 2am + 60 minutes = Nov 3, 3am
+ // Nov 4, 2am + 30 minutes = Nov 4, 2:30am
+ // Nov 4, 2am + 60 minutes = Nov 4, 3am
+ // Nov 5, 2am + 60 minutes = Nov 5, 3am
+ new DateTest(2007, 10, 3, 2, 0, 60, 2007, 10, 3, 3, 0),
+ new DateTest(2007, 10, 4, 2, 0, 30, 2007, 10, 4, 2, 30),
+ new DateTest(2007, 10, 4, 2, 0, 60, 2007, 10, 4, 3, 0),
+ new DateTest(2007, 10, 5, 2, 0, 60, 2007, 10, 5, 3, 0),
+ };
+
+ @SmallTest
+ public void testNormalize1() throws Exception {
+ Time local = new Time("America/Los_Angeles");
+
+ int len = dayTests.length;
+ for (int index = 0; index < len; index++) {
+ DateTest test = dayTests[index];
+ local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+ // call normalize() to make sure that isDst is set
+ local.normalize(false /* use isDst */);
+ local.monthDay += test.offset;
+ local.normalize(true /* ignore isDst */);
+ if (local.year != test.year2 || local.month != test.month2
+ || local.monthDay != test.day2 || local.hour != test.hour2
+ || local.minute != test.minute2) {
+ String expectedTime = String.format("%d-%02d-%02d %02d:%02d",
+ test.year2, test.month2, test.day2, test.hour2, test.minute2);
+ String actualTime = String.format("%d-%02d-%02d %02d:%02d",
+ local.year, local.month, local.monthDay, local.hour, local.minute);
+ throw new RuntimeException(
+ "day test index " + index + ", normalize(): expected local " + expectedTime
+ + " got: " + actualTime);
+ }
+
+ local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+ // call normalize() to make sure that isDst is set
+ local.normalize(false /* use isDst */);
+ local.monthDay += test.offset;
+ long millis = local.toMillis(true /* ignore isDst */);
+ local.set(millis);
+ if (local.year != test.year2 || local.month != test.month2
+ || local.monthDay != test.day2 || local.hour != test.hour2
+ || local.minute != test.minute2) {
+ String expectedTime = String.format("%d-%02d-%02d %02d:%02d",
+ test.year2, test.month2, test.day2, test.hour2, test.minute2);
+ String actualTime = String.format("%d-%02d-%02d %02d:%02d",
+ local.year, local.month, local.monthDay, local.hour, local.minute);
+ throw new RuntimeException(
+ "day test index " + index + ", toMillis(): expected local " + expectedTime
+ + " got: " + actualTime);
+ }
+ }
+
+ len = minuteTests.length;
+ for (int index = 0; index < len; index++) {
+ DateTest test = minuteTests[index];
+ local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+ local.isDst = test.dst1;
+ // call normalize() to make sure that isDst is set
+ local.normalize(false /* use isDst */);
+ if (test.dst2 == -1) test.dst2 = local.isDst;
+ local.minute += test.offset;
+ local.normalize(false /* use isDst */);
+ if (local.year != test.year2 || local.month != test.month2
+ || local.monthDay != test.day2 || local.hour != test.hour2
+ || local.minute != test.minute2 || local.isDst != test.dst2) {
+ String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+ test.year2, test.month2, test.day2, test.hour2, test.minute2,
+ test.dst2);
+ String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+ local.year, local.month, local.monthDay, local.hour, local.minute,
+ local.isDst);
+ throw new RuntimeException(
+ "minute test index " + index + ", normalize(): expected local " + expectedTime
+ + " got: " + actualTime);
+ }
+
+ local.set(0, test.minute1, test.hour1, test.day1, test.month1, test.year1);
+ local.isDst = test.dst1;
+ // call normalize() to make sure that isDst is set
+ local.normalize(false /* use isDst */);
+ if (test.dst2 == -1) test.dst2 = local.isDst;
+ local.minute += test.offset;
+ long millis = local.toMillis(false /* use isDst */);
+ local.set(millis);
+ if (local.year != test.year2 || local.month != test.month2
+ || local.monthDay != test.day2 || local.hour != test.hour2
+ || local.minute != test.minute2 || local.isDst != test.dst2) {
+ String expectedTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+ test.year2, test.month2, test.day2, test.hour2, test.minute2,
+ test.dst2);
+ String actualTime = String.format("%d-%02d-%02d %02d:%02d isDst: %d",
+ local.year, local.month, local.monthDay, local.hour, local.minute,
+ local.isDst);
+ throw new RuntimeException(
+ "minute test index " + index + ", toMillis(): expected local " + expectedTime
+ + " got: " + actualTime);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testSwitchTimezone0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.parse("20061005T120000");
+ t.switchTimezone("America/Los_Angeles");
+ // System.out.println("got: " + t);
+ }
+
+ @SmallTest
+ public void testCtor0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ assertEquals(Time.TIMEZONE_UTC, t.timezone);
+ }
+
+ @SmallTest
+ public void testGetActualMaximum0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ int r = t.getActualMaximum(Time.SECOND);
+ // System.out.println("r=" + r);
+ }
+
+ @SmallTest
+ public void testClear0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.clear(Time.TIMEZONE_UTC);
+ }
+
+ @SmallTest
+ public void testCompare0() throws Exception {
+ Time a = new Time(Time.TIMEZONE_UTC);
+ Time b = new Time("America/Los_Angeles");
+ int r = Time.compare(a, b);
+ // System.out.println("r=" + r);
+ }
+
+ @SmallTest
+ public void testFormat0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ String r = t.format("%Y%m%dT%H%M%S");
+ // System.out.println("r='" + r + "'");
+ }
+
+ @SmallTest
+ public void testToString0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ String r = t.toString();
+ // System.out.println("r='" + r + "'");
+ }
+
+ @SmallTest
+ public void testGetCurrentTimezone0() throws Exception {
+ String r = Time.getCurrentTimezone();
+ // System.out.println("r='" + r + "'");
+ }
+
+ @SmallTest
+ public void testSetToNow0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.setToNow();
+ // System.out.println("t=" + t);
+ }
+
+ @SmallTest
+ public void testMillis0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.set(0, 0, 0, 1, 1, 2006);
+ long r = t.toMillis(true /* ignore isDst */);
+ // System.out.println("r=" + r);
+ t.set(1, 0, 0, 1, 1, 2006);
+ r = t.toMillis(true /* ignore isDst */);
+ // System.out.println("r=" + r);
+ }
+
+ @SmallTest
+ public void testMillis1() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.set(1, 0, 0, 1, 0, 1970);
+ long r = t.toMillis(true /* ignore isDst */);
+ // System.out.println("r=" + r);
+ }
+
+ @SmallTest
+ public void testParse0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.parse("12345678T901234");
+ // System.out.println("t=" + t);
+ }
+
+ @SmallTest
+ public void testSet0() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.set(1000L);
+ // System.out.println("t.year=" + t.year);
+ // System.out.println("t=" + t);
+ t.set(2000L);
+ // System.out.println("t=" + t);
+ t.set(1000L * 60);
+ // System.out.println("t=" + t);
+ t.set((1000L * 60 * 60 * 24) + 1000L);
+ // System.out.println("t=" + t);
+ }
+
+ @SmallTest
+ public void testSet1() throws Exception {
+ Time t = new Time(Time.TIMEZONE_UTC);
+ t.set(1, 2, 3, 4, 5, 6);
+ // System.out.println("t=" + t);
+ }
+
+ // Timezones that cover the world. Some GMT offsets occur more than
+ // once in case some cities decide to change their GMT offset.
+ private static final String[] mTimeZones = {
+ "Pacific/Kiritimati",
+ "Pacific/Enderbury",
+ "Pacific/Fiji",
+ "Antarctica/South_Pole",
+ "Pacific/Norfolk",
+ "Pacific/Ponape",
+ "Asia/Magadan",
+ "Australia/Lord_Howe",
+ "Australia/Sydney",
+ "Australia/Adelaide",
+ "Asia/Tokyo",
+ "Asia/Seoul",
+ "Asia/Taipei",
+ "Asia/Singapore",
+ "Asia/Hong_Kong",
+ "Asia/Saigon",
+ "Asia/Bangkok",
+ "Indian/Cocos",
+ "Asia/Rangoon",
+ "Asia/Omsk",
+ "Antarctica/Mawson",
+ "Asia/Colombo",
+ "Asia/Calcutta",
+ "Asia/Oral",
+ "Asia/Kabul",
+ "Asia/Dubai",
+ "Asia/Tehran",
+ "Europe/Moscow",
+ "Asia/Baghdad",
+ "Africa/Mogadishu",
+ "Europe/Athens",
+ "Africa/Cairo",
+ "Europe/Rome",
+ "Europe/Berlin",
+ "Europe/Amsterdam",
+ "Africa/Tunis",
+ "Europe/London",
+ "Europe/Dublin",
+ "Atlantic/St_Helena",
+ "Africa/Monrovia",
+ "Africa/Accra",
+ "Atlantic/Azores",
+ "Atlantic/South_Georgia",
+ "America/Noronha",
+ "America/Sao_Paulo",
+ "America/Cayenne",
+ "America/St_Johns",
+ "America/Puerto_Rico",
+ "America/Aruba",
+ "America/New_York",
+ "America/Chicago",
+ "America/Denver",
+ "America/Los_Angeles",
+ "America/Anchorage",
+ "Pacific/Marquesas",
+ "America/Adak",
+ "Pacific/Honolulu",
+ "Pacific/Midway",
+ };
+
+ @Suppress
+ public void disableTestGetJulianDay() throws Exception {
+ Time time = new Time();
+
+ // For each day of the year, and for each timezone, get the Julian
+ // day for 12am and then check that if we change the time we get the
+ // same Julian day.
+ for (int monthDay = 1; monthDay <= 366; monthDay++) {
+ for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
+ // We leave the "month" as zero because we are changing the
+ // "monthDay" from 1 to 366. The call to normalize() will
+ // then change the "month" (but we don't really care).
+ time.set(0, 0, 0, monthDay, 0, 2008);
+ time.timezone = mTimeZones[zoneIndex];
+ long millis = time.normalize(true);
+ if (zoneIndex == 0) {
+ Log.i("TimeTest", time.format("%B %d, %Y"));
+ }
+
+ // This is the Julian day for 12am for this day of the year
+ int julianDay = Time.getJulianDay(millis, time.gmtoff);
+
+ // Change the time during the day and check that we get the same
+ // Julian day.
+ for (int hour = 0; hour < 24; hour++) {
+ for (int minute = 0; minute < 60; minute += 15) {
+ time.set(0, minute, hour, monthDay, 0, 2008);
+ millis = time.normalize(true);
+ int day = Time.getJulianDay(millis, time.gmtoff);
+ if (day != julianDay) {
+ Log.e("TimeTest", "Julian day: " + day + " at time "
+ + time.hour + ":" + time.minute
+ + " != today's Julian day: " + julianDay
+ + " timezone: " + time.timezone);
+ }
+ assertEquals(day, julianDay);
+ }
+ }
+ }
+ }
+ }
+
+ @Suppress
+ public void disableTestSetJulianDay() throws Exception {
+ Time time = new Time();
+
+ // For each day of the year in 2008, and for each timezone,
+ // test that we can set the Julian day correctly.
+ for (int monthDay = 1; monthDay <= 366; monthDay++) {
+ for (int zoneIndex = 0; zoneIndex < mTimeZones.length; zoneIndex++) {
+ // We leave the "month" as zero because we are changing the
+ // "monthDay" from 1 to 366. The call to normalize() will
+ // then change the "month" (but we don't really care).
+ time.set(0, 0, 0, monthDay, 0, 2008);
+ time.timezone = mTimeZones[zoneIndex];
+ long millis = time.normalize(true);
+ if (zoneIndex == 0) {
+ Log.i("TimeTest", time.format("%B %d, %Y"));
+ }
+ int julianDay = Time.getJulianDay(millis, time.gmtoff);
+
+ time.setJulianDay(julianDay);
+
+ // Some places change daylight saving time at 12am and so there
+ // is no 12am on some days in some timezones. In those cases,
+ // the time is set to 1am.
+ // Examples: Africa/Cairo on April 25, 2008
+ // America/Sao_Paulo on October 12, 2008
+ // Atlantic/Azores on March 30, 2008
+ assertTrue(time.hour == 0 || time.hour == 1);
+ assertEquals(0, time.minute);
+ assertEquals(0, time.second);
+
+ millis = time.toMillis(false);
+ int day = Time.getJulianDay(millis, time.gmtoff);
+ if (day != julianDay) {
+ Log.i("TimeTest", "Error: gmtoff " + (time.gmtoff / 3600.0)
+ + " day " + julianDay
+ + " millis " + millis
+ + " " + time.format("%B %d, %Y") + " " + time.timezone);
+ }
+ assertEquals(day, julianDay);
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java
new file mode 100644
index 0000000..6ba64fd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TimeUtilsTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import junit.framework.TestCase;
+
+import android.util.TimeUtils;
+
+import java.util.Calendar;
+import java.util.TimeZone;
+
+/**
+ * TimeUtilsTest tests the time zone guesser.
+ */
+public class TimeUtilsTest extends TestCase {
+ public void testMainstream() throws Exception {
+ String[] mainstream = new String[] {
+ "America/New_York", // Eastern
+ "America/Chicago", // Central
+ "America/Denver", // Mountain
+ "America/Los_Angeles", // Pacific
+ "America/Anchorage", // Alaska
+ "Pacific/Honolulu", // Hawaii, no DST
+ };
+
+ for (String name : mainstream) {
+ TimeZone tz = TimeZone.getTimeZone(name);
+ Calendar c = Calendar.getInstance(tz);
+ TimeZone guess;
+
+ c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
+ guess = guess(c, "us");
+ assertEquals(name, guess.getID());
+
+ c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
+ guess = guess(c, "us");
+ assertEquals(name, guess.getID());
+ }
+ }
+
+ public void testWeird() throws Exception {
+ String[] weird = new String[] {
+ "America/Phoenix", // Mountain, no DST
+ "America/Adak", // Same as Hawaii, but with DST
+ };
+
+ for (String name : weird) {
+ TimeZone tz = TimeZone.getTimeZone(name);
+ Calendar c = Calendar.getInstance(tz);
+ TimeZone guess;
+
+ c.set(2008, Calendar.OCTOBER, 20, 12, 00, 00);
+ guess = guess(c, "us");
+ assertEquals(name, guess.getID());
+ }
+ }
+
+ public void testOld() throws Exception {
+ String[] old = new String[] {
+ "America/Indiana/Indianapolis", // Eastern, formerly no DST
+ };
+
+ for (String name : old) {
+ TimeZone tz = TimeZone.getTimeZone(name);
+ Calendar c = Calendar.getInstance(tz);
+ TimeZone guess;
+
+ c.set(2005, Calendar.OCTOBER, 20, 12, 00, 00);
+ guess = guess(c, "us");
+ assertEquals(name, guess.getID());
+ }
+ }
+
+ public void testWorld() throws Exception {
+ String[] world = new String[] {
+ "ad", "Europe/Andorra",
+ "ae", "Asia/Dubai",
+ "af", "Asia/Kabul",
+ "ag", "America/Antigua",
+ "ai", "America/Anguilla",
+ "al", "Europe/Tirane",
+ "am", "Asia/Yerevan",
+ "an", "America/Curacao",
+ "ao", "Africa/Luanda",
+ "aq", "Antarctica/McMurdo",
+ "aq", "Antarctica/DumontDUrville",
+ "aq", "Antarctica/Casey",
+ "aq", "Antarctica/Davis",
+ "aq", "Antarctica/Mawson",
+ "aq", "Antarctica/Syowa",
+ "aq", "Antarctica/Rothera",
+ "aq", "Antarctica/Palmer",
+ "ar", "America/Argentina/Buenos_Aires",
+ "as", "Pacific/Pago_Pago",
+ "at", "Europe/Vienna",
+ "au", "Australia/Sydney",
+ "au", "Australia/Adelaide",
+ "au", "Australia/Perth",
+ "au", "Australia/Eucla",
+ "aw", "America/Aruba",
+ "ax", "Europe/Mariehamn",
+ "az", "Asia/Baku",
+ "ba", "Europe/Sarajevo",
+ "bb", "America/Barbados",
+ "bd", "Asia/Dhaka",
+ "be", "Europe/Brussels",
+ "bf", "Africa/Ouagadougou",
+ "bg", "Europe/Sofia",
+ "bh", "Asia/Bahrain",
+ "bi", "Africa/Bujumbura",
+ "bj", "Africa/Porto-Novo",
+ "bm", "Atlantic/Bermuda",
+ "bn", "Asia/Brunei",
+ "bo", "America/La_Paz",
+ "br", "America/Noronha",
+ "br", "America/Sao_Paulo",
+ "br", "America/Manaus",
+ "bs", "America/Nassau",
+ "bt", "Asia/Thimphu",
+ "bw", "Africa/Gaborone",
+ "by", "Europe/Minsk",
+ "bz", "America/Belize",
+ "ca", "America/St_Johns",
+ "ca", "America/Halifax",
+ "ca", "America/Toronto",
+ "ca", "America/Winnipeg",
+ "ca", "America/Edmonton",
+ "ca", "America/Vancouver",
+ "cc", "Indian/Cocos",
+ "cd", "Africa/Lubumbashi",
+ "cd", "Africa/Kinshasa",
+ "cf", "Africa/Bangui",
+ "cg", "Africa/Brazzaville",
+ "ch", "Europe/Zurich",
+ "ci", "Africa/Abidjan",
+ "ck", "Pacific/Rarotonga",
+ "cl", "America/Santiago",
+ "cl", "Pacific/Easter",
+ "cm", "Africa/Douala",
+ "cn", "Asia/Shanghai",
+ "co", "America/Bogota",
+ "cr", "America/Costa_Rica",
+ "cu", "America/Havana",
+ "cv", "Atlantic/Cape_Verde",
+ "cx", "Indian/Christmas",
+ "cy", "Asia/Nicosia",
+ "cz", "Europe/Prague",
+ "de", "Europe/Berlin",
+ "dj", "Africa/Djibouti",
+ "dk", "Europe/Copenhagen",
+ "dm", "America/Dominica",
+ "do", "America/Santo_Domingo",
+ "dz", "Africa/Algiers",
+ "ec", "America/Guayaquil",
+ "ec", "Pacific/Galapagos",
+ "ee", "Europe/Tallinn",
+ "eg", "Africa/Cairo",
+ "eh", "Africa/El_Aaiun",
+ "er", "Africa/Asmara",
+ "es", "Europe/Madrid",
+ "es", "Atlantic/Canary",
+ "et", "Africa/Addis_Ababa",
+ "fi", "Europe/Helsinki",
+ "fj", "Pacific/Fiji",
+ "fk", "Atlantic/Stanley",
+ "fm", "Pacific/Ponape",
+ "fm", "Pacific/Truk",
+ "fo", "Atlantic/Faroe",
+ "fr", "Europe/Paris",
+ "ga", "Africa/Libreville",
+ "gb", "Europe/London",
+ "gd", "America/Grenada",
+ "ge", "Asia/Tbilisi",
+ "gf", "America/Cayenne",
+ "gg", "Europe/Guernsey",
+ "gh", "Africa/Accra",
+ "gi", "Europe/Gibraltar",
+ "gl", "America/Danmarkshavn",
+ "gl", "America/Scoresbysund",
+ "gl", "America/Godthab",
+ "gl", "America/Thule",
+ "gm", "Africa/Banjul",
+ "gn", "Africa/Conakry",
+ "gp", "America/Guadeloupe",
+ "gq", "Africa/Malabo",
+ "gr", "Europe/Athens",
+ "gs", "Atlantic/South_Georgia",
+ "gt", "America/Guatemala",
+ "gu", "Pacific/Guam",
+ "gw", "Africa/Bissau",
+ "gy", "America/Guyana",
+ "hk", "Asia/Hong_Kong",
+ "hn", "America/Tegucigalpa",
+ "hr", "Europe/Zagreb",
+ "ht", "America/Port-au-Prince",
+ "hu", "Europe/Budapest",
+ "id", "Asia/Jayapura",
+ "id", "Asia/Makassar",
+ "id", "Asia/Jakarta",
+ "ie", "Europe/Dublin",
+ "il", "Asia/Jerusalem",
+ "im", "Europe/Isle_of_Man",
+ "in", "Asia/Calcutta",
+ "io", "Indian/Chagos",
+ "iq", "Asia/Baghdad",
+ "ir", "Asia/Tehran",
+ "is", "Atlantic/Reykjavik",
+ "it", "Europe/Rome",
+ "je", "Europe/Jersey",
+ "jm", "America/Jamaica",
+ "jo", "Asia/Amman",
+ "jp", "Asia/Tokyo",
+ "ke", "Africa/Nairobi",
+ "kg", "Asia/Bishkek",
+ "kh", "Asia/Phnom_Penh",
+ "ki", "Pacific/Kiritimati",
+ "ki", "Pacific/Enderbury",
+ "ki", "Pacific/Tarawa",
+ "km", "Indian/Comoro",
+ "kn", "America/St_Kitts",
+ "kp", "Asia/Pyongyang",
+ "kr", "Asia/Seoul",
+ "kw", "Asia/Kuwait",
+ "ky", "America/Cayman",
+ "kz", "Asia/Almaty",
+ "kz", "Asia/Aqtau",
+ "la", "Asia/Vientiane",
+ "lb", "Asia/Beirut",
+ "lc", "America/St_Lucia",
+ "li", "Europe/Vaduz",
+ "lk", "Asia/Colombo",
+ "lr", "Africa/Monrovia",
+ "ls", "Africa/Maseru",
+ "lt", "Europe/Vilnius",
+ "lu", "Europe/Luxembourg",
+ "lv", "Europe/Riga",
+ "ly", "Africa/Tripoli",
+ "ma", "Africa/Casablanca",
+ "mc", "Europe/Monaco",
+ "md", "Europe/Chisinau",
+ "me", "Europe/Podgorica",
+ "mg", "Indian/Antananarivo",
+ "mh", "Pacific/Majuro",
+ "mk", "Europe/Skopje",
+ "ml", "Africa/Bamako",
+ "mm", "Asia/Rangoon",
+ "mn", "Asia/Choibalsan",
+ "mn", "Asia/Hovd",
+ "mo", "Asia/Macau",
+ "mp", "Pacific/Saipan",
+ "mq", "America/Martinique",
+ "mr", "Africa/Nouakchott",
+ "ms", "America/Montserrat",
+ "mt", "Europe/Malta",
+ "mu", "Indian/Mauritius",
+ "mv", "Indian/Maldives",
+ "mw", "Africa/Blantyre",
+ "mx", "America/Mexico_City",
+ "mx", "America/Chihuahua",
+ "mx", "America/Tijuana",
+ "my", "Asia/Kuala_Lumpur",
+ "mz", "Africa/Maputo",
+ "na", "Africa/Windhoek",
+ "nc", "Pacific/Noumea",
+ "ne", "Africa/Niamey",
+ "nf", "Pacific/Norfolk",
+ "ng", "Africa/Lagos",
+ "ni", "America/Managua",
+ "nl", "Europe/Amsterdam",
+ "no", "Europe/Oslo",
+ "np", "Asia/Katmandu",
+ "nr", "Pacific/Nauru",
+ "nu", "Pacific/Niue",
+ "nz", "Pacific/Auckland",
+ "nz", "Pacific/Chatham",
+ "om", "Asia/Muscat",
+ "pa", "America/Panama",
+ "pe", "America/Lima",
+ "pf", "Pacific/Gambier",
+ "pf", "Pacific/Marquesas",
+ "pf", "Pacific/Tahiti",
+ "pg", "Pacific/Port_Moresby",
+ "ph", "Asia/Manila",
+ "pk", "Asia/Karachi",
+ "pl", "Europe/Warsaw",
+ "pm", "America/Miquelon",
+ "pn", "Pacific/Pitcairn",
+ "pr", "America/Puerto_Rico",
+ "ps", "Asia/Gaza",
+ "pt", "Europe/Lisbon",
+ "pt", "Atlantic/Azores",
+ "pw", "Pacific/Palau",
+ "py", "America/Asuncion",
+ "qa", "Asia/Qatar",
+ "re", "Indian/Reunion",
+ "ro", "Europe/Bucharest",
+ "rs", "Europe/Belgrade",
+ "ru", "Asia/Kamchatka",
+ "ru", "Asia/Magadan",
+ "ru", "Asia/Vladivostok",
+ "ru", "Asia/Yakutsk",
+ "ru", "Asia/Irkutsk",
+ "ru", "Asia/Krasnoyarsk",
+ "ru", "Asia/Novosibirsk",
+ "ru", "Asia/Yekaterinburg",
+ "ru", "Europe/Samara",
+ "ru", "Europe/Moscow",
+ "ru", "Europe/Kaliningrad",
+ "rw", "Africa/Kigali",
+ "sa", "Asia/Riyadh",
+ "sb", "Pacific/Guadalcanal",
+ "sc", "Indian/Mahe",
+ "sd", "Africa/Khartoum",
+ "se", "Europe/Stockholm",
+ "sg", "Asia/Singapore",
+ "sh", "Atlantic/St_Helena",
+ "si", "Europe/Ljubljana",
+ "sj", "Arctic/Longyearbyen",
+ "sk", "Europe/Bratislava",
+ "sl", "Africa/Freetown",
+ "sm", "Europe/San_Marino",
+ "sn", "Africa/Dakar",
+ "so", "Africa/Mogadishu",
+ "sr", "America/Paramaribo",
+ "st", "Africa/Sao_Tome",
+ "sv", "America/El_Salvador",
+ "sy", "Asia/Damascus",
+ "sz", "Africa/Mbabane",
+ "tc", "America/Grand_Turk",
+ "td", "Africa/Ndjamena",
+ "tf", "Indian/Kerguelen",
+ "tg", "Africa/Lome",
+ "th", "Asia/Bangkok",
+ "tj", "Asia/Dushanbe",
+ "tk", "Pacific/Fakaofo",
+ "tl", "Asia/Dili",
+ "tm", "Asia/Ashgabat",
+ "tn", "Africa/Tunis",
+ "to", "Pacific/Tongatapu",
+ "tr", "Europe/Istanbul",
+ "tt", "America/Port_of_Spain",
+ "tv", "Pacific/Funafuti",
+ "tw", "Asia/Taipei",
+ "tz", "Africa/Dar_es_Salaam",
+ "ua", "Europe/Kiev",
+ "ug", "Africa/Kampala",
+ "um", "Pacific/Wake",
+ "um", "Pacific/Johnston",
+ "um", "Pacific/Midway",
+ "us", "America/New_York",
+ "us", "America/Chicago",
+ "us", "America/Denver",
+ "us", "America/Los_Angeles",
+ "us", "America/Anchorage",
+ "us", "Pacific/Honolulu",
+ "uy", "America/Montevideo",
+ "uz", "Asia/Tashkent",
+ "va", "Europe/Vatican",
+ "vc", "America/St_Vincent",
+ "ve", "America/Caracas",
+ "vg", "America/Tortola",
+ "vi", "America/St_Thomas",
+ "vn", "Asia/Saigon",
+ "vu", "Pacific/Efate",
+ "wf", "Pacific/Wallis",
+ "ws", "Pacific/Apia",
+ "ye", "Asia/Aden",
+ "yt", "Indian/Mayotte",
+ "za", "Africa/Johannesburg",
+ "zm", "Africa/Lusaka",
+ "zw", "Africa/Harare",
+ };
+
+ for (int i = 0; i < world.length; i += 2) {
+ String country = world[i];
+ String name = world[i + 1];
+
+ TimeZone tz = TimeZone.getTimeZone(name);
+ Calendar c = Calendar.getInstance(tz);
+ TimeZone guess;
+
+ c.set(2009, Calendar.JULY, 20, 12, 00, 00);
+ guess = guess(c, country);
+ assertEquals(name, guess.getID());
+
+ c.set(2009, Calendar.JANUARY, 20, 12, 00, 00);
+ guess = guess(c, country);
+ assertEquals(name, guess.getID());
+ }
+ }
+
+ public void testWorldWeird() throws Exception {
+ String[] world = new String[] {
+ // Distinguisable from Sydney only when DST not in effect
+ "au", "Australia/Lord_Howe",
+ };
+
+ for (int i = 0; i < world.length; i += 2) {
+ String country = world[i];
+ String name = world[i + 1];
+
+ TimeZone tz = TimeZone.getTimeZone(name);
+ Calendar c = Calendar.getInstance(tz);
+ TimeZone guess;
+
+ c.set(2009, Calendar.JULY, 20, 12, 00, 00);
+ guess = guess(c, country);
+ assertEquals(name, guess.getID());
+ }
+ }
+
+ private static TimeZone guess(Calendar c, String country) {
+ return TimeUtils.getTimeZone(c.get(c.ZONE_OFFSET) + c.get(c.DST_OFFSET),
+ c.get(c.DST_OFFSET) != 0,
+ c.getTimeInMillis(),
+ country);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java
new file mode 100644
index 0000000..6705080
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TraceTest.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.os.Debug;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+/**
+ * This class is used to test the native tracing support. Run this test
+ * while tracing on the emulator and then run traceview to view the trace.
+ */
+public class TraceTest extends AndroidTestCase
+{
+ private static final String TAG = "TraceTest";
+ private int eMethodCalls = 0;
+ private int fMethodCalls = 0;
+ private int gMethodCalls = 0;
+
+ @SmallTest
+ public void testNativeTracingFromJava()
+ {
+ long start = System.currentTimeMillis();
+ Debug.startNativeTracing();
+ //nativeMethod();
+ int count = 0;
+ for (int ii = 0; ii < 20; ii++) {
+ count = eMethod();
+ }
+ Debug.stopNativeTracing();
+ long end = System.currentTimeMillis();
+ long elapsed = end - start;
+ Log.i(TAG, "elapsed millis: " + elapsed);
+ Log.i(TAG, "eMethod calls: " + eMethodCalls
+ + " fMethod calls: " + fMethodCalls
+ + " gMethod calls: " + gMethodCalls);
+ }
+
+ // This should not run in the automated suite.
+ @Suppress
+ public void disableTestNativeTracingFromC()
+ {
+ long start = System.currentTimeMillis();
+ nativeMethodAndStartTracing();
+ long end = System.currentTimeMillis();
+ long elapsed = end - start;
+ Log.i(TAG, "elapsed millis: " + elapsed);
+ }
+
+ native void nativeMethod();
+ native void nativeMethodAndStartTracing();
+
+ @LargeTest
+ public void testMethodTracing()
+ {
+ long start = System.currentTimeMillis();
+ Debug.startMethodTracing("traceTest");
+ topMethod();
+ Debug.stopMethodTracing();
+ long end = System.currentTimeMillis();
+ long elapsed = end - start;
+ Log.i(TAG, "elapsed millis: " + elapsed);
+ }
+
+ private void topMethod() {
+ aMethod();
+ bMethod();
+ cMethod();
+ dMethod(5);
+
+ Thread t1 = new aThread();
+ t1.start();
+ Thread t2 = new aThread();
+ t2.start();
+ Thread t3 = new aThread();
+ t3.start();
+ try {
+ t1.join();
+ t2.join();
+ t3.join();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ private class aThread extends Thread {
+ @Override
+ public void run() {
+ aMethod();
+ bMethod();
+ cMethod();
+ }
+ }
+
+ /** Calls other methods to make some interesting trace data.
+ *
+ * @return a meaningless value
+ */
+ private int aMethod() {
+ int count = 0;
+ for (int ii = 0; ii < 6; ii++) {
+ count += bMethod();
+ }
+ for (int ii = 0; ii < 5; ii++) {
+ count += cMethod();
+ }
+ for (int ii = 0; ii < 4; ii++) {
+ count += dMethod(ii);
+ }
+ return count;
+ }
+
+ /** Calls another method to make some interesting trace data.
+ *
+ * @return a meaningless value
+ */
+ private int bMethod() {
+ int count = 0;
+ for (int ii = 0; ii < 4; ii++) {
+ count += cMethod();
+ }
+ return count;
+ }
+
+ /** Executes a simple loop to make some interesting trace data.
+ *
+ * @return a meaningless value
+ */
+ private int cMethod() {
+ int count = 0;
+ for (int ii = 0; ii < 1000; ii++) {
+ count += ii;
+ }
+ return count;
+ }
+
+ /** Calls itself recursively to make some interesting trace data.
+ *
+ * @return a meaningless value
+ */
+ private int dMethod(int level) {
+ int count = 0;
+ if (level > 0) {
+ count = dMethod(level - 1);
+ }
+ for (int ii = 0; ii < 100; ii++) {
+ count += ii;
+ }
+ if (level == 0) {
+ return count;
+ }
+ return dMethod(level - 1);
+ }
+
+ public int eMethod() {
+ eMethodCalls += 1;
+ int count = fMethod();
+ count += gMethod(3);
+ return count;
+ }
+
+ public int fMethod() {
+ fMethodCalls += 1;
+ int count = 0;
+ for (int ii = 0; ii < 10; ii++) {
+ count += ii;
+ }
+ return count;
+ }
+
+ public int gMethod(int level) {
+ gMethodCalls += 1;
+ int count = level;
+ if (level > 1)
+ count += gMethod(level - 1);
+ return count;
+ }
+
+ /*
+ * This causes the native shared library to be loaded when the
+ * class is first used. The library is only loaded once, even if
+ * multiple classes include this line.
+ *
+ * The library must be in java.library.path, which is derived from
+ * LD_LIBRARY_PATH. The actual library name searched for will be
+ * "libtrace_test.so" under Linux, but may be different on other
+ * platforms.
+ */
+ static {
+ Log.i(TAG, "Loading trace_test native library...");
+ try {
+ System.loadLibrary("trace_test");
+ Log.i(TAG, "Successfully loaded trace_test native library");
+ }
+ catch (UnsatisfiedLinkError ule) {
+ Log.w(TAG, "Could not load trace_test native library");
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java
new file mode 100644
index 0000000..d77a819
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TreeMapTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.Collection;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Implements basic performance test functionality for java.util.TreeMap
+ */
+
+public class TreeMapTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ public static TreeMap<String, Integer> sMap;
+ public static String[] sKeys;
+
+ @Override
+ @SuppressWarnings("unchecked")
+ protected void setUp() throws Exception {
+ super.setUp();
+ sMap = new TreeMap();
+ sKeys = new String[ITERATIONS];
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sKeys[i] = Integer.toString(i, 16);
+ sMap.put(sKeys[i], i);
+ }
+ }
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testTreeMapPut() {
+ TreeMap map = new TreeMap();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ map.put(i, i);
+ }
+ }
+
+ public void testTreeMapGet() {
+ int value;
+ TreeMap<String, Integer> map = sMap;
+ String[] keys = sKeys;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ value = map.get(keys[i]);
+ }
+ }
+
+ public void testTreeMapFirstKey() {
+ String key;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ key = map.firstKey();
+ }
+ }
+
+ public void testTreeMapKeySet() {
+ Set keyset;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ keyset = map.keySet();
+ }
+ }
+
+ public void testTreeMapEntrySet() {
+ Set keyset;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ keyset = map.entrySet();
+ }
+ }
+
+ public void testTreeMapValues() {
+ Collection collection;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ collection = map.values();
+ }
+ }
+
+ public void testTreeMapSize() {
+ int len;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ len = map.size();
+ }
+ }
+
+ public void testTreeMapContainsKey() {
+ boolean flag;
+ String key = sKeys[525];
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ flag = map.containsKey(key);
+ }
+ }
+
+ public void testTreeMapContainsValue() {
+ boolean flag;
+ TreeMap<String, Integer> map = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ flag = map.containsValue(i);
+ }
+ }
+
+ public void testTreeMapHeadMap() {
+ SortedMap map;
+ String str = sKeys[100];
+ TreeMap<String, Integer> tMap = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ map = tMap.headMap(str);
+ }
+ }
+
+ public void testTreeMapSubMap() {
+ String str1 = sKeys[400];
+ String str2 = sKeys[500];
+ SortedMap map;
+ TreeMap<String, Integer> tMap = sMap;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ map = tMap.subMap(str1, str2);
+ }
+ }
+
+ public void testTreeMapTailMap() {
+ String str = sKeys[900];
+ TreeMap<String, Integer> tMap = sMap;
+ SortedMap map;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ map = tMap.tailMap(str);
+ }
+ }
+
+ @SuppressWarnings("unchecked")
+ public void testTreeMapRemove() {
+ TreeMap<String, Integer> tMap = new TreeMap(sMap);
+ String[] keys = sKeys;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ tMap.remove(keys[i]);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java
new file mode 100644
index 0000000..60dfe9a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/TreeSetTest.java
@@ -0,0 +1,349 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.TreeSet;
+import java.util.SortedSet;
+import java.util.Iterator;
+import java.util.Comparator;
+
+/**
+ * Implements basic performance test functionality for java.util.TreeSet
+ */
+
+public class TreeSetTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ public static TreeSet<Integer> sSet;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ sSet = new TreeSet<Integer>();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ sSet.add(i);
+ }
+ }
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method Add(Object arg 0)
+ *
+ */
+
+ @SuppressWarnings("unchecked")
+ public void testTreeSetAdd() {
+ TreeSet<Integer> set = new TreeSet();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ set.add(i);
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - first()
+ *
+ */
+
+ public void testTreeSetFirst() {
+ int value;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ value = set.first();
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - last()
+ *
+ */
+
+ public void testTreeSetLast() {
+ int value;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ value = set.last();
+ }
+ }
+
+ /**
+ *
+ * Tests performance of the java.util.TreeSet method- contains(Object arg0)
+ *
+ */
+
+ public void testTreeSetContains() {
+ Integer index = new Integer(500);
+ boolean flag;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ flag = set.contains(index);
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - size()
+ *
+ */
+
+ public void testTreeSetSize() {
+ int value;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ value = set.size();
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - iterator()
+ *
+ */
+
+ public void testTreeSetIterator() {
+ Iterator iterator;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ iterator = set.iterator();
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - comparator()
+ *
+ */
+
+ public void testTreeSetComparator() {
+ Comparator comparator;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ comparator = set.comparator();
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - clone()
+ *
+ */
+
+ public void testTreeSetClone() {
+ Object obj;
+ TreeSet<Integer> set = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ obj = set.clone();
+ }
+ }
+
+ /**
+ *
+ * Tests performance of the java.util.TreeSet method - remove(Object arg0)
+ *
+ */
+
+ @SuppressWarnings("unchecked")
+ public void testTreeSetRemove() {
+ TreeSet<Integer> set = new TreeSet(sSet);
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ set.remove(i);
+ }
+ }
+
+ /**
+ *
+ * Tests performance of the java.util.TreeSet method- headSet(Integer arg0)
+ *
+ */
+
+ public void testTreeSetHeadSet() {
+ Integer value = new Integer(100);
+ SortedSet set;
+ TreeSet<Integer> tSet = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ set = tSet.headSet(value);
+ }
+ }
+
+ /**
+ *
+ * Tests performance of subSet(Integer arg0, Integer arg1) - TreeSet
+ *
+ */
+
+ public void testTreeSetSubSet() {
+ Integer value = new Integer(400);
+ Integer nInt = new Integer(500);
+ SortedSet set;
+ TreeSet<Integer> tSet = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+ set = tSet.subSet(value, nInt);
+
+ }
+
+ }
+
+ /**
+ *
+ * Tests performance of tailSet(Integer arg0) - TreeSet
+ *
+ */
+
+ public void testTreeSetTailSet() {
+ Integer value = new Integer(900);
+ SortedSet set;
+ TreeSet<Integer> tSet = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ set = tSet.tailSet(value);
+ }
+ }
+
+ /**
+ *
+ * Tests performance for the java.util.TreeSet method - isEmpty()
+ *
+ */
+
+ public void testTreeSetIsEmpty() {
+ boolean flag;
+ TreeSet<Integer> tSet = sSet;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ flag = tSet.isEmpty();
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java
new file mode 100644
index 0000000..ce3ea75
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UriMatcherTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.UriMatcher;
+import android.net.Uri;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+public class UriMatcherTest extends TestCase
+{
+ static final int ROOT = 0;
+ static final int PEOPLE = 1;
+ static final int PEOPLE_ID = 2;
+ static final int PEOPLE_PHONES = 3;
+ static final int PEOPLE_PHONES_ID = 4;
+ static final int PEOPLE_ADDRESSES = 5;
+ static final int PEOPLE_ADDRESSES_ID = 6;
+ static final int PEOPLE_CONTACTMETH = 7;
+ static final int PEOPLE_CONTACTMETH_ID = 8;
+ static final int CALLS = 9;
+ static final int CALLS_ID = 10;
+ static final int CALLERID = 11;
+ static final int CALLERID_TEXT = 12;
+ static final int FILTERRECENT = 13;
+
+ @SmallTest
+ public void testContentUris() {
+ check("content://asdf", UriMatcher.NO_MATCH);
+ check("content://people", PEOPLE);
+ check("content://people/1", PEOPLE_ID);
+ check("content://people/asdf", UriMatcher.NO_MATCH);
+ check("content://people/2/phones", PEOPLE_PHONES);
+ check("content://people/2/phones/3", PEOPLE_PHONES_ID);
+ check("content://people/2/phones/asdf", UriMatcher.NO_MATCH);
+ check("content://people/2/addresses", PEOPLE_ADDRESSES);
+ check("content://people/2/addresses/3", PEOPLE_ADDRESSES_ID);
+ check("content://people/2/addresses/asdf", UriMatcher.NO_MATCH);
+ check("content://people/2/contact-methods", PEOPLE_CONTACTMETH);
+ check("content://people/2/contact-methods/3", PEOPLE_CONTACTMETH_ID);
+ check("content://people/2/contact-methods/asdf", UriMatcher.NO_MATCH);
+ check("content://calls", CALLS);
+ check("content://calls/1", CALLS_ID);
+ check("content://calls/asdf", UriMatcher.NO_MATCH);
+ check("content://caller-id", CALLERID);
+ check("content://caller-id/asdf", CALLERID_TEXT);
+ check("content://caller-id/1", CALLERID_TEXT);
+ check("content://filter-recent", FILTERRECENT);
+ }
+
+ private static final UriMatcher mURLMatcher = new UriMatcher(ROOT);
+
+ static
+ {
+ mURLMatcher.addURI("people", null, PEOPLE);
+ mURLMatcher.addURI("people", "#", PEOPLE_ID);
+ mURLMatcher.addURI("people", "#/phones", PEOPLE_PHONES);
+ mURLMatcher.addURI("people", "#/phones/blah", PEOPLE_PHONES_ID);
+ mURLMatcher.addURI("people", "#/phones/#", PEOPLE_PHONES_ID);
+ mURLMatcher.addURI("people", "#/addresses", PEOPLE_ADDRESSES);
+ mURLMatcher.addURI("people", "#/addresses/#", PEOPLE_ADDRESSES_ID);
+ mURLMatcher.addURI("people", "#/contact-methods", PEOPLE_CONTACTMETH);
+ mURLMatcher.addURI("people", "#/contact-methods/#", PEOPLE_CONTACTMETH_ID);
+ mURLMatcher.addURI("calls", null, CALLS);
+ mURLMatcher.addURI("calls", "#", CALLS_ID);
+ mURLMatcher.addURI("caller-id", null, CALLERID);
+ mURLMatcher.addURI("caller-id", "*", CALLERID_TEXT);
+ mURLMatcher.addURI("filter-recent", null, FILTERRECENT);
+ }
+
+ void check(String uri, int expected)
+ {
+ int result = mURLMatcher.match(Uri.parse(uri));
+ if (result != expected) {
+ String msg = "failed on " + uri;
+ msg += " expected " + expected + " got " + result;
+ throw new RuntimeException(msg);
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UriTest.java b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
new file mode 100644
index 0000000..130beeb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UriTest.java
@@ -0,0 +1,502 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.net.Uri;
+import android.content.ContentUris;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.util.Arrays;
+
+public class UriTest extends TestCase {
+
+ @SmallTest
+ public void testToStringWithPathOnly() {
+ Uri.Builder builder = new Uri.Builder();
+
+ // Not a valid path, but this came from a user's test case.
+ builder.path("//foo");
+ Uri uri = builder.build();
+ assertEquals("//foo", uri.toString());
+ }
+
+ @SmallTest
+ public void testParcelling() {
+ parcelAndUnparcel(Uri.parse("foo:bob%20lee"));
+ parcelAndUnparcel(Uri.fromParts("foo", "bob lee", "fragment"));
+ parcelAndUnparcel(new Uri.Builder()
+ .scheme("http")
+ .authority("crazybob.org")
+ .path("/rss/")
+ .encodedQuery("a=b")
+ .fragment("foo")
+ .build());
+ }
+
+ private void parcelAndUnparcel(Uri u) {
+ Parcel p = Parcel.obtain();
+ Uri.writeToParcel(p, u);
+ p.setDataPosition(0);
+ assertEquals(u, Uri.CREATOR.createFromParcel(p));
+
+ p.setDataPosition(0);
+ u = u.buildUpon().build();
+ Uri.writeToParcel(p, u);
+ p.setDataPosition(0);
+ assertEquals(u, Uri.CREATOR.createFromParcel(p));
+ }
+
+ @SmallTest
+ public void testBuildUponOpaqueStringUri() {
+ Uri u = Uri.parse("bob:lee").buildUpon().scheme("robert").build();
+ assertEquals("robert", u.getScheme());
+ assertEquals("lee", u.getEncodedSchemeSpecificPart());
+ assertEquals("lee", u.getSchemeSpecificPart());
+ assertNull(u.getQuery());
+ assertNull(u.getPath());
+ assertNull(u.getAuthority());
+ assertNull(u.getHost());
+ }
+
+ @SmallTest
+ public void testStringUri() {
+ assertEquals("bob lee",
+ Uri.parse("foo:bob%20lee").getSchemeSpecificPart());
+ assertEquals("bob%20lee",
+ Uri.parse("foo:bob%20lee").getEncodedSchemeSpecificPart());
+ assertEquals("/bob%20lee",
+ Uri.parse("foo:/bob%20lee").getEncodedPath());
+ assertNull(Uri.parse("foo:bob%20lee").getPath());
+ assertEquals("bob%20lee",
+ Uri.parse("foo:?bob%20lee").getEncodedQuery());
+ assertNull(Uri.parse("foo:bar#?bob%20lee").getQuery());
+ assertEquals("bob%20lee",
+ Uri.parse("foo:#bob%20lee").getEncodedFragment());
+ }
+
+ @SmallTest
+ public void testStringUriIsHierarchical() {
+ assertTrue(Uri.parse("bob").isHierarchical());
+ assertFalse(Uri.parse("bob:").isHierarchical());
+ }
+
+ @SmallTest
+ public void testNullUriString() {
+ try {
+ Uri.parse(null);
+ fail();
+ } catch (NullPointerException e) {}
+ }
+
+ @SmallTest
+ public void testNullFile() {
+ try {
+ Uri.fromFile(null);
+ fail();
+ } catch (NullPointerException e) {}
+ }
+
+ @SmallTest
+ public void testCompareTo() {
+ Uri a = Uri.parse("foo:a");
+ Uri b = Uri.parse("foo:b");
+ Uri b2 = Uri.parse("foo:b");
+
+ assertTrue(a.compareTo(b) < 0);
+ assertTrue(b.compareTo(a) > 0);
+ assertEquals(0, b.compareTo(b2));
+ }
+
+ @SmallTest
+ public void testEqualsAndHashCode() {
+
+ Uri a = Uri.parse("http://crazybob.org/test/?foo=bar#tee");
+
+ Uri b = new Uri.Builder()
+ .scheme("http")
+ .authority("crazybob.org")
+ .path("/test/")
+ .encodedQuery("foo=bar")
+ .fragment("tee")
+ .build();
+
+ // Try alternate builder methods.
+ Uri c = new Uri.Builder()
+ .scheme("http")
+ .encodedAuthority("crazybob.org")
+ .encodedPath("/test/")
+ .encodedQuery("foo=bar")
+ .encodedFragment("tee")
+ .build();
+
+ assertFalse(Uri.EMPTY.equals(null));
+
+ assertEquals(a, b);
+ assertEquals(b, c);
+ assertEquals(c, a);
+
+ assertEquals(a.hashCode(), b.hashCode());
+ assertEquals(b.hashCode(), c.hashCode());
+ }
+
+ @SmallTest
+ public void testAuthorityParsing() {
+ Uri uri = Uri.parse("http://localhost:42");
+ assertEquals("localhost", uri.getHost());
+ assertEquals(42, uri.getPort());
+
+ uri = Uri.parse("http://bob@localhost:42");
+ assertEquals("bob", uri.getUserInfo());
+ assertEquals("localhost", uri.getHost());
+ assertEquals(42, uri.getPort());
+
+ uri = Uri.parse("http://bob%20lee@localhost:42");
+ assertEquals("bob lee", uri.getUserInfo());
+ assertEquals("bob%20lee", uri.getEncodedUserInfo());
+
+ uri = Uri.parse("http://localhost");
+ assertEquals("localhost", uri.getHost());
+ assertEquals(-1, uri.getPort());
+ }
+
+ @SmallTest
+ public void testBuildUponOpaqueUri() {
+ Uri a = Uri.fromParts("foo", "bar", "tee");
+ Uri b = a.buildUpon().fragment("new").build();
+ assertEquals("new", b.getFragment());
+ assertEquals("bar", b.getSchemeSpecificPart());
+ assertEquals("foo", b.getScheme());
+ }
+
+ @SmallTest
+ public void testBuildUponEncodedOpaqueUri() {
+ Uri a = new Uri.Builder()
+ .scheme("foo")
+ .encodedOpaquePart("bar")
+ .fragment("tee")
+ .build();
+ Uri b = a.buildUpon().fragment("new").build();
+ assertEquals("new", b.getFragment());
+ assertEquals("bar", b.getSchemeSpecificPart());
+ assertEquals("foo", b.getScheme());
+ }
+
+ @SmallTest
+ public void testPathSegmentDecoding() {
+ Uri uri = Uri.parse("foo://bar/a%20a/b%20b");
+ assertEquals("a a", uri.getPathSegments().get(0));
+ assertEquals("b b", uri.getPathSegments().get(1));
+ }
+
+ @SmallTest
+ public void testSms() {
+ Uri base = Uri.parse("content://sms");
+ Uri appended = base.buildUpon()
+ .appendEncodedPath("conversations/addr=555-1212")
+ .build();
+ assertEquals("content://sms/conversations/addr=555-1212",
+ appended.toString());
+ assertEquals(2, appended.getPathSegments().size());
+ assertEquals("conversations", appended.getPathSegments().get(0));
+ assertEquals("addr=555-1212", appended.getPathSegments().get(1));
+ }
+
+ @SmallTest
+ public void testEncodeWithAllowedChars() {
+ String encoded = Uri.encode("Bob:/", "/");
+ assertEquals(-1, encoded.indexOf(':'));
+ assertTrue(encoded.indexOf('/') > -1);
+ }
+
+ @SmallTest
+ public void testEncodeDecode() {
+ code(null);
+ code("");
+ code("Bob");
+ code(":Bob");
+ code("::Bob");
+ code("Bob::Lee");
+ code("Bob:Lee");
+ code("Bob::");
+ code("Bob:");
+ code("::Bob::");
+ }
+
+ private void code(String s) {
+ assertEquals(s, Uri.decode(Uri.encode(s, null)));
+ }
+
+ @SmallTest
+ public void testFile() {
+ File f = new File("/tmp/bob");
+
+ Uri uri = Uri.fromFile(f);
+
+ assertEquals("file:///tmp/bob", uri.toString());
+ }
+
+ @SmallTest
+ public void testQueryParameters() {
+ Uri uri = Uri.parse("content://user");
+
+ assertEquals(null, uri.getQueryParameter("a"));
+
+ uri = uri.buildUpon().appendQueryParameter("a", "b").build();
+
+ assertEquals("b", uri.getQueryParameter("a"));
+
+ uri = uri.buildUpon().appendQueryParameter("a", "b2").build();
+
+ assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
+
+ uri = uri.buildUpon().appendQueryParameter("c", "d").build();
+
+ assertEquals(Arrays.asList("b", "b2"), uri.getQueryParameters("a"));
+ assertEquals("d", uri.getQueryParameter("c"));
+ }
+
+ @SmallTest
+ public void testSchemeOnly() {
+ Uri uri = Uri.parse("empty:");
+ assertEquals("empty", uri.getScheme());
+ assertTrue(uri.isAbsolute());
+ assertNull(uri.getPath());
+ }
+
+ @SmallTest
+ public void testEmptyPath() {
+ Uri uri = Uri.parse("content://user");
+ assertEquals(0, uri.getPathSegments().size());
+ }
+
+ @SmallTest
+ public void testPathOperations() {
+ Uri uri = Uri.parse("content://user/a/b");
+
+ assertEquals(2, uri.getPathSegments().size());
+ assertEquals("b", uri.getLastPathSegment());
+
+ Uri first = uri;
+ uri = uri.buildUpon().appendPath("c").build();
+
+ assertEquals(3, uri.getPathSegments().size());
+ assertEquals("c", uri.getLastPathSegment());
+ assertEquals("content://user/a/b/c", uri.toString());
+
+ uri = ContentUris.withAppendedId(uri, 100);
+
+ assertEquals(4, uri.getPathSegments().size());
+ assertEquals("100", uri.getLastPathSegment());
+ assertEquals(100, ContentUris.parseId(uri));
+ assertEquals("content://user/a/b/c/100", uri.toString());
+
+ // Make sure the original URI is still intact.
+ assertEquals(2, first.getPathSegments().size());
+ assertEquals("b", first.getLastPathSegment());
+
+ try {
+ first.getPathSegments().get(2);
+ fail();
+ } catch (IndexOutOfBoundsException e) {}
+
+ assertEquals(null, Uri.EMPTY.getLastPathSegment());
+
+ Uri withC = Uri.parse("foo:/a/b/").buildUpon().appendPath("c").build();
+ assertEquals("/a/b/c", withC.getPath());
+ }
+
+ @SmallTest
+ public void testOpaqueUri() {
+ Uri uri = Uri.parse("mailto:nobody");
+ testOpaqueUri(uri);
+
+ uri = uri.buildUpon().build();
+ testOpaqueUri(uri);
+
+ uri = Uri.fromParts("mailto", "nobody", null);
+ testOpaqueUri(uri);
+
+ uri = uri.buildUpon().build();
+ testOpaqueUri(uri);
+
+ uri = new Uri.Builder()
+ .scheme("mailto")
+ .opaquePart("nobody")
+ .build();
+ testOpaqueUri(uri);
+
+ uri = uri.buildUpon().build();
+ testOpaqueUri(uri);
+ }
+
+ private void testOpaqueUri(Uri uri) {
+ assertEquals("mailto", uri.getScheme());
+ assertEquals("nobody", uri.getSchemeSpecificPart());
+ assertEquals("nobody", uri.getEncodedSchemeSpecificPart());
+
+ assertNull(uri.getFragment());
+ assertTrue(uri.isAbsolute());
+ assertTrue(uri.isOpaque());
+ assertFalse(uri.isRelative());
+ assertFalse(uri.isHierarchical());
+
+ assertNull(uri.getAuthority());
+ assertNull(uri.getEncodedAuthority());
+ assertNull(uri.getPath());
+ assertNull(uri.getEncodedPath());
+ assertNull(uri.getUserInfo());
+ assertNull(uri.getEncodedUserInfo());
+ assertNull(uri.getQuery());
+ assertNull(uri.getEncodedQuery());
+ assertNull(uri.getHost());
+ assertEquals(-1, uri.getPort());
+
+ assertTrue(uri.getPathSegments().isEmpty());
+ assertNull(uri.getLastPathSegment());
+
+ assertEquals("mailto:nobody", uri.toString());
+
+ Uri withFragment = uri.buildUpon().fragment("top").build();
+ assertEquals("mailto:nobody#top", withFragment.toString());
+ }
+
+ @SmallTest
+ public void testHierarchicalUris() {
+ testHierarchical("http", "google.com", "/p1/p2", "query", "fragment");
+ testHierarchical("file", null, "/p1/p2", null, null);
+ testHierarchical("content", "contact", "/p1/p2", null, null);
+ testHierarchical("http", "google.com", "/p1/p2", null, "fragment");
+ testHierarchical("http", "google.com", "", null, "fragment");
+ testHierarchical("http", "google.com", "", "query", "fragment");
+ testHierarchical("http", "google.com", "", "query", null);
+ testHierarchical("http", null, "/", "query", null);
+ }
+
+ private static void testHierarchical(String scheme, String authority,
+ String path, String query, String fragment) {
+ StringBuilder sb = new StringBuilder();
+
+ if (authority != null) {
+ sb.append("//").append(authority);
+ }
+ if (path != null) {
+ sb.append(path);
+ }
+ if (query != null) {
+ sb.append('?').append(query);
+ }
+
+ String ssp = sb.toString();
+
+ if (scheme != null) {
+ sb.insert(0, scheme + ":");
+ }
+ if (fragment != null) {
+ sb.append('#').append(fragment);
+ }
+
+ String uriString = sb.toString();
+
+ Uri uri = Uri.parse(uriString);
+
+ // Run these twice to test caching.
+ compareHierarchical(
+ uriString, ssp, uri, scheme, authority, path, query, fragment);
+ compareHierarchical(
+ uriString, ssp, uri, scheme, authority, path, query, fragment);
+
+ // Test rebuilt version.
+ uri = uri.buildUpon().build();
+
+ // Run these twice to test caching.
+ compareHierarchical(
+ uriString, ssp, uri, scheme, authority, path, query, fragment);
+ compareHierarchical(
+ uriString, ssp, uri, scheme, authority, path, query, fragment);
+
+ // The decoded and encoded versions of the inputs are all the same.
+ // We'll test the actual encoding decoding separately.
+
+ // Test building with encoded versions.
+ Uri built = new Uri.Builder()
+ .scheme(scheme)
+ .encodedAuthority(authority)
+ .encodedPath(path)
+ .encodedQuery(query)
+ .encodedFragment(fragment)
+ .build();
+
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+
+ // Test building with decoded versions.
+ built = new Uri.Builder()
+ .scheme(scheme)
+ .authority(authority)
+ .path(path)
+ .query(query)
+ .fragment(fragment)
+ .build();
+
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+
+ // Rebuild.
+ built = built.buildUpon().build();
+
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+ compareHierarchical(
+ uriString, ssp, built, scheme, authority, path, query, fragment);
+ }
+
+ private static void compareHierarchical(String uriString, String ssp,
+ Uri uri,
+ String scheme, String authority, String path, String query,
+ String fragment) {
+ assertEquals(scheme, uri.getScheme());
+ assertEquals(authority, uri.getAuthority());
+ assertEquals(authority, uri.getEncodedAuthority());
+ assertEquals(path, uri.getPath());
+ assertEquals(path, uri.getEncodedPath());
+ assertEquals(query, uri.getQuery());
+ assertEquals(query, uri.getEncodedQuery());
+ assertEquals(fragment, uri.getFragment());
+ assertEquals(fragment, uri.getEncodedFragment());
+ assertEquals(ssp, uri.getSchemeSpecificPart());
+
+ if (scheme != null) {
+ assertTrue(uri.isAbsolute());
+ assertFalse(uri.isRelative());
+ } else {
+ assertFalse(uri.isAbsolute());
+ assertTrue(uri.isRelative());
+ }
+
+ assertFalse(uri.isOpaque());
+ assertTrue(uri.isHierarchical());
+
+ assertEquals(uriString, uri.toString());
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java
new file mode 100644
index 0000000..a7c19a7
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/UrlRulesTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.content.ContentResolver;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.android.net.UrlRules;
+import static com.google.android.net.UrlRules.Rule;
+
+/** Test loading and matching URL rewrite rules for UrlRules. */
+public class UrlRulesTest extends AndroidTestCase {
+ @SmallTest
+ public void testEmptyRules() {
+ UrlRules rules = new UrlRules(new Rule[] { });
+ assertTrue(rules.matchRule("http://foo.bar/") == Rule.DEFAULT);
+ }
+
+ @SmallTest
+ public void testInvalidRule() throws Exception {
+ try {
+ new Rule("rule", "foo bar");
+ } catch (Exception e) {
+ // Re-throw any exception except the one we're looking for.
+ if (!e.toString().contains("Illegal rule: foo bar")) throw e;
+ }
+ }
+
+ @SmallTest
+ public void testRewriteRule() throws UrlRules.RuleFormatException {
+ Rule rule = new Rule("test_rule",
+ "http://foo.bar/ rewrite http://bar.foo/");
+ assertEquals("test_rule", rule.mName);
+ assertEquals("http://foo.bar/", rule.mPrefix);
+ assertEquals("http://bar.foo/", rule.mRewrite);
+ assertFalse(rule.mBlock);
+ assertEquals("http://bar.foo/bat", rule.apply("http://foo.bar/bat"));
+ }
+
+ @SmallTest
+ public void testBlockRule() throws UrlRules.RuleFormatException {
+ Rule rule = new Rule("test_rule",
+ "http://foo.bar/ block");
+ assertEquals("test_rule", rule.mName);
+ assertEquals("http://foo.bar/", rule.mPrefix);
+ assertTrue(rule.mRewrite == null);
+ assertTrue(rule.mBlock);
+ assertTrue(rule.apply("http://foo.bar/bat") == null);
+ }
+
+ @SmallTest
+ public void testMatchRule() throws UrlRules.RuleFormatException {
+ UrlRules rules = new UrlRules(new Rule[] {
+ new Rule("12", "http://one.two/ rewrite http://buckle.my.shoe/"),
+ new Rule("34", "http://three.four/ rewrite http://close.the.door/"),
+ new Rule("56", "http://five.six/ rewrite http://pick.up.sticks/"),
+ });
+
+ assertTrue(rules.matchRule("https://one.two/") == Rule.DEFAULT);
+ assertTrue(rules.matchRule("http://one.two") == Rule.DEFAULT);
+ assertEquals("12", rules.matchRule("http://one.two/foo").mName);
+
+ String u = "http://five.six/bar";
+ assertEquals("http://pick.up.sticks/bar", rules.matchRule(u).apply(u));
+ }
+
+ @SmallTest
+ public void testAmbiguousMatch() throws UrlRules.RuleFormatException {
+ // Rule is the longest match wins.
+ UrlRules rules = new UrlRules(new Rule[] {
+ new Rule("1", "http://xyz/one rewrite http://rewrite/"),
+ new Rule("123", "http://xyz/onetwothree rewrite http://rewrite/"),
+ new Rule("12", "http://xyz/onetwo rewrite http://rewrite/"),
+ });
+
+ assertEquals("1", rules.matchRule("http://xyz/one").mName);
+ assertEquals("1", rules.matchRule("http://xyz/one...").mName);
+ assertEquals("12", rules.matchRule("http://xyz/onetwo...").mName);
+ assertEquals("123", rules.matchRule("http://xyz/onetwothree...").mName);
+
+ }
+
+ @MediumTest
+ public void testGservicesRules() {
+ // TODO: use a MockContentProvider/MockContentResolver instead.
+ ContentResolver r = getContext().getContentResolver();
+
+ // Update the digest, so the UrlRules cache is reloaded.
+ Settings.Gservices.putString(r, "digest", "testGservicesRules");
+ Settings.Gservices.putString(r, "url:blank_test", "");
+ Settings.Gservices.putString(r, "url:test",
+ "http://foo.bar/ rewrite http://bar.foo/");
+
+ UrlRules rules = UrlRules.getRules(r); // Don't crash, please. :)
+ assertTrue(rules.matchRule("http://bar.foo/") == Rule.DEFAULT);
+
+ Rule rule = rules.matchRule("http://foo.bar/bat");
+ assertEquals("test", rule.mName);
+ assertEquals("http://foo.bar/", rule.mPrefix);
+ assertEquals("http://bar.foo/", rule.mRewrite);
+ assertFalse(rule.mBlock);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java
new file mode 100644
index 0000000..22f9771
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/VectorTest.java
@@ -0,0 +1,555 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.PerformanceTestBase;
+import android.test.PerformanceTestCase;
+
+import java.util.Vector;
+import java.util.Enumeration;
+
+/**
+ * Basic Performance Tests for java.util.Vector
+ */
+
+@SuppressWarnings("unchecked")
+public class VectorTest extends PerformanceTestBase {
+ public static final int ITERATIONS = 1000;
+ private Vector<Integer> mVector;
+ private Vector<String> mStrVector;
+ private String mTestString = "Hello Android";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mVector = new Vector();
+ mStrVector = new Vector();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ assertTrue(mVector.add(i));
+ assertTrue(mStrVector.add(Integer.toString(i)));
+ }
+ }
+
+ @Override
+ public int startPerformance(PerformanceTestCase.Intermediates intermediates) {
+ intermediates.setInternalIterations(ITERATIONS);
+ return 0;
+ }
+
+ public void testVectorAdd() {
+ Vector<Integer> vector = new Vector();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ vector.add(i);
+ }
+ }
+
+ public void testVectorAdd1() {
+ Vector<Integer> vector = new Vector();
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ vector.add(0, i);
+ }
+ }
+
+ public void testVectorToArray() {
+ Object array;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ array = vector.toArray();
+ }
+ }
+
+ /**
+ *
+ */
+ public void testVectorSize() {
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ int mLen;
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ mLen = vector.size();
+ }
+ }
+
+ public void testVectorGet() {
+ int element;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ element = vector.get(i);
+ }
+
+ }
+
+ public void testVectorContains() {
+ boolean flag;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ flag = vector.contains(i);
+ }
+ }
+
+ public void testVectorToArray1() {
+ Integer[] rArray = new Integer[100];
+ Integer[] array;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ array = vector.toArray(rArray);
+ }
+ }
+
+ public void testVectorSet() {
+ Vector<Integer> vector = mVector;
+ int pos = 5, value = 0;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ vector.set(pos, value);
+ }
+ }
+
+ public void testVectorIndexOf() {
+ int index, value = 0;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ index = vector.indexOf(value);
+ }
+ }
+
+ public void testVectorLastIndexOf() {
+ int index, value = 0;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i >= 0; i--) {
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ index = vector.lastIndexOf(value);
+ }
+ }
+
+ public void testVectorRemove() {
+ int index, value = 0;
+ Vector<Integer> vector = new Vector(mVector);
+ for (int i = 10; i > 0; i--) {
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ index = vector.remove(value);
+ }
+ }
+
+ public void testVectorRemoveElement() {
+ Vector<Integer> vector = new Vector(mVector);
+ for (int i = 10; i > 0; i--) {
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ vector.removeElement(i);
+ }
+ }
+
+ public void VectorRemoveElementAt() {
+ Vector<Integer> vector = new Vector(mVector);
+ for (int i = 10; i > 0; i--) {
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ vector.removeElementAt(i);
+ }
+ }
+
+ public void VectorAddAll() {
+ Vector<Integer> vector = new Vector(), vector1 = mVector;
+
+ boolean flag;
+ for (int i = 10; i > 0; i--) {
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ flag = vector.addAll(vector1);
+ }
+ }
+
+ public void VectorRemove1() {
+ Vector<String> vector = mStrVector;
+ for (int j = 1000; j > 0; j--) {
+ vector.add("a");
+ vector.add("b");
+ }
+ String s = new String("a");
+ boolean flag;
+ for (int i = 10; i > 0; i--) {
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ flag = vector.remove(s);
+ }
+ }
+
+ public void testVectorAddAll1() {
+ Vector<Integer> mEmptyVector = new Vector();
+ boolean flag;
+ int pos = 0;
+ Vector<Integer> vector1 = mVector;
+ Vector<Integer> vector = mEmptyVector;
+ for (int i = 10; i > 0; i--) {
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ flag = vector.addAll(pos, vector1);
+ }
+ }
+
+ public void testVectorClone() {
+ Object obj;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ obj = vector.clone();
+ }
+ }
+
+ public void testVectorCapacity() {
+ int capacity;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ capacity = vector.capacity();
+ }
+ }
+
+ public void testVectorHashcode() {
+ int element;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ element = vector.hashCode();
+ }
+ }
+
+ public void testVectorElements() {
+ Enumeration<Integer> elements;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ elements = vector.elements();
+ }
+ }
+
+ public void testVectorToString() {
+ String str;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ str = vector.toString();
+ }
+ }
+
+ public void testVectorElementAt() {
+ int element;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ element = vector.elementAt(50);
+ }
+ }
+
+ public void testVectorAddElement() {
+ int element;
+ Vector<String> vector = mStrVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ vector.addElement(mTestString);
+ }
+ }
+
+ public void testVectorFirstElement() {
+ int element;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ element = vector.firstElement();
+ }
+ }
+
+ public void testVectorLastElement() {
+ int element;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ element = vector.lastElement();
+ }
+ }
+
+ public void testVectorSetElementAt() {
+ Vector<Integer> vector = mVector;
+ int value1 = 500, value2 = 50;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ vector.setElementAt(value1, value2);
+ }
+ }
+
+ public void testVectorIsEmpty() {
+ boolean flag;
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ flag = vector.isEmpty();
+ }
+ }
+
+ public void testVectorCopyInto() {
+ Integer[] rArray = new Integer[ITERATIONS];
+ Vector<Integer> vector = mVector;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ vector.copyInto(rArray);
+ }
+ }
+
+ public void testVectorInsertElementAt() {
+ Vector<String> vector = mStrVector;
+ String string = mTestString;
+ for (int i = ITERATIONS - 1; i > 0; i--) {
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ vector.insertElementAt(string, i);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java
new file mode 100644
index 0000000..4a0519e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/WebkitTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests;
+
+import android.test.AndroidTestCase;
+import android.text.format.DateFormat;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+import android.webkit.DateSorter;
+
+import java.util.Calendar;
+import java.util.Date;
+
+public class WebkitTest extends AndroidTestCase {
+
+ private static final String LOGTAG = WebkitTest.class.getName();
+
+ @MediumTest
+ public void testDateSorter() throws Exception {
+ /**
+ * Note: check the logging output manually to test
+ * nothing automated yet, besides object creation
+ */
+ DateSorter dateSorter = new DateSorter(mContext);
+ Date date = new Date();
+
+ for (int i = 0; i < DateSorter.DAY_COUNT; i++) {
+ Log.i(LOGTAG, "Boundary " + i + " " + dateSorter.getBoundary(i));
+ Log.i(LOGTAG, "Label " + i + " " + dateSorter.getLabel(i));
+ }
+
+ Calendar c = Calendar.getInstance();
+ long time = c.getTimeInMillis();
+ int index;
+ Log.i(LOGTAG, "now: " + dateSorter.getIndex(time));
+ for (int i = 0; i < 20; i++) {
+ time -= 8 * 60 * 60 * 1000; // 8 hours
+ date.setTime(time);
+ c.setTime(date);
+ index = dateSorter.getIndex(time);
+ Log.i(LOGTAG, "time: " + DateFormat.format("yyyy/MM/dd kk:mm:ss", c).toString() +
+ " " + index + " " + dateSorter.getLabel(index));
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java
new file mode 100644
index 0000000..d9d6101
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/AbortReceiver.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.Log;
+
+public class AbortReceiver extends BroadcastReceiver
+{
+ public AbortReceiver()
+ {
+ }
+
+ public void onReceive(Context context, Intent intent)
+ {
+ //Log.i("AbortReceiver", "onReceiveIntent!");
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(LaunchpadActivity.RECEIVER_ABORT);
+ caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+
+ // abort the broadcast!!!
+ abortBroadcast();
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
new file mode 100644
index 0000000..ab91761
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityManagerTest.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.res.Configuration;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.Iterator;
+import java.util.List;
+
+public class ActivityManagerTest extends AndroidTestCase {
+
+ protected Context mContext;
+ protected ActivityManager mActivityManager;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getContext();
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+ }
+
+ // TODO should write a test for getRecentTasks()
+ // TODO should write a test for getRunningTasks()
+ // TODO should write a test for getMemoryInfo()
+
+ // TODO: Find a way to re-enable this. It fails if any other app has failed during startup.
+ // This is probably an OK assumption given the desired system status when we run unit tests,
+ // but it's not necessarily the right assumption for a unit test.
+ @Suppress
+ public void disabledTestErrorTasksEmpty() throws Exception {
+
+ List<ActivityManager.ProcessErrorStateInfo> errList;
+
+ errList = mActivityManager.getProcessesInErrorState();
+
+ // test: confirm list is empty
+ assertNull(errList);
+ }
+
+ // TODO: Force an activity into an error state - then see if we can catch it here?
+ @SmallTest
+ public void testErrorTasksWithError() throws Exception {
+
+ List<ActivityManager.ProcessErrorStateInfo> errList;
+
+ // TODO force another process into an error condition. How?
+
+ // test: confirm error list length is at least 1 under varying query lengths
+// checkErrorListMax(1,-1);
+
+ errList = mActivityManager.getProcessesInErrorState();
+
+ // test: the list itself is healthy
+ checkErrorListSanity(errList);
+
+ // test: confirm our application shows up in the list
+ }
+
+ // TODO: Force an activity into an ANR state - then see if we can catch it here?
+ @SmallTest
+ public void testErrorTasksWithANR() throws Exception {
+
+ List<ActivityManager.ProcessErrorStateInfo> errList;
+
+ // TODO: force an application into an ANR state
+
+ errList = mActivityManager.getProcessesInErrorState();
+
+ // test: the list itself is healthy
+ checkErrorListSanity(errList);
+
+ // test: confirm our ANR'ing application shows up in the list
+ }
+
+ @SmallTest
+ public void testGetDeviceConfigurationInfo() throws Exception {
+ ConfigurationInfo config = mActivityManager.getDeviceConfigurationInfo();
+ assertNotNull(config);
+ // Validate values against configuration retrieved from resources
+ Configuration vconfig = mContext.getResources().getConfiguration();
+ assertNotNull(vconfig);
+ assertEquals(config.reqKeyboardType, vconfig.keyboard);
+ assertEquals(config.reqTouchScreen, vconfig.touchscreen);
+ assertEquals(config.reqNavigation, vconfig.navigation);
+ if (vconfig.navigation == Configuration.NAVIGATION_NONAV) {
+ assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV);
+ }
+ if (vconfig.keyboard != Configuration.KEYBOARD_UNDEFINED) {
+ assertNotNull(config.reqInputFeatures & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD);
+ }
+ }
+
+ // If any entries in appear in the list, sanity check them against all running applications
+ private void checkErrorListSanity(List<ActivityManager.ProcessErrorStateInfo> errList) {
+ if (errList == null) return;
+
+ Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+ while (iter.hasNext()) {
+ ActivityManager.ProcessErrorStateInfo info = iter.next();
+ assertNotNull(info);
+ // sanity checks
+ assertTrue((info.condition == ActivityManager.ProcessErrorStateInfo.CRASHED) ||
+ (info.condition == ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING));
+ // TODO look at each of these and consider a stronger test
+ // TODO can we cross-check at the process name via some other API?
+ // TODO is there a better test for strings, e.g. "assertIsLegalString")
+ assertNotNull(info.processName);
+ // reasonableness test for info.pid ?
+ assertNotNull(info.longMsg);
+ assertNotNull(info.shortMsg);
+ // is there any reasonable test for the crashData? Probably not.
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java
new file mode 100644
index 0000000..cffc60a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTests.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import junit.framework.TestSuite;
+
+public class ActivityTests {
+ public static final boolean DEBUG_LIFECYCLE = false;
+
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(ActivityTests.class.getName());
+
+ suite.addTestSuite(BroadcastTest.class);
+ suite.addTestSuite(IntentSenderTest.class);
+ suite.addTestSuite(ActivityManagerTest.class);
+ suite.addTestSuite(LaunchTest.class);
+ suite.addTestSuite(LifecycleTest.class);
+ suite.addTestSuite(ServiceTest.class);
+ suite.addTestSuite(MetaDataTest.class);
+ // Remove temporarily until bug 1171309 is fixed.
+ //suite.addTestSuite(SubActivityTest.class);
+ suite.addTestSuite(SetTimeZonePermissionsTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java
new file mode 100644
index 0000000..f960969
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ActivityTestsBase.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+
+public class ActivityTestsBase extends AndroidTestCase
+ implements PerformanceTestCase, LaunchpadActivity.CallingTest {
+ public static final String PERMISSION_GRANTED =
+ "com.android.unit_tests.permission.TEST_GRANTED";
+ public static final String PERMISSION_DENIED =
+ "com.android.unit_tests.permission.TEST_DENIED";
+
+ protected Intent mIntent;
+
+ private PerformanceTestCase.Intermediates mIntermediates;
+ private String mExpecting;
+
+ // Synchronization of activity result.
+ private boolean mFinished;
+ private int mResultCode = 0;
+ private Intent mData;
+ private RuntimeException mResultStack = null;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mIntent = new Intent(mContext, LaunchpadActivity.class);
+ mIntermediates = null;
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mIntermediates = null;
+ super.tearDown();
+ }
+
+ public boolean isPerformanceOnly() {
+ return false;
+ }
+
+ public void setInternalIterations(int count) {
+ }
+
+ public void startTiming(boolean realTime) {
+ if (mIntermediates != null) {
+ mIntermediates.startTiming(realTime);
+ }
+ }
+
+ public void addIntermediate(String name) {
+ if (mIntermediates != null) {
+ mIntermediates.addIntermediate(name);
+ }
+ }
+
+ public void addIntermediate(String name, long timeInNS) {
+ if (mIntermediates != null) {
+ mIntermediates.addIntermediate(name, timeInNS);
+ }
+ }
+
+ public void finishTiming(boolean realTime) {
+ if (mIntermediates != null) {
+ mIntermediates.finishTiming(realTime);
+ }
+ }
+
+ public void activityFinished(int resultCode, Intent data, RuntimeException where) {
+ finishWithResult(resultCode, data, where);
+ }
+
+ public Intent editIntent() {
+ return mIntent;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public int startPerformance(Intermediates intermediates) {
+ mIntermediates = intermediates;
+ return 1;
+ }
+
+ public void finishGood() {
+ finishWithResult(Activity.RESULT_OK, null);
+ }
+
+ public void finishBad(String error) {
+ finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(error));
+ }
+
+ public void finishWithResult(int resultCode, Intent data) {
+ RuntimeException where = new RuntimeException("Original error was here");
+ where.fillInStackTrace();
+ finishWithResult(resultCode, data, where);
+ }
+
+ public void finishWithResult(int resultCode, Intent data, RuntimeException where) {
+ synchronized (this) {
+ //System.out.println("*** Activity finished!!");
+ mResultCode = resultCode;
+ mData = data;
+ mResultStack = where;
+ mFinished = true;
+ notifyAll();
+ }
+ }
+
+ public int runLaunchpad(String action) {
+ LaunchpadActivity.setCallingTest(this);
+
+ synchronized (this) {
+ mIntent.setAction(action);
+ mFinished = false;
+ //System.out.println("*** Starting: " + mIntent);
+ mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ mContext.startActivity(mIntent);
+ }
+
+ return waitForResultOrThrow(60 * 1000);
+ }
+
+ public int waitForResultOrThrow(int timeoutMs) {
+ return waitForResultOrThrow(timeoutMs, null);
+ }
+
+ public int waitForResultOrThrow(int timeoutMs, String expected) {
+ int res = waitForResult(timeoutMs, expected);
+
+ if (res == Activity.RESULT_CANCELED) {
+ if (mResultStack != null) {
+ throw new RuntimeException(
+ mData != null ? mData.toString() : "Unable to launch",
+ mResultStack);
+ } else {
+ throw new RuntimeException(
+ mData != null ? mData.toString() : "Unable to launch");
+ }
+ }
+ return res;
+ }
+
+ public int waitForResult(int timeoutMs, String expected) {
+ mExpecting = expected;
+
+ long endTime = System.currentTimeMillis() + timeoutMs;
+
+ boolean timeout = false;
+ synchronized (this) {
+ while (!mFinished) {
+ long delay = endTime - System.currentTimeMillis();
+ if (delay < 0) {
+ timeout = true;
+ break;
+ }
+
+ try {
+ wait(delay);
+ } catch (java.lang.InterruptedException e) {
+ // do nothing
+ }
+ }
+ }
+
+ mFinished = false;
+
+ if (timeout) {
+ mResultCode = Activity.RESULT_CANCELED;
+ onTimeout();
+ }
+ return mResultCode;
+ }
+
+ public int getResultCode() {
+ return mResultCode;
+ }
+
+ public Intent getResultData() {
+ return mData;
+ }
+
+ public RuntimeException getResultStack() {
+ return mResultStack;
+ }
+
+ public void onTimeout() {
+ String msg = mExpecting == null
+ ? "Timeout" : ("Timeout while expecting " + mExpecting);
+ finishWithResult(Activity.RESULT_CANCELED, (new Intent()).setAction(msg));
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java
new file mode 100644
index 0000000..7f6db3c
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/BroadcastTest.java
@@ -0,0 +1,536 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class BroadcastTest extends ActivityTestsBase {
+ public static final int BROADCAST_TIMEOUT = 5 * 1000;
+
+ public static final String BROADCAST_REGISTERED =
+ "com.android.unit_tests.activity.BROADCAST_REGISTERED";
+ public static final String BROADCAST_LOCAL =
+ "com.android.unit_tests.activity.BROADCAST_LOCAL";
+ public static final String BROADCAST_LOCAL_GRANTED =
+ "com.android.unit_tests.activity.BROADCAST_LOCAL_GRANTED";
+ public static final String BROADCAST_LOCAL_DENIED =
+ "com.android.unit_tests.activity.BROADCAST_LOCAL_DENIED";
+ public static final String BROADCAST_REMOTE =
+ "com.android.unit_tests.activity.BROADCAST_REMOTE";
+ public static final String BROADCAST_REMOTE_GRANTED =
+ "com.android.unit_tests.activity.BROADCAST_REMOTE_GRANTED";
+ public static final String BROADCAST_REMOTE_DENIED =
+ "com.android.unit_tests.activity.BROADCAST_REMOTE_DENIED";
+ public static final String BROADCAST_ALL =
+ "com.android.unit_tests.activity.BROADCAST_ALL";
+ public static final String BROADCAST_MULTI =
+ "com.android.unit_tests.activity.BROADCAST_MULTI";
+ public static final String BROADCAST_ABORT =
+ "com.android.unit_tests.activity.BROADCAST_ABORT";
+
+ public static final String BROADCAST_STICKY1 =
+ "com.android.unit_tests.activity.BROADCAST_STICKY1";
+ public static final String BROADCAST_STICKY2 =
+ "com.android.unit_tests.activity.BROADCAST_STICKY2";
+
+ public static final String BROADCAST_FAIL_REGISTER =
+ "com.android.unit_tests.activity.BROADCAST_FAIL_REGISTER";
+ public static final String BROADCAST_FAIL_BIND =
+ "com.android.unit_tests.activity.BROADCAST_FAIL_BIND";
+
+ public static final String RECEIVER_REG = "receiver-reg";
+ public static final String RECEIVER_LOCAL = "receiver-local";
+ public static final String RECEIVER_REMOTE = "receiver-remote";
+ public static final String RECEIVER_ABORT = "receiver-abort";
+ public static final String RECEIVER_RESULTS = "receiver-results";
+
+ public static final String DATA_1 = "one";
+ public static final String DATA_2 = "two";
+
+ public static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+ public static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+ private String[] mExpectedReceivers = null;
+ private int mNextReceiver;
+
+ private String[] mExpectedData = null;
+ private boolean[] mReceivedData = null;
+
+ boolean mReceiverRegistered = false;
+
+ public void setExpectedReceivers(String[] receivers) {
+ mExpectedReceivers = receivers;
+ mNextReceiver = 0;
+ }
+
+ public void setExpectedData(String[] data) {
+ mExpectedData = data;
+ mReceivedData = new boolean[data.length];
+ }
+
+ public void onTimeout() {
+ String msg = "Timeout";
+ if (mExpectedReceivers != null && mNextReceiver < mExpectedReceivers.length) {
+ msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
+ }
+ finishBad(msg);
+ }
+
+ public Intent makeBroadcastIntent(String action) {
+ Intent intent = new Intent(action, null);
+ intent.putExtra("caller", mCallTarget);
+ return intent;
+ }
+
+ public void finishWithResult(int resultCode, Intent data) {
+ unregisterMyReceiver();
+ super.finishWithResult(resultCode, data);
+ }
+
+ public final void gotReceive(String name, Intent intent) {
+ synchronized (this) {
+
+ //System.out.println("Got receive: " + name);
+ //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
+ //new RuntimeException("stack").printStackTrace();
+
+ addIntermediate(name);
+
+ if (mExpectedData != null) {
+ int n = mExpectedData.length;
+ int i;
+ boolean prev = false;
+ for (i = 0; i < n; i++) {
+ if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
+ if (mReceivedData[i]) {
+ prev = true;
+ continue;
+ }
+ mReceivedData[i] = true;
+ break;
+ }
+ }
+ if (i >= n) {
+ if (prev) {
+ finishBad("Receive got data too many times: "
+ + intent.getStringExtra("test"));
+ } else {
+ finishBad("Receive got unexpected data: "
+ + intent.getStringExtra("test"));
+ }
+ new RuntimeException("stack").printStackTrace();
+ return;
+ }
+ }
+
+ if (mNextReceiver >= mExpectedReceivers.length) {
+ finishBad("Got too many onReceiveIntent() calls!");
+// System.out.println("Too many intents received: now at "
+// + mNextReceiver + ", expect list: "
+// + Arrays.toString(mExpectedReceivers));
+ fail("Got too many onReceiveIntent() calls!");
+ } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
+ finishBad("Receive out of order: got " + name
+ + " but expected "
+ + mExpectedReceivers[mNextReceiver]);
+ fail("Receive out of order: got " + name
+ + " but expected "
+ + mExpectedReceivers[mNextReceiver]);
+ } else {
+ mNextReceiver++;
+ if (mNextReceiver == mExpectedReceivers.length) {
+ finishTest();
+ }
+ }
+ }
+ }
+
+ public void registerMyReceiver(IntentFilter filter, String permission) {
+ mReceiverRegistered = true;
+ //System.out.println("Registering: " + mReceiver);
+ getContext().registerReceiver(mReceiver, filter, permission, null);
+ }
+
+ public void unregisterMyReceiver() {
+ if (mReceiverRegistered) {
+ unregisterMyReceiverNoCheck();
+ }
+ }
+
+ public void unregisterMyReceiverNoCheck() {
+ mReceiverRegistered = false;
+ //System.out.println("Unregistering: " + mReceiver);
+ getContext().unregisterReceiver(mReceiver);
+ }
+
+ public void onRegisteredReceiver(Intent intent) {
+ gotReceive(RECEIVER_REG, intent);
+ }
+
+ private Binder mCallTarget = new Binder() {
+ public boolean onTransact(int code, Parcel data, Parcel reply,
+ int flags) {
+ data.setDataPosition(0);
+ data.enforceInterface(LaunchpadActivity.LAUNCH);
+ if (code == GOT_RECEIVE_TRANSACTION) {
+ String name = data.readString();
+ gotReceive(name, null);
+ return true;
+ } else if (code == ERROR_TRANSACTION) {
+ finishBad(data.readString());
+ return true;
+ }
+ return false;
+ }
+ };
+
+ private void finishTest() {
+ if (mReceiverRegistered) {
+ addIntermediate("before-unregister");
+ unregisterMyReceiver();
+ }
+ finishTiming(true);
+ finishGood();
+ }
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ //System.out.println("Receive in: " + this + ": " + intent);
+ onRegisteredReceiver(intent);
+ }
+ };
+
+ // Mark flaky until http://b/issue?id=1191607 is resolved.
+ @FlakyTest(tolerance=2)
+ public void testRegistered() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_REGISTERED);
+ }
+
+ public void testLocal() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_LOCAL);
+ }
+
+ public void testRemote() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_REMOTE);
+ }
+
+ public void testAbort() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_ABORT);
+ }
+
+ @FlakyTest(tolerance=2)
+ public void testAll() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_ALL);
+ }
+
+ @FlakyTest(tolerance=2)
+ public void testMulti() throws Exception {
+ runLaunchpad(LaunchpadActivity.BROADCAST_MULTI);
+ }
+
+ private class TestBroadcastReceiver extends BroadcastReceiver {
+ public boolean mHaveResult = false;
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (BroadcastTest.this) {
+ mHaveResult = true;
+ BroadcastTest.this.notifyAll();
+ }
+ }
+ }
+
+ public void testResult() throws Exception {
+ TestBroadcastReceiver broadcastReceiver = new TestBroadcastReceiver();
+
+ synchronized (this) {
+ Bundle map = new Bundle();
+ map.putString("foo", "you");
+ map.putString("remove", "me");
+ getContext().sendOrderedBroadcast(
+ new Intent("com.android.unit_tests.activity.BROADCAST_RESULT"),
+ null, broadcastReceiver, null, 1, "foo", map);
+ while (!broadcastReceiver.mHaveResult) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ //System.out.println("Code: " + mResultCode + ", data: " + mResultData);
+ //System.out.println("Extras: " + mResultExtras);
+
+ assertEquals("Incorrect code: " + broadcastReceiver.getResultCode(),
+ 3, broadcastReceiver.getResultCode());
+
+ assertEquals("bar", broadcastReceiver.getResultData());
+
+ Bundle resultExtras = broadcastReceiver.getResultExtras(false);
+ assertEquals("them", resultExtras.getString("bar"));
+ assertEquals("you", resultExtras.getString("foo"));
+ assertNull(resultExtras.getString("remove"));
+ }
+ }
+
+ public void testSetSticky() throws Exception {
+ Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_1);
+ ActivityManagerNative.getDefault().unbroadcastIntent(null, intent);
+
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ addIntermediate("finished-broadcast");
+
+ IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+ Intent sticky = getContext().registerReceiver(null, filter);
+ assertNotNull("Sticky not found", sticky);
+ assertEquals(LaunchpadActivity.DATA_1, sticky.getStringExtra("test"));
+ }
+
+ public void testClearSticky() throws Exception {
+ Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_1);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+ ActivityManagerNative.getDefault().unbroadcastIntent(
+ null, new Intent(LaunchpadActivity.BROADCAST_STICKY1, null));
+ addIntermediate("finished-unbroadcast");
+
+ IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+ Intent sticky = getContext().registerReceiver(null, filter);
+ assertNull("Sticky not found", sticky);
+ }
+
+ public void testReplaceSticky() throws Exception {
+ Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_1);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_2);
+
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ addIntermediate("finished-broadcast");
+
+ IntentFilter filter = new IntentFilter(LaunchpadActivity.BROADCAST_STICKY1);
+ Intent sticky = getContext().registerReceiver(null, filter);
+ assertNotNull("Sticky not found", sticky);
+ assertEquals(LaunchpadActivity.DATA_2, sticky.getStringExtra("test"));
+ }
+
+ // Marking flaky until http://b/issue?id=1191337 is resolved
+ @FlakyTest(tolerance=2)
+ public void testReceiveSticky() throws Exception {
+ Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_1);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+ runLaunchpad(LaunchpadActivity.BROADCAST_STICKY1);
+ }
+
+ // Marking flaky until http://b/issue?id=1191337 is resolved
+ @FlakyTest(tolerance=2)
+ public void testReceive2Sticky() throws Exception {
+ Intent intent = new Intent(LaunchpadActivity.BROADCAST_STICKY1, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_1);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+ intent = new Intent(LaunchpadActivity.BROADCAST_STICKY2, null);
+ intent.putExtra("test", LaunchpadActivity.DATA_2);
+ ActivityManagerNative.broadcastStickyIntent(intent, null);
+
+ runLaunchpad(LaunchpadActivity.BROADCAST_STICKY2);
+ }
+
+ public void testRegisteredReceivePermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_REG});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
+ addIntermediate("after-register");
+ getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRegisteredReceivePermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED);
+ addIntermediate("after-register");
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_REGISTERED),
+ null, finish, null, Activity.RESULT_CANCELED, null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRegisteredBroadcastPermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_REG});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+ addIntermediate("after-register");
+ getContext().sendBroadcast(
+ makeBroadcastIntent(BROADCAST_REGISTERED),
+ PERMISSION_GRANTED);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRegisteredBroadcastPermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+ addIntermediate("after-register");
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_REGISTERED),
+ PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+ null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testLocalReceivePermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL_GRANTED));
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testLocalReceivePermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_LOCAL_DENIED),
+ null, finish, null, Activity.RESULT_CANCELED,
+ null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testLocalBroadcastPermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ getContext().sendBroadcast(
+ makeBroadcastIntent(BROADCAST_LOCAL),
+ PERMISSION_GRANTED);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testLocalBroadcastPermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_LOCAL),
+ PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+ null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRemoteReceivePermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+ getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE_GRANTED));
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRemoteReceivePermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_REMOTE_DENIED),
+ null, finish, null, Activity.RESULT_CANCELED,
+ null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRemoteBroadcastPermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+ getContext().sendBroadcast(
+ makeBroadcastIntent(BROADCAST_REMOTE),
+ PERMISSION_GRANTED);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testRemoteBroadcastPermissionDenied() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+ BroadcastReceiver finish = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ getContext().sendOrderedBroadcast(
+ makeBroadcastIntent(BROADCAST_REMOTE),
+ PERMISSION_DENIED, finish, null, Activity.RESULT_CANCELED,
+ null, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testReceiverCanNotRegister() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_REGISTER));
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testReceiverCanNotBind() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ getContext().sendBroadcast(makeBroadcastIntent(BROADCAST_FAIL_BIND));
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ }
+
+ public void testLocalUnregisterTwice() throws Exception {
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), null);
+ unregisterMyReceiverNoCheck();
+ try {
+ unregisterMyReceiverNoCheck();
+ fail("No exception thrown on second unregister");
+ } catch (IllegalArgumentException e) {
+ Log.i("foo", "Unregister exception", e);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java
new file mode 100644
index 0000000..dd5274a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ClearTop.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+
+public class ClearTop extends Activity {
+ public static final String WAIT_CLEAR_TASK = "waitClearTask";
+
+ public ClearTop() {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ //Log.i("foo", "Creating: " + this);
+ Intent intent = new Intent(getIntent()).setAction(LocalScreen.CLEAR_TASK)
+ .setClass(this, LocalScreen.class);
+ startActivity(intent);
+ }
+
+ @Override
+ public void onNewIntent(Intent intent) {
+ //Log.i("foo", "New intent in " + this + ": " + intent);
+ if (LocalScreen.CLEAR_TASK.equals(intent.getAction())) {
+ setResult(RESULT_OK);
+ } else {
+ setResult(RESULT_CANCELED, new Intent().setAction(
+ "New intent received " + intent + ", expecting action "
+ + TestedScreen.CLEAR_TASK));
+ }
+ finish();
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java
new file mode 100644
index 0000000..a30c1cb
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/IntentSenderTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.test.suitebuilder.annotation.Suppress;
+import android.os.Bundle;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class IntentSenderTest extends BroadcastTest {
+
+ public void testRegisteredReceivePermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_REG});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_GRANTED);
+ addIntermediate("after-register");
+ PendingIntent is = PendingIntent.getBroadcast(getContext(), 0,
+ makeBroadcastIntent(BROADCAST_REGISTERED), 0);
+ is.send();
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ is.cancel();
+ }
+
+ public void testRegisteredReceivePermissionDenied() throws Exception {
+ final Intent intent = makeBroadcastIntent(BROADCAST_REGISTERED);
+
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED), PERMISSION_DENIED);
+ addIntermediate("after-register");
+
+ PendingIntent.OnFinished finish = new PendingIntent.OnFinished() {
+ public void onSendFinished(PendingIntent pi, Intent intent,
+ int resultCode, String resultData, Bundle resultExtras) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+ is.send(Activity.RESULT_CANCELED, finish, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ is.cancel();
+ }
+
+ public void testLocalReceivePermissionGranted() throws Exception {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ PendingIntent is = PendingIntent.getBroadcast(getContext(), 0,
+ makeBroadcastIntent(BROADCAST_LOCAL_GRANTED), 0);
+ is.send();
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ is.cancel();
+ }
+
+ public void testLocalReceivePermissionDenied() throws Exception {
+ final Intent intent = makeBroadcastIntent(BROADCAST_LOCAL_DENIED);
+
+ setExpectedReceivers(new String[]{RECEIVER_RESULTS});
+
+ PendingIntent.OnFinished finish = new PendingIntent.OnFinished() {
+ public void onSendFinished(PendingIntent pi, Intent intent,
+ int resultCode, String resultData, Bundle resultExtras) {
+ gotReceive(RECEIVER_RESULTS, intent);
+ }
+ };
+
+ PendingIntent is = PendingIntent.getBroadcast(getContext(), 0, intent, 0);
+ is.send(Activity.RESULT_CANCELED, finish, null);
+ waitForResultOrThrow(BROADCAST_TIMEOUT);
+ is.cancel();
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java
new file mode 100644
index 0000000..12b1b5d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class LaunchTest extends ActivityTestsBase {
+
+ @LargeTest
+ public void testColdActivity() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), TestedActivity.class));
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ @LargeTest
+ public void testLocalActivity() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), LocalActivity.class));
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ @LargeTest
+ public void testColdScreen() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), TestedScreen.class));
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ @LargeTest
+ public void testLocalScreen() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), LocalScreen.class));
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ @LargeTest
+ public void testForwardResult() throws Exception {
+ runLaunchpad(LaunchpadActivity.FORWARD_RESULT);
+ }
+
+ // The following is disabled until we can catch and recover from
+ // application errors.
+ public void xxtestBadParcelable() throws Exception {
+ // All we really care about for this test is that the system
+ // doesn't crash.
+ runLaunchpad(LaunchpadActivity.BAD_PARCELABLE);
+ }
+
+ @LargeTest
+ public void testClearTopInCreate() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ @LargeTest
+ public void testClearTopWhileResumed() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), ClearTop.class));
+ mIntent.putExtra(ClearTop.WAIT_CLEAR_TASK, true);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+}
+
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java
new file mode 100644
index 0000000..06e7a84
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadActivity.java
@@ -0,0 +1,588 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.test.PerformanceTestCase;
+import android.util.Log;
+
+class MyBadParcelable implements Parcelable {
+ public MyBadParcelable() {
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString("I am bad");
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Parcelable.Creator<MyBadParcelable> CREATOR
+ = new Parcelable.Creator<MyBadParcelable>() {
+ public MyBadParcelable createFromParcel(Parcel in) {
+ return new MyBadParcelable(in);
+ }
+
+ public MyBadParcelable[] newArray(int size) {
+ return new MyBadParcelable[size];
+ }
+ };
+
+ public MyBadParcelable(Parcel in) {
+ String nm = in.readString();
+ }
+}
+
+public class LaunchpadActivity extends Activity {
+ public interface CallingTest extends PerformanceTestCase.Intermediates {
+ public void startTiming(boolean realTime);
+ public void addIntermediate(String name);
+ public void addIntermediate(String name, long timeInNS);
+ public void finishTiming(boolean realTime);
+ public void activityFinished(int resultCode, Intent data,
+ RuntimeException where);
+ }
+
+ // Also used as the Binder interface descriptor string in these tests
+ public static final String LAUNCH = "com.android.unit_tests.activity.LAUNCH";
+
+ public static final String FORWARD_RESULT =
+ "com.android.unit_tests.activity.FORWARD_RESULT";
+ public static final String RETURNED_RESULT =
+ "com.android.unit_tests.activity.RETURNED_RESULT";
+
+ public static final String BAD_PARCELABLE =
+ "com.android.unit_tests.activity.BAD_PARCELABLE";
+
+ public static final int LAUNCHED_RESULT = 1;
+ public static final int FORWARDED_RESULT = 2;
+
+ public static final String LIFECYCLE_BASIC =
+ "com.android.unit_tests.activity.LIFECYCLE_BASIC";
+ public static final String LIFECYCLE_SCREEN =
+ "com.android.unit_tests.activity.LIFECYCLE_SCREEN";
+ public static final String LIFECYCLE_DIALOG =
+ "com.android.unit_tests.activity.LIFECYCLE_DIALOG";
+ public static final String LIFECYCLE_FINISH_CREATE =
+ "com.android.unit_tests.activity.LIFECYCLE_FINISH_CREATE";
+ public static final String LIFECYCLE_FINISH_START =
+ "com.android.unit_tests.activity.LIFECYCLE_FINISH_START";
+
+ public static final String BROADCAST_REGISTERED =
+ "com.android.unit_tests.activity.BROADCAST_REGISTERED";
+ public static final String BROADCAST_LOCAL =
+ "com.android.unit_tests.activity.BROADCAST_LOCAL";
+ public static final String BROADCAST_REMOTE =
+ "com.android.unit_tests.activity.BROADCAST_REMOTE";
+ public static final String BROADCAST_ALL =
+ "com.android.unit_tests.activity.BROADCAST_ALL";
+ public static final String BROADCAST_REPEAT =
+ "com.android.unit_tests.activity.BROADCAST_REPEAT";
+ public static final String BROADCAST_MULTI =
+ "com.android.unit_tests.activity.BROADCAST_MULTI";
+ public static final String BROADCAST_ABORT =
+ "com.android.unit_tests.activity.BROADCAST_ABORT";
+
+ public static final String BROADCAST_STICKY1 =
+ "com.android.unit_tests.activity.BROADCAST_STICKY1";
+ public static final String BROADCAST_STICKY2 =
+ "com.android.unit_tests.activity.BROADCAST_STICKY2";
+
+ public static final String RECEIVER_REG = "receiver-reg";
+ public static final String RECEIVER_LOCAL = "receiver-local";
+ public static final String RECEIVER_REMOTE = "receiver-remote";
+ public static final String RECEIVER_ABORT = "receiver-abort";
+
+ public static final String DATA_1 = "one";
+ public static final String DATA_2 = "two";
+
+ public static final String ON_START = "onStart";
+ public static final String ON_RESTART = "onRestart";
+ public static final String ON_RESUME = "onResume";
+ public static final String ON_FREEZE = "onSaveInstanceState";
+ public static final String ON_PAUSE = "onPause";
+ public static final String ON_STOP = "onStop";
+ public static final String ON_DESTROY = "onDestroy";
+
+ public static final String DO_FINISH = "finish";
+ public static final String DO_LOCAL_SCREEN = "local-screen";
+ public static final String DO_LOCAL_DIALOG = "local-dialog";
+
+ private boolean mBadParcelable = false;
+
+ private boolean mStarted = false;
+ private long mStartTime;
+
+ private int mResultCode = RESULT_CANCELED;
+ private Intent mData = (new Intent()).setAction("No result received");
+ private RuntimeException mResultStack = null;
+
+ private String[] mExpectedLifecycle = null;
+ private int mNextLifecycle;
+
+ private String[] mExpectedReceivers = null;
+ private int mNextReceiver;
+
+ private String[] mExpectedData = null;
+ private boolean[] mReceivedData = null;
+
+ boolean mReceiverRegistered = false;
+
+ private static CallingTest sCallingTest = null;
+
+ public static void setCallingTest(CallingTest ct) {
+ sCallingTest = ct;
+ }
+
+ public LaunchpadActivity() {
+ mStartTime = System.currentTimeMillis();
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ String action = getIntent().getAction();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ if (LIFECYCLE_BASIC.equals(action)) {
+ setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+ DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+ } else if (LIFECYCLE_SCREEN.equals(action)) {
+ setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+ DO_LOCAL_SCREEN, ON_FREEZE, ON_PAUSE, ON_STOP,
+ ON_RESTART, ON_START, ON_RESUME,
+ DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+ } else if (LIFECYCLE_DIALOG.equals(action)) {
+ setExpectedLifecycle(new String[]{ON_START, ON_RESUME,
+ DO_LOCAL_DIALOG, ON_FREEZE, ON_PAUSE, ON_RESUME,
+ DO_FINISH, ON_PAUSE, ON_STOP, ON_DESTROY});
+ } else if (LIFECYCLE_FINISH_CREATE.equals(action)) {
+ // This one behaves a little differently when running in a group.
+ if (getParent() == null) {
+ setExpectedLifecycle(new String[]{ON_DESTROY});
+ } else {
+ setExpectedLifecycle(new String[]{ON_START, ON_STOP, ON_DESTROY});
+ }
+ finish();
+ } else if (LIFECYCLE_FINISH_START.equals(action)) {
+ setExpectedLifecycle(new String[]{ON_START, DO_FINISH,
+ ON_STOP, ON_DESTROY});
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "START lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ checkLifecycle(ON_START);
+ }
+
+ @Override
+ protected void onRestart() {
+ super.onStart();
+ checkLifecycle(ON_RESTART);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ checkLifecycle(ON_RESUME);
+
+ if (!mStarted) {
+ mStarted = true;
+
+ mHandler.postDelayed(mTimeout, 5 * 1000);
+
+ String action = getIntent().getAction();
+
+ sCallingTest.startTiming(true);
+
+ if (LAUNCH.equals(action)) {
+ Intent intent = getIntent();
+ intent.setFlags(0);
+ intent.setComponent((ComponentName)
+ intent.getParcelableExtra("component"));
+ //System.out.println("*** Launchpad is starting: comp=" + intent.component);
+ startActivityForResult(intent, LAUNCHED_RESULT);
+ } else if (FORWARD_RESULT.equals(action)) {
+ Intent intent = getIntent();
+ intent.setFlags(0);
+ intent.setClass(this, LocalScreen.class);
+ startActivityForResult(intent, FORWARDED_RESULT);
+ } else if (BAD_PARCELABLE.equals(action)) {
+ mBadParcelable = true;
+ Intent intent = getIntent();
+ intent.setFlags(0);
+ intent.setClass(this, LocalScreen.class);
+ startActivityForResult(intent, LAUNCHED_RESULT);
+ } else if (BROADCAST_REGISTERED.equals(action)) {
+ setExpectedReceivers(new String[]{RECEIVER_REG});
+ registerMyReceiver(new IntentFilter(BROADCAST_REGISTERED));
+ sCallingTest.addIntermediate("after-register");
+ sendBroadcast(makeBroadcastIntent(BROADCAST_REGISTERED));
+ } else if (BROADCAST_LOCAL.equals(action)) {
+ setExpectedReceivers(new String[]{RECEIVER_LOCAL});
+ sendBroadcast(makeBroadcastIntent(BROADCAST_LOCAL));
+ } else if (BROADCAST_REMOTE.equals(action)) {
+ setExpectedReceivers(new String[]{RECEIVER_REMOTE});
+ sendBroadcast(makeBroadcastIntent(BROADCAST_REMOTE));
+ } else if (BROADCAST_ALL.equals(action)) {
+ setExpectedReceivers(new String[]{
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL});
+ registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+ sCallingTest.addIntermediate("after-register");
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ } else if (BROADCAST_MULTI.equals(action)) {
+ setExpectedReceivers(new String[]{
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_LOCAL, RECEIVER_REMOTE,
+ RECEIVER_LOCAL, RECEIVER_REMOTE,
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_REG, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_LOCAL,
+ RECEIVER_REMOTE, RECEIVER_LOCAL});
+ registerMyReceiver(new IntentFilter(BROADCAST_ALL));
+ sCallingTest.addIntermediate("after-register");
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_LOCAL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REMOTE), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ALL), null);
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_REPEAT), null);
+ } else if (BROADCAST_ABORT.equals(action)) {
+ setExpectedReceivers(new String[]{
+ RECEIVER_REMOTE, RECEIVER_ABORT});
+ registerMyReceiver(new IntentFilter(BROADCAST_ABORT));
+ sCallingTest.addIntermediate("after-register");
+ sendOrderedBroadcast(makeBroadcastIntent(BROADCAST_ABORT), null);
+ } else if (BROADCAST_STICKY1.equals(action)) {
+ setExpectedReceivers(new String[]{RECEIVER_REG});
+ setExpectedData(new String[]{DATA_1});
+ registerMyReceiver(new IntentFilter(BROADCAST_STICKY1));
+ sCallingTest.addIntermediate("after-register");
+ } else if (BROADCAST_STICKY2.equals(action)) {
+ setExpectedReceivers(new String[]{RECEIVER_REG, RECEIVER_REG});
+ setExpectedData(new String[]{DATA_1, DATA_2});
+ IntentFilter filter = new IntentFilter(BROADCAST_STICKY1);
+ filter.addAction(BROADCAST_STICKY2);
+ registerMyReceiver(filter);
+ sCallingTest.addIntermediate("after-register");
+ }
+ }
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle icicle) {
+ super.onSaveInstanceState(icicle);
+ checkLifecycle(ON_FREEZE);
+ if (mBadParcelable) {
+ icicle.putParcelable("baddy", new MyBadParcelable());
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "PAUSE lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ checkLifecycle(ON_PAUSE);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ checkLifecycle(ON_STOP);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ switch (requestCode) {
+ case LAUNCHED_RESULT:
+ sCallingTest.finishTiming(true);
+ finishWithResult(resultCode, data);
+ break;
+ case FORWARDED_RESULT:
+ sCallingTest.finishTiming(true);
+ if (RETURNED_RESULT.equals(data.getAction())) {
+ finishWithResult(resultCode, data);
+ } else {
+ finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Bad data returned: " + data));
+ }
+ break;
+ default:
+ sCallingTest.finishTiming(true);
+ finishWithResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Unexpected request code: " + requestCode));
+ break;
+ }
+ }
+
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "DESTROY lauchpad "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ checkLifecycle(ON_DESTROY);
+ sCallingTest.activityFinished(mResultCode, mData, mResultStack);
+ }
+
+ private void setExpectedLifecycle(String[] lifecycle) {
+ mExpectedLifecycle = lifecycle;
+ mNextLifecycle = 0;
+ }
+
+ private void checkLifecycle(String where) {
+ if (mExpectedLifecycle == null) return;
+
+ if (mNextLifecycle >= mExpectedLifecycle.length) {
+ finishBad("Activity lifecycle incorrect: received " + where
+ + " but don't expect any more calls");
+ mExpectedLifecycle = null;
+ return;
+ }
+ if (!mExpectedLifecycle[mNextLifecycle].equals(where)) {
+ finishBad("Activity lifecycle incorrect: received " + where
+ + " but expected " + mExpectedLifecycle[mNextLifecycle]
+ + " at " + mNextLifecycle);
+ mExpectedLifecycle = null;
+ return;
+ }
+
+ mNextLifecycle++;
+
+ if (mNextLifecycle >= mExpectedLifecycle.length) {
+ setTestResult(RESULT_OK, null);
+ return;
+ }
+
+ String next = mExpectedLifecycle[mNextLifecycle];
+ if (where.equals(ON_DESTROY)) {
+ finishBad("Activity lifecycle incorrect: received " + where
+ + " but expected more actions (next is " + next + ")");
+ mExpectedLifecycle = null;
+ return;
+ } else if (next.equals(DO_FINISH)) {
+ mNextLifecycle++;
+ if (mNextLifecycle >= mExpectedLifecycle.length) {
+ setTestResult(RESULT_OK, null);
+ }
+ if (!isFinishing()) {
+ finish();
+ }
+ } else if (next.equals(DO_LOCAL_SCREEN)) {
+ mNextLifecycle++;
+ Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+ intent.setClass(this, LocalScreen.class);
+ startActivity(intent);
+ } else if (next.equals(DO_LOCAL_DIALOG)) {
+ mNextLifecycle++;
+ Intent intent = new Intent(TestedScreen.WAIT_BEFORE_FINISH);
+ intent.setClass(this, LocalDialog.class);
+ startActivity(intent);
+ }
+ }
+
+ private void setExpectedReceivers(String[] receivers) {
+ mExpectedReceivers = receivers;
+ mNextReceiver = 0;
+ }
+
+ private void setExpectedData(String[] data) {
+ mExpectedData = data;
+ mReceivedData = new boolean[data.length];
+ }
+
+ private Intent makeBroadcastIntent(String action) {
+ Intent intent = new Intent(action, null);
+ intent.putExtra("caller", mCallTarget);
+ return intent;
+ }
+
+ private void finishGood() {
+ finishWithResult(RESULT_OK, null);
+ }
+
+ private void finishBad(String error) {
+ finishWithResult(RESULT_CANCELED, (new Intent()).setAction(error));
+ }
+
+ private void finishWithResult(int resultCode, Intent data) {
+ setTestResult(resultCode, data);
+ finish();
+ }
+
+ private void setTestResult(int resultCode, Intent data) {
+ mHandler.removeCallbacks(mTimeout);
+ unregisterMyReceiver();
+ mResultCode = resultCode;
+ mData = data;
+ mResultStack = new RuntimeException("Original error was here");
+ mResultStack.fillInStackTrace();
+ }
+
+ private void registerMyReceiver(IntentFilter filter) {
+ mReceiverRegistered = true;
+ //System.out.println("Registering: " + mReceiver);
+ registerReceiver(mReceiver, filter);
+ }
+
+ private void unregisterMyReceiver() {
+ if (mReceiverRegistered) {
+ mReceiverRegistered = false;
+ //System.out.println("Unregistering: " + mReceiver);
+ unregisterReceiver(mReceiver);
+ }
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ }
+ };
+
+ static final int GOT_RECEIVE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION;
+ static final int ERROR_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 1;
+
+ private Binder mCallTarget = new Binder() {
+ public boolean onTransact(int code, Parcel data, Parcel reply, int flags) {
+ data.setDataPosition(0);
+ data.enforceInterface(LaunchpadActivity.LAUNCH);
+ if (code == GOT_RECEIVE_TRANSACTION) {
+ String name = data.readString();
+ gotReceive(name, null);
+ return true;
+ } else if (code == ERROR_TRANSACTION) {
+ finishBad(data.readString());
+ return true;
+ }
+ return false;
+ }
+ };
+
+ private final void gotReceive(String name, Intent intent) {
+ synchronized (this) {
+
+ //System.out.println("Got receive: " + name);
+ //System.out.println(mNextReceiver + " in " + mExpectedReceivers);
+ //new RuntimeException("stack").printStackTrace();
+
+ sCallingTest.addIntermediate(mNextReceiver + "-" + name);
+
+ if (mExpectedData != null) {
+ int n = mExpectedData.length;
+ int i;
+ boolean prev = false;
+ for (i = 0; i < n; i++) {
+ if (mExpectedData[i].equals(intent.getStringExtra("test"))) {
+ if (mReceivedData[i]) {
+ prev = true;
+ continue;
+ }
+ mReceivedData[i] = true;
+ break;
+ }
+ }
+ if (i >= n) {
+ if (prev) {
+ finishBad("Receive got data too many times: "
+ + intent.getStringExtra("test"));
+ } else {
+ finishBad("Receive got unexpected data: "
+ + intent.getStringExtra("test"));
+ }
+ return;
+ }
+ }
+
+ if (mNextReceiver >= mExpectedReceivers.length) {
+ finishBad("Got too many onReceiveIntent() calls!");
+// System.out.println("Too many intents received: now at "
+// + mNextReceiver + ", expect list: "
+// + Arrays.toString(mExpectedReceivers));
+ } else if (!mExpectedReceivers[mNextReceiver].equals(name)) {
+ finishBad("Receive out of order: got " + name + " but expected "
+ + mExpectedReceivers[mNextReceiver] + " at "
+ + mNextReceiver);
+ } else {
+ mNextReceiver++;
+ if (mNextReceiver == mExpectedReceivers.length) {
+ mHandler.post(mUnregister);
+ }
+ }
+
+ }
+ }
+
+ private Runnable mUnregister = new Runnable() {
+ public void run() {
+ if (mReceiverRegistered) {
+ sCallingTest.addIntermediate("before-unregister");
+ unregisterMyReceiver();
+ }
+ sCallingTest.finishTiming(true);
+ finishGood();
+ }
+ };
+
+ private Runnable mTimeout = new Runnable() {
+ public void run() {
+ Log.i("foo", "**** TIMEOUT");
+ String msg = "Timeout";
+ if (mExpectedReceivers != null
+ && mNextReceiver < mExpectedReceivers.length) {
+ msg = msg + " waiting for " + mExpectedReceivers[mNextReceiver];
+ }
+ finishBad(msg);
+ }
+ };
+
+ private BroadcastReceiver mReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ //System.out.println("Receive in: " + this + ": " + intent);
+ gotReceive(RECEIVER_REG, intent);
+ }
+ };
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java
new file mode 100644
index 0000000..1e0e4a6
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LaunchpadTabActivity.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.TabActivity;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Bundle;
+import android.widget.TabHost;
+
+public class LaunchpadTabActivity extends TabActivity {
+ public LaunchpadTabActivity() {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent tabIntent = new Intent(getIntent());
+ tabIntent.setComponent((ComponentName)tabIntent.getParcelableExtra("tab"));
+
+ TabHost th = getTabHost();
+ TabHost.TabSpec ts = th.newTabSpec("1");
+ ts.setIndicator("One");
+ ts.setContent(tabIntent);
+ th.addTab(ts);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java
new file mode 100644
index 0000000..fdc12ce
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LifecycleTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class LifecycleTest extends ActivityTestsBase {
+ private Intent mTopIntent;
+ private Intent mTabIntent;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTopIntent = mIntent;
+ mTabIntent = new Intent(mContext, LaunchpadTabActivity.class);
+ mTabIntent.putExtra("tab", new ComponentName(mContext,
+ LaunchpadActivity.class));
+ }
+
+ @LargeTest
+ public void testBasic() throws Exception {
+ mIntent = mTopIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+ }
+
+ //Suppressing until 1285425 is fixed.
+ @Suppress
+ public void testTabBasic() throws Exception {
+ mIntent = mTabIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_BASIC);
+ }
+
+ //Marking flaky until bug 1164344 is fixed.
+ @FlakyTest(tolerance=2)
+ @LargeTest
+ public void testScreen() throws Exception {
+ mIntent = mTopIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+ }
+
+ //Marking flaky until bug 1164344 is fixed.
+ //@FlakyTest(tolerance=2)
+ //Suppressing until 1285425 is fixed.
+ @Suppress
+ public void testTabScreen() throws Exception {
+ mIntent = mTabIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_SCREEN);
+ }
+
+ @LargeTest
+ public void testDialog() throws Exception {
+ mIntent = mTopIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+ }
+
+ //Suppressing until 1285425 is fixed.
+ @Suppress
+ public void testTabDialog() throws Exception {
+ mIntent = mTabIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_DIALOG);
+ }
+
+ @MediumTest
+ public void testFinishCreate() throws Exception {
+ mIntent = mTopIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE);
+ }
+
+ //Suppressing until 1285425 is fixed.
+ @Suppress
+ public void testTabFinishCreate() throws Exception {
+ mIntent = mTabIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_CREATE);
+ }
+
+ @MediumTest
+ public void testFinishStart() throws Exception {
+ mIntent = mTopIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START);
+ }
+
+ //Suppressing until 1285425 is fixed.
+ @Suppress
+ public void testTabFinishStart() throws Exception {
+ mIntent = mTabIntent;
+ runLaunchpad(LaunchpadActivity.LIFECYCLE_FINISH_START);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java
new file mode 100644
index 0000000..3c107be
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalActivity extends TestedActivity
+{
+ public LocalActivity()
+ {
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java
new file mode 100644
index 0000000..ac235c0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+class LocalDeniedReceiver extends BroadcastReceiver {
+ public LocalDeniedReceiver() {
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(BroadcastTest.RECEIVER_LOCAL);
+ caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java
new file mode 100644
index 0000000..0473ea9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDeniedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+public class LocalDeniedService extends LocalService
+{
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java
new file mode 100644
index 0000000..3694375
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalDialog.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalDialog extends TestedScreen
+{
+ public LocalDialog()
+ {
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java
new file mode 100644
index 0000000..48f5658
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class LocalGrantedReceiver extends BroadcastReceiver {
+ public LocalGrantedReceiver() {
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(BroadcastTest.RECEIVER_LOCAL);
+ caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java
new file mode 100644
index 0000000..0dbcd00
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalGrantedService.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+public class LocalGrantedService extends LocalService
+{
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java
new file mode 100644
index 0000000..a3375bd
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalProvider.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.UriMatcher;
+import android.content.*;
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.database.sqlite.SQLiteQueryBuilder;
+import android.net.Uri;
+import android.util.Config;
+import android.util.Log;
+
+/** Simple test provider that runs in the local process. */
+public class LocalProvider extends ContentProvider {
+ private static final String TAG = "LocalProvider";
+
+ private SQLiteOpenHelper mOpenHelper;
+
+ private static final int DATA = 1;
+ private static final int DATA_ID = 2;
+ private static final UriMatcher sURLMatcher = new UriMatcher(
+ UriMatcher.NO_MATCH);
+
+ static {
+ sURLMatcher.addURI("*", "data", DATA);
+ sURLMatcher.addURI("*", "data/#", DATA_ID);
+ }
+
+ private static class DatabaseHelper extends SQLiteOpenHelper {
+ private static final String DATABASE_NAME = "local.db";
+ private static final int DATABASE_VERSION = 1;
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE data (" +
+ "_id INTEGER PRIMARY KEY," +
+ "text TEXT, " +
+ "integer INTEGER);");
+
+ // insert alarms
+ db.execSQL("INSERT INTO data (text, integer) VALUES ('first data', 100);");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int currentVersion) {
+ Log.w(TAG, "Upgrading test database from version " +
+ oldVersion + " to " + currentVersion +
+ ", which will destroy all old data");
+ db.execSQL("DROP TABLE IF EXISTS data");
+ onCreate(db);
+ }
+ }
+
+
+ public LocalProvider() {
+ }
+
+ @Override
+ public boolean onCreate() {
+ mOpenHelper = new DatabaseHelper(getContext());
+ return true;
+ }
+
+ @Override
+ public Cursor query(Uri url, String[] projectionIn, String selection,
+ String[] selectionArgs, String sort) {
+ SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
+
+ // Generate the body of the query
+ int match = sURLMatcher.match(url);
+ switch (match) {
+ case DATA:
+ qb.setTables("data");
+ break;
+ case DATA_ID:
+ qb.setTables("data");
+ qb.appendWhere("_id=");
+ qb.appendWhere(url.getPathSegments().get(1));
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown URL " + url);
+ }
+
+ SQLiteDatabase db = mOpenHelper.getReadableDatabase();
+ Cursor ret = qb.query(db, projectionIn, selection, selectionArgs,
+ null, null, sort);
+
+ if (ret == null) {
+ if (Config.LOGD) Log.d(TAG, "Alarms.query: failed");
+ } else {
+ ret.setNotificationUri(getContext().getContentResolver(), url);
+ }
+
+ return ret;
+ }
+
+ @Override
+ public String getType(Uri url) {
+ int match = sURLMatcher.match(url);
+ switch (match) {
+ case DATA:
+ return "vnd.android.cursor.dir/vnd.google.unit_tests.local";
+ case DATA_ID:
+ return "vnd.android.cursor.item/vnd.google.unit_tests.local";
+ default:
+ throw new IllegalArgumentException("Unknown URL");
+ }
+ }
+
+ @Override
+ public int update(Uri url, ContentValues values, String where, String[] whereArgs) {
+ int count;
+ long rowId = 0;
+ int match = sURLMatcher.match(url);
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ switch (match) {
+ case DATA_ID: {
+ String segment = url.getPathSegments().get(1);
+ rowId = Long.parseLong(segment);
+ count = db.update("data", values, "_id=" + rowId, null);
+ break;
+ }
+ default: {
+ throw new UnsupportedOperationException(
+ "Cannot update URL: " + url);
+ }
+ }
+ if (Config.LOGD) Log.d(TAG, "*** notifyChange() rowId: " + rowId);
+ getContext().getContentResolver().notifyChange(url, null);
+ return count;
+ }
+
+
+ @Override
+ public Uri insert(Uri url, ContentValues initialValues) {
+ return null;
+ }
+
+ @Override
+ public int delete(Uri url, String where, String[] whereArgs) {
+ throw new UnsupportedOperationException("delete not supported");
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java
new file mode 100644
index 0000000..019c5c0
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalReceiver.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ReceiverCallNotAllowedException;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class LocalReceiver extends BroadcastReceiver {
+ public LocalReceiver() {
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ String resultString = LaunchpadActivity.RECEIVER_LOCAL;
+ if (BroadcastTest.BROADCAST_FAIL_REGISTER.equals(intent.getAction())) {
+ resultString = "Successfully registered, but expected it to fail";
+ try {
+ context.registerReceiver(this, new IntentFilter("foo.bar"));
+ context.unregisterReceiver(this);
+ } catch (ReceiverCallNotAllowedException e) {
+ //resultString = "This is the correct behavior but not yet implemented";
+ resultString = LaunchpadActivity.RECEIVER_LOCAL;
+ }
+ } else if (BroadcastTest.BROADCAST_FAIL_BIND.equals(intent.getAction())) {
+ resultString = "Successfully bound to service, but expected it to fail";
+ try {
+ ServiceConnection sc = new ServiceConnection() {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ };
+ context.bindService(new Intent(context, LocalService.class), sc, 0);
+ context.unbindService(sc);
+ } catch (ReceiverCallNotAllowedException e) {
+ //resultString = "This is the correct behavior but not yet implemented";
+ resultString = LaunchpadActivity.RECEIVER_LOCAL;
+ }
+ } else if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) {
+ Intent newIntent = new Intent(intent);
+ newIntent.setAction(LaunchpadActivity.BROADCAST_LOCAL);
+ context.sendOrderedBroadcast(newIntent, null);
+ }
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(resultString);
+ caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java
new file mode 100644
index 0000000..ad65fcc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalScreen.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import java.util.Map;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+
+public class LocalScreen extends TestedScreen
+{
+ public LocalScreen()
+ {
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java
new file mode 100644
index 0000000..d79205d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/LocalService.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.util.Log;
+
+public class LocalService extends Service {
+ private final IBinder mBinder = new Binder() {
+
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply,
+ int flags) throws RemoteException {
+ if (code == ServiceTest.SET_REPORTER_CODE) {
+ data.enforceInterface(ServiceTest.SERVICE_LOCAL);
+ mReportObject = data.readStrongBinder();
+ return true;
+ } else {
+ return super.onTransact(code, data, reply, flags);
+ }
+ }
+
+ };
+
+ private IBinder mReportObject;
+ private int mStartCount = 1;
+
+ public LocalService() {
+ }
+
+ @Override
+ public void onStart(Intent intent, int startId) {
+ //Log.i("LocalService", "onStart: " + intent);
+ if (intent.getExtras() != null) {
+ mReportObject = intent.getExtras().getIBinder(ServiceTest.REPORT_OBJ_NAME);
+ if (mReportObject != null) {
+ try {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+ data.writeInt(mStartCount);
+ mStartCount++;
+ mReportObject.transact(
+ ServiceTest.STARTED_CODE, data, null, 0);
+ data.recycle();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ Log.i("LocalService", "onDestroy: mReportObject=" + mReportObject);
+ if (mReportObject != null) {
+ try {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+ mReportObject.transact(
+ ServiceTest.DESTROYED_CODE, data, null, 0);
+ data.recycle();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ Log.i("LocalService", "onBind: " + intent);
+ return mBinder;
+ }
+
+ @Override
+ public boolean onUnbind(Intent intent) {
+ Log.i("LocalService", "onUnbind: " + intent);
+ if (mReportObject != null) {
+ try {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+ mReportObject.transact(
+ ServiceTest.UNBIND_CODE, data, null, 0);
+ data.recycle();
+ } catch (RemoteException e) {
+ }
+ }
+ return true;
+ }
+
+ @Override
+ public void onRebind(Intent intent) {
+ Log.i("LocalService", "onUnbind: " + intent);
+ if (mReportObject != null) {
+ try {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(ServiceTest.SERVICE_LOCAL);
+ mReportObject.transact(
+ ServiceTest.REBIND_CODE, data, null, 0);
+ data.recycle();
+ } catch (RemoteException e) {
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java
new file mode 100644
index 0000000..4660e29
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/MetaDataTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.content.pm.PackageItemInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.content.pm.ProviderInfo;
+import android.content.pm.ServiceInfo;
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.os.Bundle;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.unit_tests.R;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+
+/**
+ * Tests for meta-data associated with application components.
+ */
+public class MetaDataTest extends AndroidTestCase {
+
+ private void checkMetaData(ComponentName cn, PackageItemInfo ci)
+ throws IOException, XmlPullParserException {
+ assertNotNull("Unable to find component " + cn, ci);
+
+ Bundle md = ci.metaData;
+ assertNotNull("No meta data found", md);
+
+ assertEquals("foo", md.getString("com.android.unit_tests.string"));
+ assertTrue(md.getBoolean("com.android.unit_tests.boolean"));
+ assertEquals(100, md.getInt("com.android.unit_tests.integer"));
+ assertEquals(0xff000000, md.getInt("com.android.unit_tests.color"));
+
+ assertEquals((double) 1001,
+ Math.floor(md.getFloat("com.android.unit_tests.float") * 10 + .5));
+
+ assertEquals(R.xml.metadata, md.getInt("com.android.unit_tests.reference"));
+
+ XmlResourceParser xml = ci.loadXmlMetaData(mContext.getPackageManager(),
+ "com.android.unit_tests.reference");
+ assertNotNull(xml);
+
+ int type;
+ while ((type = xml.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ }
+ assertEquals(XmlPullParser.START_TAG, type);
+ assertEquals("thedata", xml.getName());
+
+ // method 1: direct access
+ final String rawAttr = xml.getAttributeValue(null, "rawText");
+ assertEquals("some raw text", rawAttr);
+
+ // method 2: direct access of typed value
+ final int rawColorIntAttr = xml.getAttributeIntValue(null, "rawColor", 0);
+ assertEquals(0xffffff00, rawColorIntAttr);
+ final String rawColorStrAttr = xml.getAttributeValue(null, "rawColor");
+ assertEquals("#ffffff00", rawColorStrAttr);
+
+ // method 2: direct access of resource attribute
+ final String nameSpace = "http://schemas.android.com/apk/res/android";
+ final int colorIntAttr = xml.getAttributeIntValue(nameSpace, "color", 0);
+ assertEquals(0xffff0000, colorIntAttr);
+ final String colorStrAttr = xml.getAttributeValue(nameSpace, "color");
+ assertEquals("#ffff0000", colorStrAttr);
+
+ // method 3: styled access (borrowing an attr from view system here)
+ TypedArray a = mContext.obtainStyledAttributes(xml,
+ android.R.styleable.TextView);
+ String styledAttr = a.getString(android.R.styleable.TextView_text);
+ assertEquals("text", styledAttr);
+ a.recycle();
+
+ xml.close();
+ }
+
+ @SmallTest
+ public void testActivityWithData() throws Exception {
+ ComponentName cn = new ComponentName(mContext, LocalActivity.class);
+ ActivityInfo ai = mContext.getPackageManager().getActivityInfo(
+ cn, PackageManager.GET_META_DATA);
+
+ checkMetaData(cn, ai);
+
+ ai = mContext.getPackageManager().getActivityInfo(cn, 0);
+
+ assertNull("Meta data returned when not requested", ai.metaData);
+ }
+
+ @SmallTest
+ public void testReceiverWithData() throws Exception {
+ ComponentName cn = new ComponentName(mContext, LocalReceiver.class);
+ ActivityInfo ai = mContext.getPackageManager().getReceiverInfo(
+ cn, PackageManager.GET_META_DATA);
+
+ checkMetaData(cn, ai);
+
+ ai = mContext.getPackageManager().getReceiverInfo(cn, 0);
+
+ assertNull("Meta data returned when not requested", ai.metaData);
+ }
+
+ @SmallTest
+ public void testServiceWithData() throws Exception {
+ ComponentName cn = new ComponentName(mContext, LocalService.class);
+ ServiceInfo si = mContext.getPackageManager().getServiceInfo(
+ cn, PackageManager.GET_META_DATA);
+
+ checkMetaData(cn, si);
+
+ si = mContext.getPackageManager().getServiceInfo(cn, 0);
+
+ assertNull("Meta data returned when not requested", si.metaData);
+ }
+
+ @MediumTest
+ public void testProviderWithData() throws Exception {
+ ComponentName cn = new ComponentName(mContext, LocalProvider.class);
+ ProviderInfo pi = mContext.getPackageManager().resolveContentProvider(
+ "com.android.unit_tests.LocalProvider",
+ PackageManager.GET_META_DATA);
+ checkMetaData(cn, pi);
+
+ pi = mContext.getPackageManager().resolveContentProvider(
+ "com.android.unit_tests.LocalProvider", 0);
+
+ assertNull("Meta data returned when not requested", pi.metaData);
+ }
+
+ @SmallTest
+ public void testPermissionWithData() throws Exception {
+ ComponentName cn = new ComponentName("foo",
+ "com.android.unit_tests.permission.TEST_GRANTED");
+ PermissionInfo pi = mContext.getPackageManager().getPermissionInfo(
+ cn.getClassName(), PackageManager.GET_META_DATA);
+ checkMetaData(cn, pi);
+
+ pi = mContext.getPackageManager().getPermissionInfo(
+ cn.getClassName(), 0);
+
+ assertNull("Meta data returned when not requested", pi.metaData);
+ }
+}
+
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java
new file mode 100644
index 0000000..7656580
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteDeniedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+class RemoteDeniedReceiver extends BroadcastReceiver {
+ public RemoteDeniedReceiver() {
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(BroadcastTest.RECEIVER_REMOTE);
+ caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java
new file mode 100644
index 0000000..034aa1d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteGrantedReceiver.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class RemoteGrantedReceiver extends BroadcastReceiver {
+ public RemoteGrantedReceiver() {
+ }
+
+ public void onReceive(Context context, Intent intent) {
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(BroadcastTest.RECEIVER_REMOTE);
+ caller.transact(BroadcastTest.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java
new file mode 100644
index 0000000..818bffe
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteReceiver.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+
+public class RemoteReceiver extends BroadcastReceiver
+{
+ public RemoteReceiver()
+ {
+ }
+
+ public void onReceive(Context context, Intent intent)
+ {
+ if (LaunchpadActivity.BROADCAST_REPEAT.equals(intent.getAction())) {
+ Intent newIntent = new Intent(intent);
+ newIntent.setAction(LaunchpadActivity.BROADCAST_REMOTE);
+ context.sendOrderedBroadcast(newIntent, null);
+ }
+ try {
+ IBinder caller = intent.getIBinderExtra("caller");
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(LaunchpadActivity.LAUNCH);
+ data.writeString(LaunchpadActivity.RECEIVER_REMOTE);
+ caller.transact(LaunchpadActivity.GOT_RECEIVE_TRANSACTION, data, null, 0);
+ data.recycle();
+ } catch (RemoteException ex) {
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java
new file mode 100644
index 0000000..e750ed6
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/RemoteSubActivityScreen.java
@@ -0,0 +1,59 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/activity/TestedScreen.java
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.unit_tests.activity;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Process;
+import android.util.Log;
+
+public class RemoteSubActivityScreen extends SubActivityScreen {
+ Handler mHandler = new Handler();
+ boolean mFirst = false;
+
+ public RemoteSubActivityScreen() {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ // We are running in a remote process, so want to have the sub-activity
+ // sending the result back in the original process.
+ Intent intent = getIntent();
+ intent.setClass(this, SubActivityScreen.class);
+
+ super.onCreate(icicle);
+
+ boolean kill = intent.getBooleanExtra("kill", false);
+ //Log.i("foo", "RemoteSubActivityScreen pid=" + Process.myPid()
+ // + " kill=" + kill);
+
+ if (kill) {
+ // After finishing initialization, kill the process! But only if
+ // this is the first time...
+ if (icicle == null) {
+ mHandler.post(new Runnable() {
+ public void run() {
+ handleBeforeStopping();
+ Process.killProcess(Process.myPid());
+ }
+ });
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java
new file mode 100644
index 0000000..4b5d468
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ResultReceiver.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.BroadcastReceiver;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Bundle;
+
+import java.util.Map;
+
+public class ResultReceiver extends BroadcastReceiver
+{
+ public ResultReceiver()
+ {
+ }
+
+ public void onReceive(Context context, Intent intent)
+ {
+ setResultCode(3);
+ setResultData("bar");
+ Bundle map = getResultExtras(false);
+ map.remove("remove");
+ map.putString("bar", "them");
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java
new file mode 100644
index 0000000..db523dc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/ServiceTest.java
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+// These test binders purport to support an interface whose canonical
+// interface name is ServiceTest.SERVICE_LOCAL
+public class ServiceTest extends ActivityTestsBase {
+
+ public static final String SERVICE_LOCAL =
+ "com.android.unit_tests.activity.SERVICE_LOCAL";
+ public static final String SERVICE_LOCAL_GRANTED =
+ "com.android.unit_tests.activity.SERVICE_LOCAL_GRANTED";
+ public static final String SERVICE_LOCAL_DENIED =
+ "com.android.unit_tests.activity.SERVICE_LOCAL_DENIED";
+
+ public static final String REPORT_OBJ_NAME = "report";
+
+ public static final int STARTED_CODE = 1;
+ public static final int DESTROYED_CODE = 2;
+ public static final int SET_REPORTER_CODE = 3;
+ public static final int UNBIND_CODE = 4;
+ public static final int REBIND_CODE = 5;
+
+ public static final int STATE_START_1 = 0;
+ public static final int STATE_START_2 = 1;
+ public static final int STATE_UNBIND = 2;
+ public static final int STATE_DESTROY = 3;
+ public static final int STATE_REBIND = 4;
+ public static final int STATE_UNBIND_ONLY = 5;
+ public int mStartState;
+
+ public IBinder mStartReceiver = new Binder() {
+ @Override
+ protected boolean onTransact(int code, Parcel data, Parcel reply,
+ int flags) throws RemoteException {
+ //Log.i("ServiceTest", "Received code " + code + " in state " + mStartState);
+ if (code == STARTED_CODE) {
+ data.enforceInterface(SERVICE_LOCAL);
+ int count = data.readInt();
+ if (mStartState == STATE_START_1) {
+ if (count == 1) {
+ finishGood();
+ } else {
+ finishBad("onStart() again on an object when it should have been the first time");
+ }
+ } else if (mStartState == STATE_START_2) {
+ if (count == 2) {
+ finishGood();
+ } else {
+ finishBad("onStart() the first time on an object when it should have been the second time");
+ }
+ } else {
+ finishBad("onStart() was called when not expected (state="+mStartState+")");
+ }
+ return true;
+ } else if (code == DESTROYED_CODE) {
+ data.enforceInterface(SERVICE_LOCAL);
+ if (mStartState == STATE_DESTROY) {
+ finishGood();
+ } else {
+ finishBad("onDestroy() was called when not expected (state="+mStartState+")");
+ }
+ return true;
+ } else if (code == UNBIND_CODE) {
+ data.enforceInterface(SERVICE_LOCAL);
+ if (mStartState == STATE_UNBIND) {
+ mStartState = STATE_DESTROY;
+ } else if (mStartState == STATE_UNBIND_ONLY) {
+ finishGood();
+ } else {
+ finishBad("onUnbind() was called when not expected (state="+mStartState+")");
+ }
+ return true;
+ } else if (code == REBIND_CODE) {
+ data.enforceInterface(SERVICE_LOCAL);
+ if (mStartState == STATE_REBIND) {
+ finishGood();
+ } else {
+ finishBad("onRebind() was called when not expected (state="+mStartState+")");
+ }
+ return true;
+ } else {
+ return super.onTransact(code, data, reply, flags);
+ }
+ }
+ };
+
+ public class EmptyConnection implements ServiceConnection {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ }
+ }
+
+ public class TestConnection implements ServiceConnection {
+ private final boolean mExpectDisconnect;
+ private final boolean mSetReporter;
+ private boolean mMonitor;
+ private int mCount;
+
+ public TestConnection(boolean expectDisconnect, boolean setReporter) {
+ mExpectDisconnect = expectDisconnect;
+ mSetReporter = setReporter;
+ mMonitor = !setReporter;
+ }
+
+ void setMonitor(boolean v) {
+ mMonitor = v;
+ }
+
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (mSetReporter) {
+ Parcel data = Parcel.obtain();
+ data.writeInterfaceToken(SERVICE_LOCAL);
+ data.writeStrongBinder(mStartReceiver);
+ try {
+ service.transact(SET_REPORTER_CODE, data, null, 0);
+ } catch (RemoteException e) {
+ finishBad("DeadObjectException when sending reporting object");
+ }
+ data.recycle();
+ }
+
+ if (mMonitor) {
+ mCount++;
+ if (mStartState == STATE_START_1) {
+ if (mCount == 1) {
+ finishGood();
+ } else {
+ finishBad("onServiceConnected() again on an object when it should have been the first time");
+ }
+ } else if (mStartState == STATE_START_2) {
+ if (mCount == 2) {
+ finishGood();
+ } else {
+ finishBad("onServiceConnected() the first time on an object when it should have been the second time");
+ }
+ } else {
+ finishBad("onServiceConnected() called unexpectedly");
+ }
+ }
+ }
+
+ public void onServiceDisconnected(ComponentName name) {
+ if (mMonitor) {
+ if (mStartState == STATE_DESTROY) {
+ if (mExpectDisconnect) {
+ finishGood();
+ } else {
+ finishBad("onServiceDisconnected() when it shouldn't have been");
+ }
+ } else {
+ finishBad("onServiceDisconnected() called unexpectedly");
+ }
+ }
+ }
+ }
+
+ void startExpectResult(Intent service) {
+ startExpectResult(service, new Bundle());
+ }
+
+ void startExpectResult(Intent service, Bundle bundle) {
+ bundle.putIBinder(REPORT_OBJ_NAME, mStartReceiver);
+ boolean success = false;
+ try {
+ //Log.i("foo", "STATE_START_1");
+ mStartState = STATE_START_1;
+ getContext().startService(new Intent(service).putExtras(bundle));
+ waitForResultOrThrow(5 * 1000, "service to start first time");
+ //Log.i("foo", "STATE_START_2");
+ mStartState = STATE_START_2;
+ getContext().startService(new Intent(service).putExtras(bundle));
+ waitForResultOrThrow(5 * 1000, "service to start second time");
+ success = true;
+ } finally {
+ if (!success) {
+ try {
+ getContext().stopService(service);
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ }
+ //Log.i("foo", "STATE_DESTROY");
+ mStartState = STATE_DESTROY;
+ getContext().stopService(service);
+ waitForResultOrThrow(5 * 1000, "service to be destroyed");
+ }
+
+ void startExpectNoPermission(Intent service) {
+ try {
+ getContext().startService(service);
+ fail("Expected security exception when starting " + service);
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ void bindExpectResult(Intent service) {
+ TestConnection conn = new TestConnection(true, false);
+ TestConnection conn2 = new TestConnection(false, false);
+ boolean success = false;
+ try {
+ // Expect to see the TestConnection connected.
+ mStartState = STATE_START_1;
+ getContext().bindService(service, conn, 0);
+ getContext().startService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+ // Expect to see the second TestConnection connected.
+ getContext().bindService(service, conn2, 0);
+ waitForResultOrThrow(5 * 1000, "new connection to receive service");
+
+ getContext().unbindService(conn2);
+ success = true;
+ } finally {
+ if (!success) {
+ try {
+ getContext().stopService(service);
+ getContext().unbindService(conn);
+ getContext().unbindService(conn2);
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ }
+
+ // Expect to see the TestConnection disconnected.
+ mStartState = STATE_DESTROY;
+ getContext().stopService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+ getContext().unbindService(conn);
+
+ conn = new TestConnection(true, true);
+ success = false;
+ try {
+ // Expect to see the TestConnection connected.
+ conn.setMonitor(true);
+ mStartState = STATE_START_1;
+ getContext().bindService(service, conn, 0);
+ getContext().startService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+ success = true;
+ } finally {
+ if (!success) {
+ try {
+ getContext().stopService(service);
+ getContext().unbindService(conn);
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ }
+
+ // Expect to see the service unbind and then destroyed.
+ conn.setMonitor(false);
+ mStartState = STATE_UNBIND;
+ getContext().stopService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+ getContext().unbindService(conn);
+
+ conn = new TestConnection(true, true);
+ success = false;
+ try {
+ // Expect to see the TestConnection connected.
+ conn.setMonitor(true);
+ mStartState = STATE_START_1;
+ getContext().bindService(service, conn, 0);
+ getContext().startService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to receive service");
+
+ success = true;
+ } finally {
+ if (!success) {
+ try {
+ getContext().stopService(service);
+ getContext().unbindService(conn);
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ }
+
+ // Expect to see the service unbind but not destroyed.
+ conn.setMonitor(false);
+ mStartState = STATE_UNBIND_ONLY;
+ getContext().unbindService(conn);
+ waitForResultOrThrow(5 * 1000, "existing connection to unbind service");
+
+ // Expect to see the service rebound.
+ mStartState = STATE_REBIND;
+ getContext().bindService(service, conn, 0);
+ waitForResultOrThrow(5 * 1000, "existing connection to rebind service");
+
+ // Expect to see the service unbind and then destroyed.
+ mStartState = STATE_UNBIND;
+ getContext().stopService(service);
+ waitForResultOrThrow(5 * 1000, "existing connection to lose service");
+
+ getContext().unbindService(conn);
+ }
+
+ void bindAutoExpectResult(Intent service) {
+ TestConnection conn = new TestConnection(false, true);
+ boolean success = false;
+ try {
+ conn.setMonitor(true);
+ mStartState = STATE_START_1;
+ getContext().bindService(
+ service, conn, Context.BIND_AUTO_CREATE);
+ waitForResultOrThrow(5 * 1000, "connection to start and receive service");
+ success = true;
+ } finally {
+ if (!success) {
+ try {
+ getContext().unbindService(conn);
+ } catch (Exception e) {
+ // eat
+ }
+ }
+ }
+ mStartState = STATE_UNBIND;
+ getContext().unbindService(conn);
+ waitForResultOrThrow(5 * 1000, "disconnecting from service");
+ }
+
+ void bindExpectNoPermission(Intent service) {
+ TestConnection conn = new TestConnection(false, false);
+ try {
+ getContext().bindService(service, conn, Context.BIND_AUTO_CREATE);
+ fail("Expected security exception when binding " + service);
+ } catch (SecurityException e) {
+ // expected
+ } finally {
+ getContext().unbindService(conn);
+ }
+ }
+
+
+ @MediumTest
+ public void testLocalStartClass() throws Exception {
+ startExpectResult(new Intent(getContext(), LocalService.class));
+ }
+
+ @MediumTest
+ public void testLocalStartAction() throws Exception {
+ startExpectResult(new Intent(SERVICE_LOCAL));
+ }
+
+ @MediumTest
+ public void testLocalBindClass() throws Exception {
+ bindExpectResult(new Intent(getContext(), LocalService.class));
+ }
+
+ @MediumTest
+ public void testLocalBindAction() throws Exception {
+ bindExpectResult(new Intent(SERVICE_LOCAL));
+ }
+
+ @MediumTest
+ public void testLocalBindAutoClass() throws Exception {
+ bindAutoExpectResult(new Intent(getContext(), LocalService.class));
+ }
+
+ @MediumTest
+ public void testLocalBindAutoAction() throws Exception {
+ bindAutoExpectResult(new Intent(SERVICE_LOCAL));
+ }
+
+ @MediumTest
+ public void testLocalStartClassPermissionGranted() throws Exception {
+ startExpectResult(new Intent(getContext(), LocalGrantedService.class));
+ }
+
+ @MediumTest
+ public void testLocalStartActionPermissionGranted() throws Exception {
+ startExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+ }
+
+ @MediumTest
+ public void testLocalBindClassPermissionGranted() throws Exception {
+ bindExpectResult(new Intent(getContext(), LocalGrantedService.class));
+ }
+
+ @MediumTest
+ public void testLocalBindActionPermissionGranted() throws Exception {
+ bindExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+ }
+
+ @MediumTest
+ public void testLocalBindAutoClassPermissionGranted() throws Exception {
+ bindAutoExpectResult(new Intent(getContext(), LocalGrantedService.class));
+ }
+
+ @MediumTest
+ public void testLocalBindAutoActionPermissionGranted() throws Exception {
+ bindAutoExpectResult(new Intent(SERVICE_LOCAL_GRANTED));
+ }
+
+ @MediumTest
+ public void testLocalStartClassPermissionDenied() throws Exception {
+ startExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
+ }
+
+ @MediumTest
+ public void testLocalStartActionPermissionDenied() throws Exception {
+ startExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
+ }
+
+ @MediumTest
+ public void testLocalBindClassPermissionDenied() throws Exception {
+ bindExpectNoPermission(new Intent(getContext(), LocalDeniedService.class));
+ }
+
+ @MediumTest
+ public void testLocalBindActionPermissionDenied() throws Exception {
+ bindExpectNoPermission(new Intent(SERVICE_LOCAL_DENIED));
+ }
+
+ @MediumTest
+ public void testLocalUnbindTwice() throws Exception {
+ EmptyConnection conn = new EmptyConnection();
+ getContext().bindService(
+ new Intent(SERVICE_LOCAL_GRANTED), conn, 0);
+ getContext().unbindService(conn);
+ try {
+ getContext().unbindService(conn);
+ fail("No exception thrown on second unbind");
+ } catch (IllegalArgumentException e) {
+ //Log.i("foo", "Unbind exception", e);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java
new file mode 100644
index 0000000..1fa7579
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SetTimeZonePermissionsTest.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import java.util.TimeZone;
+
+public class SetTimeZonePermissionsTest extends AndroidTestCase {
+
+ private String[] mZones;
+ private String mCurrentZone;
+ private AlarmManager mAlarm;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mZones = TimeZone.getAvailableIDs();
+ mCurrentZone = TimeZone.getDefault().getID();
+ mAlarm = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ /**
+ * Verify that non-system processes cannot set the time zone.
+ */
+ @LargeTest
+ public void testSetTimeZonePermissions() {
+ /**
+ * Attempt to set several predefined time zones, verifying that the system
+ * system default time zone has not actually changed from its prior state
+ * after each attempt.
+ */
+ int max = (mZones.length > 10) ? mZones.length : 10;
+ assertTrue("No system-defined time zones - test invalid", max > 0);
+
+ for (int i = 0; i < max; i++) {
+ String tz = mZones[i];
+ try {
+ mAlarm.setTimeZone(tz);
+ } catch (SecurityException se) {
+ // Expected failure; no need to handle specially since we're
+ // about to assert that the test invariant holds: no change
+ // to the system time zone.
+ }
+
+ String newZone = TimeZone.getDefault().getID();
+ assertEquals("AlarmManager.setTimeZone() succeeded despite lack of permission",
+ mCurrentZone,
+ newZone);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java
new file mode 100644
index 0000000..914b909
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityScreen.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class SubActivityScreen extends Activity {
+ static final int NO_RESULT_MODE = 0;
+ static final int RESULT_MODE = 1;
+ static final int PENDING_RESULT_MODE = 2;
+ static final int FINISH_SUB_MODE = 3;
+
+ static final int CHILD_OFFSET = 1000;
+
+ int mMode;
+
+ public SubActivityScreen() {
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mMode = getIntent().getIntExtra("mode", mMode);
+ //Log.i("foo", "SubActivityScreen pid=" + Process.myPid()
+ // + " mode=" + mMode);
+
+ // Move on to the next thing that will generate a result... but only
+ // if we are being launched for the first time.
+ if (icicle == null) {
+ if (mMode == PENDING_RESULT_MODE) {
+ PendingIntent apr = createPendingResult(1, null,
+ Intent.FILL_IN_ACTION);
+ Intent res = new Intent();
+ res.putExtra("tkey", "tval");
+ res.setAction("test");
+ try {
+ apr.send(this, RESULT_OK, res);
+ } catch (PendingIntent.CanceledException e) {
+ }
+ } else if (mMode < CHILD_OFFSET) {
+ Intent intent = new Intent();
+ intent.setClass(this, SubActivityScreen.class);
+ intent.putExtra("mode", CHILD_OFFSET+mMode);
+ //System.out.println("*** Starting from onStart: " + intent);
+ startActivityForResult(intent, 1);
+ return;
+ }
+ }
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ //Log.i("foo", "SubActivityScreen pid=" + Process.myPid() + " onResume");
+
+ if (mMode >= CHILD_OFFSET) {
+ // Wait a little bit, to give our parent time to kill itself
+ // if that is something it is into.
+ try {
+ Thread.sleep(500);
+ } catch (InterruptedException e) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction("Interrupted!"));
+ finish();
+ return;
+ }
+ //System.out.println("Resuming sub-activity: mode=" + mMode);
+ switch (mMode-CHILD_OFFSET) {
+ case NO_RESULT_MODE:
+ finish();
+ break;
+ case RESULT_MODE:
+ Intent res = new Intent();
+ res.putExtra("tkey", "tval");
+ res.setAction("test");
+ setResult(RESULT_OK, res);
+ finish();
+ break;
+ case FINISH_SUB_MODE:
+ break;
+ }
+ }
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode,
+ Intent data) {
+ //Log.i("foo", "SubActivityScreen pid=" + Process.myPid()
+ // + " onActivityResult: req=" + requestCode
+ // + " res=" + resultCode);
+
+ // Assume success.
+ setResult(RESULT_OK);
+
+ if (requestCode == 1) {
+ switch (mMode) {
+ case NO_RESULT_MODE:
+ case FINISH_SUB_MODE:
+ if (resultCode != RESULT_CANCELED) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Incorrect result code returned: " + resultCode));
+ }
+ break;
+ case RESULT_MODE:
+ case PENDING_RESULT_MODE:
+ if (resultCode != RESULT_OK) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Incorrect result code returned: " + resultCode));
+ } else if (data == null) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "null data returned"));
+ } else if (!("test".equals(data.getAction()))) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Incorrect action returned: " + data));
+ } else if (!("tval".equals(data.getStringExtra("tkey")))) {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Incorrect extras returned: " + data.getExtras()));
+ }
+ break;
+ }
+ } else {
+ setResult(RESULT_CANCELED, (new Intent()).setAction(
+ "Incorrect request code returned: " + requestCode));
+ }
+
+ finish();
+ }
+
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ handleBeforeStopping();
+ }
+
+ public void handleBeforeStopping() {
+ if (mMode == FINISH_SUB_MODE) {
+ finishActivity(1);
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java
new file mode 100644
index 0000000..ee02c98
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/SubActivityTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.test.suitebuilder.annotation.Suppress;
+import android.content.ComponentName;
+
+@Suppress
+public class SubActivityTest extends ActivityTestsBase {
+
+ public void testPendingResult() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.PENDING_RESULT_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testNoResult() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testResult() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testFinishSub() throws Exception {
+ mIntent.putExtra("component",
+ new ComponentName(getContext(), RemoteSubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteNoResult() throws Exception {
+ mIntent.putExtra("component",
+ new ComponentName(getContext(), RemoteSubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteResult() throws Exception {
+ mIntent.putExtra("component",
+ new ComponentName(getContext(), RemoteSubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteFinishSub() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteRestartNoResult() throws Exception {
+ mIntent.putExtra("component",
+ new ComponentName(getContext(), RemoteSubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.NO_RESULT_MODE);
+ mIntent.putExtra("kill", true);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteRestartResult() throws Exception {
+ mIntent.putExtra("component",
+ new ComponentName(getContext(), RemoteSubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.RESULT_MODE);
+ mIntent.putExtra("kill", true);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+
+ public void testRemoteRestartFinishSub() throws Exception {
+ mIntent.putExtra("component", new ComponentName(getContext(), SubActivityScreen.class));
+ mIntent.putExtra("mode", SubActivityScreen.FINISH_SUB_MODE);
+ mIntent.putExtra("kill", true);
+ runLaunchpad(LaunchpadActivity.LAUNCH);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java
new file mode 100644
index 0000000..ec407a9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.Bundle;
+
+public class TestedActivity extends Activity
+{
+ public TestedActivity()
+ {
+ }
+
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+ }
+
+ protected void onRestoreInstanceState(Bundle state)
+ {
+ super.onRestoreInstanceState(state);
+ }
+
+ protected void onResume()
+ {
+ super.onResume();
+ Looper.myLooper().myQueue().addIdleHandler(new Idler());
+ }
+
+ protected void onSaveInstanceState(Bundle outState)
+ {
+ super.onSaveInstanceState(outState);
+ }
+
+ protected void onStop()
+ {
+ super.onStop();
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ setResult(RESULT_OK);
+ finish();
+ }
+ };
+
+ private class Idler implements MessageQueue.IdleHandler
+ {
+ public final boolean queueIdle()
+ {
+ //Message m = Message.obtain();
+ //mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+ setResult(RESULT_OK);
+ finish();
+ return false;
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java
new file mode 100644
index 0000000..4085aa9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/activity/TestedScreen.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.activity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue;
+import android.os.SystemClock;
+import android.os.Bundle;
+import android.util.Log;
+
+public class TestedScreen extends Activity
+{
+ public static final String WAIT_BEFORE_FINISH = "TestedScreen.WAIT_BEFORE_FINISH";
+ public static final String DELIVER_RESULT = "TestedScreen.DELIVER_RESULT";
+ public static final String CLEAR_TASK = "TestedScreen.CLEAR_TASK";
+
+ public TestedScreen() {
+ }
+
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "CREATE tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ if (LaunchpadActivity.FORWARD_RESULT.equals(getIntent().getAction())) {
+ Intent intent = new Intent(getIntent());
+ intent.setAction(DELIVER_RESULT);
+ intent.setFlags(Intent.FLAG_ACTIVITY_FORWARD_RESULT);
+ startActivity(intent);
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ finish();
+ } else if (DELIVER_RESULT.equals(getIntent().getAction())) {
+ setResult(RESULT_OK, (new Intent()).setAction(
+ LaunchpadActivity.RETURNED_RESULT));
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ finish();
+ } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+ if (!getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+ launchClearTask();
+ }
+ }
+ }
+
+ protected void onRestoreInstanceState(Bundle state) {
+ super.onRestoreInstanceState(state);
+ }
+
+ protected void onResume() {
+ super.onResume();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "RESUME tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ if (CLEAR_TASK.equals(getIntent().getAction())) {
+ if (getIntent().getBooleanExtra(ClearTop.WAIT_CLEAR_TASK, false)) {
+ Looper.myLooper().myQueue().addIdleHandler(new Idler());
+ }
+ } else {
+ Looper.myLooper().myQueue().addIdleHandler(new Idler());
+ }
+ }
+
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ }
+
+ protected void onStop() {
+ super.onStop();
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "STOP tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ }
+
+ private void launchClearTask() {
+ Intent intent = new Intent(getIntent()).
+ addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP).
+ setClass(this, ClearTop.class);
+ startActivity(intent);
+ }
+
+ private Handler mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (CLEAR_TASK.equals(getIntent().getAction())) {
+ launchClearTask();
+ } else {
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ setResult(RESULT_OK);
+ finish();
+ }
+ }
+ };
+
+ private class Idler implements MessageQueue.IdleHandler {
+ public final boolean queueIdle() {
+ if (WAIT_BEFORE_FINISH.equals(getIntent().getAction())) {
+ Message m = Message.obtain();
+ mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+ } else if (CLEAR_TASK.equals(getIntent().getAction())) {
+ Message m = Message.obtain();
+ mHandler.sendMessageAtTime(m, SystemClock.uptimeMillis()+1000);
+ } else {
+ if (ActivityTests.DEBUG_LIFECYCLE) Log.v("test", "Finishing tested "
+ + Integer.toHexString(System.identityHashCode(this)) + ": " + getIntent());
+ setResult(RESULT_OK);
+ finish();
+ }
+ return false;
+ }
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java
new file mode 100644
index 0000000..4d5b5e7
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ArrayTest.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class ArrayTest extends AndroidTestCase {
+ private Resources mResources;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ private void checkEntry(int resid, int index, Object res, Object expected) {
+ assertEquals("in resource 0x" + Integer.toHexString(resid)
+ + " at index " + index, expected, res);
+ }
+
+ private void checkStringArray(int resid, String[] expected) {
+ String[] res = mResources.getStringArray(resid);
+ assertEquals(res.length, expected.length);
+ for (int i=0; i<expected.length; i++) {
+ checkEntry(resid, i, res[i], expected[i]);
+ }
+ }
+
+ private void checkTextArray(int resid, String[] expected) {
+ CharSequence[] res = mResources.getTextArray(resid);
+ assertEquals(res.length, expected.length);
+ for (int i=0; i<expected.length; i++) {
+ checkEntry(resid, i, res[i], expected[i]);
+ }
+ }
+
+ private void checkIntArray(int resid, int[] expected) {
+ int[] res = mResources.getIntArray(resid);
+ assertEquals(res.length, expected.length);
+ for (int i=0; i<expected.length; i++) {
+ assertEquals("in resource 0x" + Integer.toHexString(resid)
+ + " at index " + i, expected[i], res[i]);
+ }
+ }
+
+ @SmallTest
+ public void testStrings() throws Exception {
+ checkStringArray(R.array.strings, new String[] {"zero", "1", "here"});
+ checkTextArray(R.array.strings, new String[] {"zero", "1", "here"});
+ checkStringArray(R.array.integers, new String[] {null, null, null});
+ checkTextArray(R.array.integers, new String[] {null, null, null});
+ }
+
+ @SmallTest
+ public void testIntegers() throws Exception {
+ checkIntArray(R.array.strings, new int[] {0, 0, 0});
+ checkIntArray(R.array.integers, new int[] {0, 1, 101});
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java
new file mode 100644
index 0000000..f38d062
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/AssetTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.AssetManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+public class AssetTest extends AndroidTestCase {
+ private AssetManager mAssets;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mAssets = mContext.getAssets();
+ }
+
+ public static void verifyTextAsset(InputStream is) throws IOException {
+ String expectedString = "OneTwoThreeFourFiveSixSevenEightNineTen";
+ byte[] buffer = new byte[10];
+
+ int readCount;
+ int curIndex = 0;
+ while ((readCount = is.read(buffer, 0, buffer.length)) > 0) {
+ for (int i = 0; i < readCount; i++) {
+ assertEquals("At index " + curIndex
+ + " expected " + expectedString.charAt(curIndex)
+ + " but found " + ((char) buffer[i]),
+ buffer[i], expectedString.charAt(curIndex));
+ curIndex++;
+ }
+ }
+
+ readCount = is.read(buffer, 0, buffer.length);
+ assertEquals("Reading end of buffer: expected readCount=-1 but got " + readCount,
+ -1, readCount);
+
+ readCount = is.read(buffer, buffer.length, 0);
+ assertEquals("Reading end of buffer length 0: expected readCount=0 but got " + readCount,
+ 0, readCount);
+
+ is.close();
+ }
+
+ @SmallTest
+ public void testReadToEnd() throws Exception {
+ InputStream is = mAssets.open("text.txt");
+ verifyTextAsset(is);
+ }
+
+ // XXX failing
+ public void xxtestListDir() throws Exception {
+ String[] files = mAssets.list("");
+ assertEquals(1, files.length);
+ assertEquals("test.txt", files[0]);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
new file mode 100644
index 0000000..a63885d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ConfigTest.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+import com.android.unit_tests.R;
+
+import java.util.Locale;
+
+public class ConfigTest extends AndroidTestCase {
+
+ private static void checkValue(Resources res, int resId, String expectedValue) {
+ try {
+ String actual = res.getString(resId);
+ assertNotNull("Returned wrong configuration-based simple value: expected <nothing>, got '"
+ + actual + "' from resource 0x"
+ + Integer.toHexString(resId),
+ expectedValue);
+ assertEquals("Returned wrong configuration-based simple value: expected "
+ + expectedValue + ", got '" + actual + "' from resource 0x"
+ + Integer.toHexString(resId),
+ expectedValue, actual);
+ } catch (Resources.NotFoundException e) {
+ assertNull("Resource not found for configuration-based simple value: expecting \""
+ + expectedValue + "\"",
+ expectedValue);
+ }
+ }
+
+ private static void checkValue(Resources res, int resId,
+ int[] styleable, String[] expectedValues) {
+ Resources.Theme theme = res.newTheme();
+ TypedArray sa = theme.obtainStyledAttributes(resId, styleable);
+ for (int i = 0; i < styleable.length; i++) {
+ String actual = sa.getString(i);
+ assertEquals("Returned wrong configuration-based style value: expected "
+ + expectedValues[i] + ", got '" + actual + "' from attr "
+ + i + " of resource 0x" + Integer.toHexString(resId),
+ actual, expectedValues[i]);
+ }
+ sa.recycle();
+ }
+
+ public Resources getResources(Configuration config,
+ int mcc, int mnc, int touchscreen, int keyboard, int keysHidden,
+ int navigation, int width, int height) {
+ AssetManager assmgr = new AssetManager();
+ assmgr.addAssetPath(mContext.getPackageResourcePath());
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
+ Display d = wm.getDefaultDisplay();
+ d.getMetrics(metrics);
+ config.mcc = mcc;
+ config.mnc = mnc;
+ config.touchscreen = touchscreen;
+ config.keyboard = keyboard;
+ config.keyboardHidden = keysHidden;
+ config.navigation = navigation;
+ metrics.widthPixels = width;
+ metrics.heightPixels = height;
+ return new Resources(assmgr, metrics, config);
+ }
+
+ private static void checkPair(Resources res, int[] notResIds,
+ int simpleRes, String simpleString,
+ int bagRes, String bagString) {
+ boolean willHave = true;
+ if (notResIds != null) {
+ for (int i : notResIds) {
+ if (i == simpleRes) {
+ willHave = false;
+ break;
+ }
+ }
+ }
+ checkValue(res, simpleRes, willHave ? simpleString : null);
+ checkValue(res, bagRes, R.styleable.TestConfig,
+ new String[]{willHave ? bagString : null});
+ }
+
+ private static void checkAllExcept(Resources res, int[] notResIds) {
+ checkPair(res, notResIds,
+ R.configVarying.simple_default, "only simple default",
+ R.configVarying.bag_default, "only bag default");
+ checkPair(res, notResIds,
+ R.configVarying.simple_mcc111, "only simple mcc111",
+ R.configVarying.bag_mcc111, "only bag mcc111");
+ checkPair(res, notResIds,
+ R.configVarying.simple_mnc222, "only simple mnc222",
+ R.configVarying.bag_mnc222, "only bag mnc222");
+ checkPair(res, notResIds,
+ R.configVarying.simple_xx, "only simple xx",
+ R.configVarying.bag_xx, "only bag xx");
+ checkPair(res, notResIds,
+ R.configVarying.simple_xx_rYY, "only simple xx_rYY",
+ R.configVarying.bag_xx_rYY, "only bag xx_rYY");
+ checkPair(res, notResIds,
+ R.configVarying.simple_notouch, "only simple notouch",
+ R.configVarying.bag_notouch, "only bag notouch");
+ checkPair(res, notResIds,
+ R.configVarying.simple_finger, "only simple finger",
+ R.configVarying.bag_finger, "only bag finger");
+ checkPair(res, notResIds,
+ R.configVarying.simple_stylus, "only simple stylus",
+ R.configVarying.bag_stylus, "only bag stylus");
+ checkPair(res, notResIds,
+ R.configVarying.simple_12key, "only simple 12key",
+ R.configVarying.bag_12key, "only bag 12key");
+ checkPair(res, notResIds,
+ R.configVarying.simple_320x200, "only simple 320x200",
+ R.configVarying.bag_320x200, "only bag 320x200");
+ checkPair(res, notResIds,
+ R.configVarying.simple_480x320, "only simple 480x320",
+ R.configVarying.bag_480x320, "only bag 480x320");
+ }
+
+ @SmallTest
+ public void testDefaultNavigationMethod() throws Exception {
+ assertEquals(mContext.getResources().getConfiguration().navigation,
+ Configuration.NAVIGATION_TRACKBALL);
+ }
+
+ @SmallTest
+ public void testAllConfigs() throws Exception {
+ /**
+ * Test a resource that contains a value for each possible single
+ * configuration value.
+ */
+ Configuration config = new Configuration();
+ Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple default");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag default"});
+
+ config.locale = new Locale("xx");
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple xx");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag xx"});
+
+ config.locale = new Locale("xx", "YY");
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple xx-rYY");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag xx-rYY"});
+
+ config = new Configuration();
+ res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple mcc111");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag mcc111"});
+
+ res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple mnc222");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag mnc222"});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple notouch");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag notouch"});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple finger");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag finger"});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple stylus");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag stylus"});
+
+ res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_NOKEYS, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple nokeys");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag nokeys"});
+
+ res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_QWERTY, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple qwerty");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag qwerty"});
+
+ res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple 12key");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag 12key"});
+
+ res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_YES, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple keyshidden");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag keyshidden"});
+
+ res = getResources(config, 0, 0, 0, 0, Configuration.KEYBOARDHIDDEN_NO, 0, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple keysexposed");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag keysexposed"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_NONAV, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple nonav");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag nonav"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_DPAD, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple dpad");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag dpad"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_TRACKBALL, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple trackball");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag trackball"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, Configuration.NAVIGATION_WHEEL, 0, 0);
+ checkValue(res, R.configVarying.simple, "simple wheel");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag wheel"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200);
+ checkValue(res, R.configVarying.simple, "simple 320x200");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag 320x200"});
+
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320);
+ checkValue(res, R.configVarying.simple, "simple 480x320");
+ checkValue(res, R.configVarying.bag,
+ R.styleable.TestConfig, new String[]{"bag 480x320"});
+ }
+
+ @MediumTest
+ public void testSingleConfig() throws Exception {
+ /**
+ * Test resources that contain a value for only one possible configuration
+ * value. XXX This is not yet complete.
+ */
+ Configuration config = new Configuration();
+ Resources res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY});
+
+ config.locale = new Locale("xx");
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, null);
+
+ config.locale = new Locale("xx", "YY");
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, null);
+
+ config.locale = new Locale("xx", "ZZ");
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{R.configVarying.simple_xx_rYY});
+
+ config = new Configuration();
+ res = getResources(config, 111, 0, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY});
+
+ res = getResources(config, 0, 222, 0, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_NOTOUCH, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY,
+ R.configVarying.simple_finger,
+ R.configVarying.simple_stylus});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_FINGER, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY,
+ R.configVarying.simple_notouch,
+ R.configVarying.simple_stylus});
+
+ res = getResources(config, 0, 0, Configuration.TOUCHSCREEN_STYLUS, 0, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY,
+ R.configVarying.simple_notouch,
+ R.configVarying.simple_finger});
+
+ res = getResources(config, 0, 0, 0, Configuration.KEYBOARD_12KEY, 0, 0, 0, 0);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY});
+
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 320, 200);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY,
+ R.configVarying.simple_480x320});
+
+ res = getResources(config, 0, 0, 0, 0, 0, 0, 480, 320);
+ checkAllExcept(res, new int[]{
+ R.configVarying.simple_xx,
+ R.configVarying.simple_xx_rYY,
+ R.configVarying.simple_320x200});
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java
new file mode 100644
index 0000000..80318dc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ContentTests.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import junit.framework.TestSuite;
+
+public class ContentTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(ContentTests.class.getName());
+
+ suite.addTestSuite(AssetTest.class);
+ suite.addTestSuite(IntentFilterTest.class);
+ suite.addTest(ResourceTests.suite());
+ suite.addTestSuite(PluralResourcesTest.class);
+ suite.addTestSuite(ConfigTest.class);
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java
new file mode 100644
index 0000000..74a6b8d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/FractionTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class FractionTest extends AndroidTestCase {
+
+ private Resources mResources;
+ private final TypedValue mValue = new TypedValue();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ @SmallTest
+ public void testFractions() throws Exception {
+ tryFraction(R.dimen.frac100perc, 1, 1, 1);
+ tryFraction(R.dimen.frac1perc, 1, 1, .01f);
+ tryFraction(R.dimen.fracp1perc, 1, 1, .001f);
+ tryFraction(R.dimen.fracp01perc, 1, 1, .0001f);
+ tryFraction(R.dimen.frac0perc, 1, 1, 0);
+ tryFraction(R.dimen.frac1p1perc, 1, 1, .011f);
+ tryFraction(R.dimen.frac100p1perc, 1, 1, 1.001f);
+ tryFraction(R.dimen.frac25510perc, 1, 1, 255.1f);
+ tryFraction(R.dimen.frac25610perc, 1, 1, 256.1f);
+ tryFraction(R.dimen.frac6553510perc, 1, 1, 65535.1f);
+ tryFraction(R.dimen.frac6553610perc, 1, 1, 65536.1f);
+
+ tryFraction(R.dimen.frac100perc, 100, 1, 100);
+ tryFraction(R.dimen.frac1perc, 100, 1, .01f * 100);
+ tryFraction(R.dimen.fracp1perc, 100, 1, .001f * 100);
+ tryFraction(R.dimen.fracp01perc, 100, 1, .0001f * 100);
+ tryFraction(R.dimen.frac0perc, 100, 1, 0);
+ tryFraction(R.dimen.frac1p1perc, 100, 1, .011f * 100);
+ tryFraction(R.dimen.frac100p1perc, 100, 1, 1.001f * 100);
+ tryFraction(R.dimen.frac25510perc, 100, 1, 255.1f * 100);
+ tryFraction(R.dimen.frac25610perc, 100, 1, 256.1f * 100);
+ tryFraction(R.dimen.frac6553510perc, 100, 1, 65535.1f * 100);
+ tryFraction(R.dimen.frac6553610perc, 100, 1, 65536.1f * 100);
+
+ tryFraction(R.dimen.frac100pperc, 100, 2, 2);
+ tryFraction(R.dimen.frac1pperc, 100, 2, .01f * 2);
+ tryFraction(R.dimen.fracp1pperc, 100, 2, .001f * 2);
+ tryFraction(R.dimen.fracp01pperc, 100, 2, .0001f * 2);
+ tryFraction(R.dimen.frac0pperc, 100, 2, 0);
+ tryFraction(R.dimen.frac1p1pperc, 100, 2, .011f * 2);
+ tryFraction(R.dimen.frac100p1pperc, 100, 2, 1.001f * 2);
+ tryFraction(R.dimen.frac25510pperc, 100, 2, 255.1f * 2);
+ tryFraction(R.dimen.frac25610pperc, 100, 2, 256.1f * 2);
+ tryFraction(R.dimen.frac6553510pperc, 100, 2, 65535.1f * 2);
+ tryFraction(R.dimen.frac6553610pperc, 100, 2, 65536.1f * 2);
+ }
+
+ private void tryFraction(int resid, float base, float pbase, float expected) {
+ mResources.getValue(resid, mValue, true);
+ float res = mValue.getFraction(base, pbase);
+ float diff = Math.abs(expected - res);
+ float prec = expected * 1e-4f;
+ if (prec < 1e-5f) {
+ prec = 1e-5f;
+ }
+ //System.out.println(
+ // "Res 0x" + Integer.toHexString(resid) + ": got=" + res
+ // + ", expected=" + expected + ", diff=" + diff);
+ assertFalse("Expecting value " + expected + " got " + res
+ + ": in resource 0x" + Integer.toHexString(resid)
+ + " " + mValue,
+ diff > prec);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java
new file mode 100644
index 0000000..0335b9d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/IntentFilterTest.java
@@ -0,0 +1,570 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.IntentFilter;
+import android.test.suitebuilder.annotation.SmallTest;
+import static android.os.PatternMatcher.PATTERN_LITERAL;
+import static android.os.PatternMatcher.PATTERN_PREFIX;
+import static android.os.PatternMatcher.PATTERN_SIMPLE_GLOB;
+import android.net.Uri;
+import android.util.StringBuilderPrinter;
+import junit.framework.TestCase;
+
+import java.util.HashSet;
+
+public class IntentFilterTest extends TestCase {
+
+ public static class Match extends IntentFilter {
+ Match(String[] actions, String[] categories, String[] mimeTypes,
+ String[] schemes, String[] authorities, String[] ports) {
+ if (actions != null) {
+ for (int i = 0; i < actions.length; i++) {
+ addAction(actions[i]);
+ }
+ }
+ if (categories != null) {
+ for (int i = 0; i < categories.length; i++) {
+ addCategory(categories[i]);
+ }
+ }
+ if (mimeTypes != null) {
+ for (int i = 0; i < mimeTypes.length; i++) {
+ try {
+ addDataType(mimeTypes[i]);
+ } catch (IntentFilter.MalformedMimeTypeException e) {
+ throw new RuntimeException("Bad mime type", e);
+ }
+ }
+ }
+ if (schemes != null) {
+ for (int i = 0; i < schemes.length; i++) {
+ addDataScheme(schemes[i]);
+ }
+ }
+ if (authorities != null) {
+ for (int i = 0; i < authorities.length; i++) {
+ addDataAuthority(authorities[i],
+ ports != null ? ports[i] : null);
+ }
+ }
+ }
+
+ Match(String[] actions, String[] categories, String[] mimeTypes,
+ String[] schemes, String[] authorities, String[] ports,
+ String[] paths, int[] pathTypes) {
+ this(actions, categories, mimeTypes, schemes, authorities, ports);
+ if (paths != null) {
+ for (int i = 0; i < paths.length; i++) {
+ addDataPath(paths[i], pathTypes[i]);
+ }
+ }
+ }
+ }
+
+ public static class MatchCondition {
+ public final int result;
+ public final String action;
+ public final String mimeType;
+ public final Uri data;
+ public final String[] categories;
+
+ public MatchCondition(int _result, String _action, String[] _categories,
+ String _mimeType, String _data) {
+ result = _result;
+ action = _action;
+ mimeType = _mimeType;
+ data = _data != null ? Uri.parse(_data) : null;
+ categories = _categories;
+ }
+ }
+
+ public static void checkMatches(IntentFilter filter,
+ MatchCondition[] results) {
+ for (int i = 0; i < results.length; i++) {
+ MatchCondition mc = results[i];
+ HashSet<String> categories = null;
+ if (mc.categories != null) {
+ for (int j = 0; j < mc.categories.length; j++) {
+ if (categories == null) {
+ categories = new HashSet<String>();
+ }
+ categories.add(mc.categories[j]);
+ }
+ }
+ int result = filter.match(mc.action, mc.mimeType,
+ mc.data != null ? mc.data.getScheme() : null, mc.data,
+ categories, "test");
+ if ( (result & IntentFilter.MATCH_CATEGORY_MASK)
+ != (mc.result & IntentFilter.MATCH_CATEGORY_MASK) ) {
+ StringBuilder msg = new StringBuilder();
+ msg.append("Error matching against IntentFilter:\n");
+ filter.dump(new StringBuilderPrinter(msg), " ");
+ msg.append("Match action: ");
+ msg.append(mc.action);
+ msg.append("\nMatch mimeType: ");
+ msg.append(mc.mimeType);
+ msg.append("\nMatch data: ");
+ msg.append(mc.data);
+ msg.append("\nMatch categories: ");
+ if (mc.categories != null) {
+ for (int j = 0; j < mc.categories.length; j++) {
+ if (j > 0) msg.append(", ");
+ msg.append(mc.categories[j]);
+ }
+ }
+ msg.append("\nExpected result: 0x");
+ msg.append(Integer.toHexString(mc.result));
+ msg.append(", got result: 0x");
+ msg.append(Integer.toHexString(result));
+ throw new RuntimeException(msg.toString());
+ }
+ }
+ }
+
+ @SmallTest
+ public void testActions() throws Exception {
+ IntentFilter filter = new Match(
+ new String[]{"action1"}, null, null, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1",
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action2",
+ null, null, null),
+ });
+
+ filter = new Match(
+ new String[]{"action1", "action2"},
+ null, null, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action1",
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, "action2",
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_ACTION, "action3",
+ null, null, null),
+ });
+ }
+
+ @SmallTest
+ public void testCategories() throws Exception {
+ IntentFilter filter = new Match(
+ null, new String[]{"category1"}, null, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ new String[]{"category1"}, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+ new String[]{"category2"}, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+ new String[]{"category1", "category2"}, null, null),
+ });
+
+ filter = new Match(
+ null, new String[]{"category1", "category2"}, null, null,
+ null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ new String[]{"category1"}, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ new String[]{"category2"}, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_EMPTY, null,
+ new String[]{"category1", "category2"}, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+ new String[]{"category3"}, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_CATEGORY, null,
+ new String[]{"category1", "category2", "category3"},
+ null, null),
+ });
+ }
+
+ @SmallTest
+ public void testMimeTypes() throws Exception {
+ IntentFilter filter = new Match(
+ null, null, new String[]{"which1/what1"}, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what1", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "*/*", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which2/what2", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which2/*", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which1/what2", null),
+ });
+
+ filter = new Match(null, null,
+ new String[]{"which1/what1", "which2/what2"}, null, null,
+ null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what1", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "*/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which2/what2", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which2/*", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which1/what2", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which3/what3", null),
+ });
+
+ filter = new Match(null, null,
+ new String[]{"which1/*"}, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what1", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "*/*", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which2/what2", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which2/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what2", null),
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null, null,
+ "which3/what3", null),
+ });
+
+ filter = new Match(null, null,
+ new String[]{"*/*"}, null, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_TYPE, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what1", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "*/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which2/what2", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which2/*", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which1/what2", null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_TYPE, null, null,
+ "which3/what3", null),
+ });
+ }
+
+ @SmallTest
+ public void testSchemes() throws Exception {
+ IntentFilter filter = new Match(null, null, null,
+ new String[]{"scheme1"}, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+ null, null, "scheme1:foo"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme2:foo"),
+ });
+
+ filter = new Match(null, null, null,
+ new String[]{"scheme1", "scheme2"}, null, null);
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+ null, null, "scheme1:foo"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_SCHEME, null,
+ null, null, "scheme2:foo"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme3:foo"),
+ });
+ }
+
+ @SmallTest
+ public void testAuthorities() throws Exception {
+ IntentFilter filter = new Match(null, null, null,
+ new String[]{"scheme1"},
+ new String[]{"authority1"}, new String[]{null});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1:foo"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+ null, null, "scheme1://authority1/"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority2/"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+ null, null, "scheme1://authority1:100/"),
+ });
+
+ filter = new Match(null, null, null, new String[]{"scheme1"},
+ new String[]{"authority1"}, new String[]{"100"});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1:foo"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority1/"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority2/"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null,
+ null, null, "scheme1://authority1:100/"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority1:200/"),
+ });
+
+ filter = new Match(null, null, null, new String[]{"scheme1"},
+ new String[]{"authority1", "authority2"},
+ new String[]{"100", null});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1:foo"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority1/"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_HOST, null,
+ null, null, "scheme1://authority2/"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PORT, null,
+ null, null, "scheme1://authority1:100/"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme1://authority1:200/"),
+ });
+ }
+
+ @SmallTest
+ public void testPaths() throws Exception {
+ IntentFilter filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/literal1", "/2literal"},
+ new int[]{PATTERN_LITERAL, PATTERN_LITERAL});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/literal1"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/2literal"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/literal"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/literal12"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/literal1", "/2literal"},
+ new int[]{PATTERN_PREFIX, PATTERN_PREFIX});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/literal1"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/2literal"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/literal"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/literal12"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/.*"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/literal1"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{".*"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/literal1"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a1*b"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a1b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a11b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a2b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a1bc"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a1*"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a1"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a11"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a1b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a11"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a2"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a\\.*b"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a..b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a2b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a.bc"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a.*b"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.1b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a2b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a.bc"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a.*"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.1b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a2b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.bc"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a.\\*b"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.*b"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a1*b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a2b"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a.bc"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/"),
+ });
+ filter = new Match(null, null, null,
+ new String[]{"scheme"}, new String[]{"authority"}, null,
+ new String[]{"/a.\\*"},
+ new int[]{PATTERN_SIMPLE_GLOB});
+ checkMatches(filter, new MatchCondition[]{
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, null),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/ab"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a.*"),
+ new MatchCondition(IntentFilter.MATCH_CATEGORY_PATH, null,
+ null, null, "scheme://authority/a1*"),
+ new MatchCondition(IntentFilter.NO_MATCH_DATA, null,
+ null, null, "scheme://authority/a1b"),
+ });
+ }
+
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java
new file mode 100644
index 0000000..c3d1478
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/PluralResourcesTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.AssetManager;
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import android.util.Log;
+import com.android.unit_tests.R;
+
+import junit.framework.Assert;
+
+import java.util.Locale;
+
+public class PluralResourcesTest extends AndroidTestCase {
+ private static final String TAG = "PluralResourcesTest";
+
+ private Resources mResources;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ Resources resourcesForLanguage(String lang) {
+ Configuration config = new Configuration();
+ config.updateFrom(mResources.getConfiguration());
+ config.locale = new Locale(lang);
+ return new Resources(mResources.getAssets(), mResources.getDisplayMetrics(), config);
+ }
+
+ @SmallTest
+ public void testPlurals() throws Exception {
+ CharSequence cs;
+ Resources res = resourcesForLanguage("en");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 0);
+ Log.d(TAG, "english 0 cs=" + cs);
+ Assert.assertEquals(cs.toString(), "Some dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 1);
+ Log.d(TAG, "english 1 cs=" + cs);
+ Assert.assertEquals(cs.toString(), "A dog");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 2);
+ Assert.assertEquals(cs.toString(), "Some dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 5);
+ Assert.assertEquals(cs.toString(), "Some dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 500);
+ Assert.assertEquals(cs.toString(), "Some dogs");
+ }
+
+ @SmallTest
+ public void testCzech() throws Exception {
+ CharSequence cs;
+ Resources res = resourcesForLanguage("cs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 0);
+ Log.d(TAG, "czech 0 cs=" + cs);
+ Assert.assertEquals(cs.toString(), "Some Czech dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 1);
+ Log.d(TAG, "czech 1 cs=" + cs);
+ Assert.assertEquals(cs.toString(), "A Czech dog");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 2);
+ Log.d(TAG, "czech 2 cs=" + cs);
+ Assert.assertEquals(cs.toString(), "Few Czech dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 5);
+ Assert.assertEquals(cs.toString(), "Some Czech dogs");
+
+ cs = res.getQuantityText(R.plurals.plurals_test, 500);
+ Assert.assertEquals(cs.toString(), "Some Czech dogs");
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java
new file mode 100644
index 0000000..44098cc
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/PrimitiveTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.TypedValue;
+import com.android.unit_tests.R;
+
+public class PrimitiveTest extends AndroidTestCase {
+ private Resources mResources;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ private void tryEnum(int resid, int expected) {
+ TypedArray sa =
+ mContext.obtainStyledAttributes(resid, R.styleable.EnumStyle);
+ int value = sa.getInt(R.styleable.EnumStyle_testEnum, -1);
+ sa.recycle();
+
+ assertEquals("Expecting value " + expected + " got " + value
+ + ": in resource 0x" + Integer.toHexString(resid),
+ expected, value);
+ }
+
+ @SmallTest
+ public void testEnum() throws Exception {
+ tryEnum(R.style.TestEnum1, 1);
+ tryEnum(R.style.TestEnum2, 2);
+ tryEnum(R.style.TestEnum10, 10);
+ tryEnum(R.style.TestEnum1_EmptyInherit, 1);
+ }
+
+ private void tryFlag(int resid, int expected) {
+ TypedArray sa =
+ mContext.obtainStyledAttributes(resid, R.styleable.FlagStyle);
+ int value = sa.getInt(R.styleable.FlagStyle_testFlags, -1);
+ sa.recycle();
+
+ assertEquals("Expecting value " + expected + " got " + value
+ + ": in resource 0x" + Integer.toHexString(resid),
+ expected, value);
+ }
+
+ @SmallTest
+ public void testFlags() throws Exception {
+ tryFlag(R.style.TestFlag1, 0x1);
+ tryFlag(R.style.TestFlag2, 0x2);
+ tryFlag(R.style.TestFlag31, 0x40000000);
+ tryFlag(R.style.TestFlag1And2, 0x3);
+ tryFlag(R.style.TestFlag1And2And31, 0x40000003);
+ }
+
+ private void tryBoolean(int resid, boolean expected) {
+ TypedValue v = new TypedValue();
+ mContext.getResources().getValue(resid, v, true);
+ assertEquals(TypedValue.TYPE_INT_BOOLEAN, v.type);
+ assertEquals("Expecting boolean value " + expected + " got " + v
+ + " from TypedValue: in resource 0x" + Integer.toHexString(resid),
+ expected, v.data != 0);
+ assertEquals("Expecting boolean value " + expected + " got " + v
+ + " from getBoolean(): in resource 0x" + Integer.toHexString(resid),
+ expected, mContext.getResources().getBoolean(resid));
+ }
+
+ @SmallTest
+ public void testBoolean() throws Exception {
+ tryBoolean(R.bool.trueRes, true);
+ tryBoolean(R.bool.falseRes, false);
+ }
+
+ private void tryString(int resid, String expected) {
+ TypedValue v = new TypedValue();
+ mContext.getResources().getValue(resid, v, true);
+ assertEquals(TypedValue.TYPE_STRING, v.type);
+ assertEquals("Expecting string value " + expected + " got " + v
+ + ": in resource 0x" + Integer.toHexString(resid),
+ expected, v.string);
+ }
+
+ @SmallTest
+ public void testStringCoerce() throws Exception {
+ tryString(R.string.coerceIntegerToString, "100");
+ tryString(R.string.coerceBooleanToString, "true");
+ tryString(R.string.coerceColorToString, "#fff");
+ tryString(R.string.coerceFloatToString, "100.0");
+ tryString(R.string.coerceDimensionToString, "100px");
+ tryString(R.string.coerceFractionToString, "100%");
+ }
+
+ private static void checkString(int resid, String actual, String expected) {
+ assertEquals("Expecting string value \"" + expected + "\" got \""
+ + actual + "\" in resources 0x" + Integer.toHexString(resid),
+ expected, actual);
+ }
+
+ @SmallTest
+ public void testFormattedString() throws Exception {
+ // Make sure the regular one doesn't format anything
+ checkString(R.string.formattedStringNone,
+ mResources.getString(R.string.formattedStringNone),
+ "Format[]");
+ checkString(R.string.formattedStringOne,
+ mResources.getString(R.string.formattedStringOne),
+ "Format[%d]");
+ checkString(R.string.formattedStringTwo,
+ mResources.getString(R.string.formattedStringTwo),
+ "Format[%3$d,%2$s]");
+ // Make sure the formatted one works
+ checkString(R.string.formattedStringNone,
+ mResources.getString(R.string.formattedStringNone),
+ "Format[]");
+ checkString(R.string.formattedStringOne,
+ mResources.getString(R.string.formattedStringOne, 42),
+ "Format[42]");
+ checkString(R.string.formattedStringTwo,
+ mResources.getString(R.string.formattedStringTwo, "unused", "hi", 43),
+ "Format[43,hi]");
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java
new file mode 100644
index 0000000..1786dc4
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/RawResourceTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.android.unit_tests.R;
+
+import java.io.InputStream;
+
+public class RawResourceTest extends AndroidTestCase {
+ private Resources mResources;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ }
+
+ @SmallTest
+ public void testReadToEnd() throws Exception {
+ InputStream is = mResources.openRawResource(R.raw.text);
+ AssetTest.verifyTextAsset(is);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java
new file mode 100644
index 0000000..2a56243
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceNameTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.unit_tests.R;
+
+public class ResourceNameTest extends AndroidTestCase {
+
+ @SmallTest
+ public void testGetResourceName() {
+ Resources res = mContext.getResources();
+
+ String fullName = res.getResourceName(R.configVarying.simple);
+ assertEquals("com.android.unit_tests:configVarying/simple", fullName);
+
+ String packageName = res.getResourcePackageName(R.configVarying.simple);
+ assertEquals("com.android.unit_tests", packageName);
+
+ String typeName = res.getResourceTypeName(R.configVarying.simple);
+ assertEquals("configVarying", typeName);
+
+ String entryName = res.getResourceEntryName(R.configVarying.simple);
+ assertEquals("simple", entryName);
+ }
+
+ @SmallTest
+ public void testGetResourceIdentifier() {
+ Resources res = mContext.getResources();
+ int resid = res.getIdentifier(
+ "com.android.unit_tests:configVarying/simple",
+ null, null);
+ assertEquals(R.configVarying.simple, resid);
+
+ resid = res.getIdentifier("configVarying/simple", null,
+ "com.android.unit_tests");
+ assertEquals(R.configVarying.simple, resid);
+
+ resid = res.getIdentifier("simple", "configVarying",
+ "com.android.unit_tests");
+ assertEquals(R.configVarying.simple, resid);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java
new file mode 100644
index 0000000..943941e
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/content/ResourceTests.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.content;
+
+import junit.framework.TestSuite;
+
+public class ResourceTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(ResourceTests.class.getName());
+
+ suite.addTestSuite(FractionTest.class);
+ suite.addTestSuite(PrimitiveTest.class);
+ suite.addTestSuite(ArrayTest.class);
+ suite.addTestSuite(ConfigTest.class);
+ suite.addTestSuite(RawResourceTest.class);
+ suite.addTestSuite(ResourceNameTest.class);
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java
new file mode 100644
index 0000000..e8001e34
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/BitmapTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.graphics;
+
+import android.graphics.Bitmap;
+import android.graphics.Color;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class BitmapTest extends TestCase {
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+ Bitmap bm2 = Bitmap.createBitmap(100, 200, Bitmap.Config.RGB_565);
+ Bitmap bm3 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_4444);
+
+ assertTrue("mutability", bm1.isMutable());
+ assertTrue("mutability", bm2.isMutable());
+ assertTrue("mutability", bm3.isMutable());
+
+ assertEquals("width", 100, bm1.getWidth());
+ assertEquals("width", 100, bm2.getWidth());
+ assertEquals("width", 100, bm3.getWidth());
+
+ assertEquals("rowbytes", 400, bm1.getRowBytes());
+ assertEquals("rowbytes", 200, bm2.getRowBytes());
+ assertEquals("rowbytes", 200, bm3.getRowBytes());
+
+ assertEquals("height", 200, bm1.getHeight());
+ assertEquals("height", 200, bm2.getHeight());
+ assertEquals("height", 200, bm3.getHeight());
+
+ assertTrue("hasAlpha", bm1.hasAlpha());
+ assertFalse("hasAlpha", bm2.hasAlpha());
+ assertTrue("hasAlpha", bm3.hasAlpha());
+
+ assertTrue("getConfig", bm1.getConfig() == Bitmap.Config.ARGB_8888);
+ assertTrue("getConfig", bm2.getConfig() == Bitmap.Config.RGB_565);
+ assertTrue("getConfig", bm3.getConfig() == Bitmap.Config.ARGB_4444);
+ }
+
+ @SmallTest
+ public void testMutability() throws Exception {
+ Bitmap bm1 = Bitmap.createBitmap(100, 200, Bitmap.Config.ARGB_8888);
+ Bitmap bm2 = Bitmap.createBitmap(new int[100 * 200], 100, 200,
+ Bitmap.Config.ARGB_8888);
+
+ assertTrue("mutability", bm1.isMutable());
+ assertFalse("mutability", bm2.isMutable());
+
+ bm1.eraseColor(0);
+
+ try {
+ bm2.eraseColor(0);
+ fail("eraseColor should throw exception");
+ } catch (IllegalStateException ex) {
+ // safe to catch and ignore this
+ }
+ }
+
+ @SmallTest
+ public void testGetPixelsWithAlpha() throws Exception {
+ int[] colors = new int[100];
+ for (int i = 0; i < 100; i++) {
+ colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+ }
+
+ Bitmap bm = Bitmap.createBitmap(colors, 10, 10,
+ Bitmap.Config.ARGB_8888);
+
+ int[] pixels = new int[100];
+ bm.getPixels(pixels, 0, 10, 0, 0, 10, 10);
+ for (int i = 0; i < 100; i++) {
+ int p = bm.getPixel(i % 10, i / 10);
+ assertEquals("getPixels", p, pixels[i]);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ int p = bm.getPixel(i % 10, i / 10);
+ assertEquals("getPixel", p, colors[i]);
+ assertEquals("pixel value", p,
+ ((0xFF << 24) | (i << 16) | (i << 8) | i));
+ }
+
+ }
+
+ @SmallTest
+ public void testGetPixelsWithoutAlpha() throws Exception {
+ int[] colors = new int[100];
+ for (int i = 0; i < 100; i++) {
+ colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+ }
+
+ Bitmap bm = Bitmap.createBitmap(colors, 10, 10, Bitmap.Config.RGB_565);
+
+ int[] pixels = new int[100];
+ bm.getPixels(pixels, 0, 10, 0, 0, 10, 10);
+ for (int i = 0; i < 100; i++) {
+ int p = bm.getPixel(i % 10, i / 10);
+ assertEquals("getPixels", p, pixels[i]);
+ }
+ }
+
+ @SmallTest
+ public void testSetPixelsWithAlpha() throws Exception {
+ int[] colors = new int[100];
+ for (int i = 0; i < 100; i++) {
+ colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+ }
+
+ Bitmap.Config config = Bitmap.Config.ARGB_8888;
+ Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config);
+ Bitmap bm2 = Bitmap.createBitmap(10, 10, config);
+
+ for (int i = 0; i < 100; i++) {
+ bm2.setPixel(i % 10, i / 10, colors[i]);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals("setPixel",
+ bm1.getPixel(i % 10, i / 10), bm2.getPixel(i % 10, i / 10));
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals("setPixel value",
+ bm1.getPixel(i % 10, i / 10), colors[i]);
+ }
+ }
+
+ @SmallTest
+ public void testSetPixelsWithoutAlpha() throws Exception {
+ int[] colors = new int[100];
+ for (int i = 0; i < 100; i++) {
+ colors[i] = (0xFF << 24) | (i << 16) | (i << 8) | i;
+ }
+
+ Bitmap.Config config = Bitmap.Config.RGB_565;
+ Bitmap bm1 = Bitmap.createBitmap(colors, 10, 10, config);
+ Bitmap bm2 = Bitmap.createBitmap(10, 10, config);
+
+ for (int i = 0; i < 100; i++) {
+ bm2.setPixel(i % 10, i / 10, colors[i]);
+ }
+
+ for (int i = 0; i < 100; i++) {
+ assertEquals("setPixel", bm1.getPixel(i % 10, i / 10),
+ bm2.getPixel(i % 10, i / 10));
+ }
+ }
+
+ private static int computePrePostMul(int alpha, int comp) {
+ if (alpha == 0) {
+ return 0;
+ }
+ int premul = Math.round(alpha * comp / 255.f);
+ int unpre = Math.round(255.0f * premul / alpha);
+ return unpre;
+ }
+
+ @SmallTest
+ public void testSetPixelsWithNonOpaqueAlpha() throws Exception {
+ int[] colors = new int[256];
+ for (int i = 0; i < 256; i++) {
+ colors[i] = (i << 24) | (0xFF << 16) | (0x80 << 8) | 0;
+ }
+
+ Bitmap.Config config = Bitmap.Config.ARGB_8888;
+
+ // create a bitmap with the color array specified
+ Bitmap bm1 = Bitmap.createBitmap(colors, 16, 16, config);
+
+ // create a bitmap with no colors, but then call setPixels
+ Bitmap bm2 = Bitmap.createBitmap(16, 16, config);
+ bm2.setPixels(colors, 0, 16, 0, 0, 16, 16);
+
+ // now check that we did a good job returning the unpremultiplied alpha
+ final int tolerance = 1;
+ for (int i = 0; i < 256; i++) {
+ int c0 = colors[i];
+ int c1 = bm1.getPixel(i % 16, i / 16);
+ int c2 = bm2.getPixel(i % 16, i / 16);
+
+ // these two should always be identical
+ assertEquals("getPixel", c1, c2);
+
+ // comparing the original (c0) with the returned color is tricky,
+ // since it gets premultiplied during the set(), and unpremultiplied
+ // by the get().
+ int a0 = Color.alpha(c0);
+ int a1 = Color.alpha(c1);
+ assertEquals("alpha", a0, a1);
+
+ int r0 = Color.red(c0);
+ int r1 = Color.red(c1);
+ int rr = computePrePostMul(a0, r0);
+ assertTrue("red", Math.abs(rr - r1) <= tolerance);
+
+ int g0 = Color.green(c0);
+ int g1 = Color.green(c1);
+ int gg = computePrePostMul(a0, g0);
+ assertTrue("green", Math.abs(gg - g1) <= tolerance);
+
+ int b0 = Color.blue(c0);
+ int b1 = Color.blue(c1);
+ int bb = computePrePostMul(a0, b0);
+ assertTrue("blue", Math.abs(bb - b1) <= tolerance);
+
+ if (false) {
+ int cc = Color.argb(a0, rr, gg, bb);
+ android.util.Log.d("skia", "original " + Integer.toHexString(c0) +
+ " set+get " + Integer.toHexString(c1) +
+ " local " + Integer.toHexString(cc));
+ }
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java
new file mode 100644
index 0000000..a8b6b9a
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/GraphicsTests.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.graphics;
+
+import junit.framework.TestSuite;
+
+public class GraphicsTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(GraphicsTests.class.getName());
+
+ suite.addTestSuite(BitmapTest.class);
+ suite.addTestSuite(TypefaceTest.class);
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java
new file mode 100644
index 0000000..5c40e6f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/graphics/TypefaceTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.graphics;
+
+import android.graphics.Paint;
+import android.graphics.Typeface;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+
+public class TypefaceTest extends TestCase {
+
+ // create array of all std faces
+ private final Typeface[] mFaces = new Typeface[] {
+ Typeface.create(Typeface.SANS_SERIF, 0),
+ Typeface.create(Typeface.SANS_SERIF, 1),
+ Typeface.create(Typeface.SERIF, 0),
+ Typeface.create(Typeface.SERIF, 1),
+ Typeface.create(Typeface.SERIF, 2),
+ Typeface.create(Typeface.SERIF, 3),
+ Typeface.create(Typeface.MONOSPACE, 0)
+ };
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ assertTrue("basic", Typeface.DEFAULT != null);
+ assertTrue("basic", Typeface.DEFAULT_BOLD != null);
+ assertTrue("basic", Typeface.SANS_SERIF != null);
+ assertTrue("basic", Typeface.SERIF != null);
+ assertTrue("basic", Typeface.MONOSPACE != null);
+ }
+
+ @SmallTest
+ public void testUnique() throws Exception {
+ final int n = mFaces.length;
+ for (int i = 0; i < n; i++) {
+ for (int j = i + 1; j < n; j++) {
+ assertTrue("unique", mFaces[i] != mFaces[j]);
+ }
+ }
+ }
+
+ @SmallTest
+ public void testStyles() throws Exception {
+ assertTrue("style", mFaces[0].getStyle() == Typeface.NORMAL);
+ assertTrue("style", mFaces[1].getStyle() == Typeface.BOLD);
+ assertTrue("style", mFaces[2].getStyle() == Typeface.NORMAL);
+ assertTrue("style", mFaces[3].getStyle() == Typeface.BOLD);
+ assertTrue("style", mFaces[4].getStyle() == Typeface.ITALIC);
+ assertTrue("style", mFaces[5].getStyle() == Typeface.BOLD_ITALIC);
+ assertTrue("style", mFaces[6].getStyle() == Typeface.NORMAL);
+ }
+
+ @MediumTest
+ public void testUniformY() throws Exception {
+ Paint p = new Paint();
+ final int n = mFaces.length;
+ for (int i = 1; i <= 36; i++) {
+ p.setTextSize(i);
+ float ascent = 0;
+ float descent = 0;
+ for (int j = 0; j < n; j++) {
+ p.setTypeface(mFaces[j]);
+ Paint.FontMetrics fm = p.getFontMetrics();
+ if (j == 0) {
+ ascent = fm.ascent;
+ descent = fm.descent;
+ } else {
+ assertTrue("fontMetrics", fm.ascent == ascent);
+ assertTrue("fontMetrics", fm.descent == descent);
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl
new file mode 100644
index 0000000..62c75a5
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.aidl
@@ -0,0 +1,20 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/AidlTest.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.unit_tests.os;
+
+parcelable AidlTest.TestParcelable;
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java
new file mode 100644
index 0000000..52e666d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/AidlTest.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.IInterface;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.test.suitebuilder.annotation.SmallTest;
+import com.google.android.collect.Lists;
+import junit.framework.TestCase;
+
+import java.util.List;
+
+public class AidlTest extends TestCase {
+
+ private IAidlTest mRemote;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ AidlObject mLocal = new AidlObject();
+ mRemote = IAidlTest.Stub.asInterface(mLocal);
+ }
+
+ private static boolean check(TestParcelable p, int n, String s) {
+ return p.mAnInt == n &&
+ ((s == null && p.mAString == null) || s.equals(p.mAString));
+ }
+
+ public static class TestParcelable implements Parcelable {
+ public int mAnInt;
+ public String mAString;
+
+ public TestParcelable() {
+ }
+
+ public TestParcelable(int i, String s) {
+ mAnInt = i;
+ mAString = s;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeInt(mAnInt);
+ parcel.writeString(mAString);
+ }
+
+ public void readFromParcel(Parcel parcel) {
+ mAnInt = parcel.readInt();
+ mAString = parcel.readString();
+ }
+
+ public static final Parcelable.Creator<TestParcelable> CREATOR
+ = new Parcelable.Creator<TestParcelable>() {
+ public TestParcelable createFromParcel(Parcel parcel) {
+ return new TestParcelable(parcel.readInt(),
+ parcel.readString());
+ }
+
+ public TestParcelable[] newArray(int size) {
+ return new TestParcelable[size];
+ }
+ };
+
+ public String toString() {
+ return super.toString() + " {" + mAnInt + "/" + mAString + "}";
+ }
+ }
+
+ private static class AidlObject extends IAidlTest.Stub {
+ public IInterface queryLocalInterface(String descriptor) {
+ // overriding this to return null makes asInterface always
+ // generate a proxy
+ return null;
+ }
+
+ public int intMethod(int a) {
+ return a;
+ }
+
+ public TestParcelable parcelableIn(TestParcelable p) {
+ p.mAnInt++;
+ return p;
+ }
+
+ public TestParcelable parcelableOut(TestParcelable p) {
+ p.mAnInt = 44;
+ return p;
+ }
+
+ public TestParcelable parcelableInOut(TestParcelable p) {
+ p.mAnInt++;
+ return p;
+ }
+
+ public TestParcelable listParcelableLonger(List<TestParcelable> list, int index) {
+ list.add(list.get(index));
+ return list.get(index);
+ }
+
+ public int listParcelableShorter(List<TestParcelable> list, int index) {
+ list.remove(index);
+ return list.size();
+ }
+
+ public boolean[] booleanArray(boolean[] a0, boolean[] a1, boolean[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public char[] charArray(char[] a0, char[] a1, char[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public int[] intArray(int[] a0, int[] a1, int[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public long[] longArray(long[] a0, long[] a1, long[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public float[] floatArray(float[] a0, float[] a1, float[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public double[] doubleArray(double[] a0, double[] a1, double[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public String[] stringArray(String[] a0, String[] a1, String[] a2) {
+ for (int i = 0; i < a0.length && i < a2.length; i++) {
+ a2[i] = a0[i];
+ }
+ for (int i = 0; i < a0.length && i < a1.length; i++) {
+ a1[i] = a0[i];
+ }
+ return a0;
+ }
+
+ public TestParcelable[] parcelableArray(TestParcelable[] a0,
+ TestParcelable[] a1, TestParcelable[] a2) {
+ return null;
+ }
+
+ public void voidSecurityException() {
+ throw new SecurityException("gotcha!");
+ }
+
+ public int intSecurityException() {
+ throw new SecurityException("gotcha!");
+ }
+ }
+
+ @SmallTest
+ public void testInt() throws Exception {
+ int result = mRemote.intMethod(42);
+ assertEquals(42, result);
+ }
+
+ @SmallTest
+ public void testParcelableIn() throws Exception {
+ TestParcelable arg = new TestParcelable(43, "hi");
+ TestParcelable result = mRemote.parcelableIn(arg);
+ assertNotSame(arg, result);
+
+ assertEquals(43, arg.mAnInt);
+ assertEquals(44, result.mAnInt);
+ }
+
+ @SmallTest
+ public void testParcelableOut() throws Exception {
+ TestParcelable arg = new TestParcelable(43, "hi");
+ TestParcelable result = mRemote.parcelableOut(arg);
+ assertNotSame(arg, result);
+ assertEquals(44, arg.mAnInt);
+ }
+
+ @SmallTest
+ public void testParcelableInOut() throws Exception {
+ TestParcelable arg = new TestParcelable(43, "hi");
+ TestParcelable result = mRemote.parcelableInOut(arg);
+ assertNotSame(arg, result);
+ assertEquals(44, arg.mAnInt);
+ }
+
+ @SmallTest
+ public void testListParcelableLonger() throws Exception {
+ List<TestParcelable> list = Lists.newArrayList();
+ list.add(new TestParcelable(33, "asdf"));
+ list.add(new TestParcelable(34, "jkl;"));
+
+ TestParcelable result = mRemote.listParcelableLonger(list, 1);
+
+// System.out.println("result=" + result);
+// for (TestParcelable p : list) {
+// System.out.println("longer: " + p);
+// }
+
+ assertEquals("jkl;", result.mAString);
+ assertEquals(34, result.mAnInt);
+
+ assertEquals(3, list.size());
+ assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf"));
+ assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;"));
+ assertTrue("out parameter 2: " + list.get(2), check(list.get(2), 34, "jkl;"));
+
+ assertNotSame(list.get(1), list.get(2));
+ }
+
+ @SmallTest
+ public void testListParcelableShorter() throws Exception {
+ List<TestParcelable> list = Lists.newArrayList();
+ list.add(new TestParcelable(33, "asdf"));
+ list.add(new TestParcelable(34, "jkl;"));
+ list.add(new TestParcelable(35, "qwerty"));
+
+ int result = mRemote.listParcelableShorter(list, 2);
+
+// System.out.println("result=" + result);
+// for (TestParcelable p : list) {
+// System.out.println("shorter: " + p);
+// }
+
+ assertEquals(2, result);
+ assertEquals(2, list.size());
+ assertTrue("out parameter 0: " + list.get(0), check(list.get(0), 33, "asdf"));
+ assertTrue("out parameter 1: " + list.get(1), check(list.get(1), 34, "jkl;"));
+
+ assertNotSame(list.get(0), list.get(1));
+ }
+
+ @SmallTest
+ public void testArrays() throws Exception {
+ // boolean
+ boolean[] b0 = new boolean[]{true};
+ boolean[] b1 = new boolean[]{false, true};
+ boolean[] b2 = new boolean[]{true, false, true};
+ boolean[] br = mRemote.booleanArray(b0, b1, b2);
+
+ assertEquals(1, br.length);
+ assertTrue(br[0]);
+
+ assertTrue(b1[0]);
+ assertFalse(b1[1]);
+
+ assertTrue(b2[0]);
+ assertFalse(b2[1]);
+ assertTrue(b2[2]);
+
+ // char
+ char[] c0 = new char[]{'a'};
+ char[] c1 = new char[]{'b', 'c'};
+ char[] c2 = new char[]{'d', 'e', 'f'};
+ char[] cr = mRemote.charArray(c0, c1, c2);
+
+ assertEquals(1, cr.length);
+ assertEquals('a', cr[0]);
+
+ assertEquals('a', c1[0]);
+ assertEquals('\0', c1[1]);
+
+ assertEquals('a', c2[0]);
+ assertEquals('e', c2[1]);
+ assertEquals('f', c2[2]);
+
+ // int
+ int[] i0 = new int[]{34};
+ int[] i1 = new int[]{38, 39};
+ int[] i2 = new int[]{42, 43, 44};
+ int[] ir = mRemote.intArray(i0, i1, i2);
+
+ assertEquals(1, ir.length);
+ assertEquals(34, ir[0]);
+
+ assertEquals(34, i1[0]);
+ assertEquals(0, i1[1]);
+
+ assertEquals(34, i2[0]);
+ assertEquals(43, i2[1]);
+ assertEquals(44, i2[2]);
+
+ // long
+ long[] l0 = new long[]{50};
+ long[] l1 = new long[]{51, 52};
+ long[] l2 = new long[]{53, 54, 55};
+ long[] lr = mRemote.longArray(l0, l1, l2);
+
+ assertEquals(1, lr.length);
+ assertEquals(50, lr[0]);
+
+ assertEquals(50, l1[0]);
+ assertEquals(0, l1[1]);
+
+ assertEquals(50, l2[0]);
+ assertEquals(54, l2[1]);
+ assertEquals(55, l2[2]);
+
+ // float
+ float[] f0 = new float[]{90.1f};
+ float[] f1 = new float[]{90.2f, 90.3f};
+ float[] f2 = new float[]{90.4f, 90.5f, 90.6f};
+ float[] fr = mRemote.floatArray(f0, f1, f2);
+
+ assertEquals(1, fr.length);
+ assertEquals(90.1f, fr[0]);
+
+ assertEquals(90.1f, f1[0]);
+ assertEquals(0f, f1[1], 0.0f);
+
+ assertEquals(90.1f, f2[0]);
+ assertEquals(90.5f, f2[1]);
+ assertEquals(90.6f, f2[2]);
+
+ // double
+ double[] d0 = new double[]{100.1};
+ double[] d1 = new double[]{100.2, 100.3};
+ double[] d2 = new double[]{100.4, 100.5, 100.6};
+ double[] dr = mRemote.doubleArray(d0, d1, d2);
+
+ assertEquals(1, dr.length);
+ assertEquals(100.1, dr[0]);
+
+ assertEquals(100.1, d1[0]);
+ assertEquals(0, d1[1], 0.0);
+
+ assertEquals(100.1, d2[0]);
+ assertEquals(100.5, d2[1]);
+ assertEquals(100.6, d2[2]);
+
+ // String
+ String[] s0 = new String[]{"s0[0]"};
+ String[] s1 = new String[]{"s1[0]", "s1[1]"};
+ String[] s2 = new String[]{"s2[0]", "s2[1]", "s2[2]"};
+ String[] sr = mRemote.stringArray(s0, s1, s2);
+
+ assertEquals(1, sr.length);
+ assertEquals("s0[0]", sr[0]);
+
+ assertEquals("s0[0]", s1[0]);
+ assertNull(s1[1]);
+
+ assertEquals("s0[0]", s2[0]);
+ assertEquals("s2[1]", s2[1]);
+ assertEquals("s2[2]", s2[2]);
+ }
+
+ @SmallTest
+ public void testVoidSecurityException() throws Exception {
+ boolean good = false;
+ try {
+ mRemote.voidSecurityException();
+ } catch (SecurityException e) {
+ good = true;
+ }
+ assertEquals(good, true);
+ }
+
+ @SmallTest
+ public void testIntSecurityException() throws Exception {
+ boolean good = false;
+ try {
+ mRemote.intSecurityException();
+ } catch (SecurityException e) {
+ good = true;
+ }
+ assertEquals(good, true);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java
new file mode 100644
index 0000000..0df1653
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/BroadcasterTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.Broadcaster;
+import android.os.Handler;
+import android.os.Message;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+public class BroadcasterTest extends TestCase {
+ private static final int MESSAGE_A = 23234;
+ private static final int MESSAGE_B = 3;
+ private static final int MESSAGE_C = 14;
+ private static final int MESSAGE_D = 95;
+
+ @MediumTest
+ public void test1() throws Exception {
+ /*
+ * One handler requestes one message, with a translation
+ */
+ HandlerTester tester = new HandlerTester() {
+ Handler h;
+
+ public void go() {
+ Broadcaster b = new Broadcaster();
+ h = new H();
+
+ b.request(MESSAGE_A, h, MESSAGE_B);
+
+ Message msg = new Message();
+ msg.what = MESSAGE_A;
+
+ b.broadcast(msg);
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == MESSAGE_B) {
+ success();
+ } else {
+ failure();
+ }
+ }
+ };
+ tester.doTest(1000);
+ }
+
+ private static class Tests2and3 extends HandlerTester {
+ Tests2and3(int n) {
+ N = n;
+ }
+
+ int N;
+ Handler mHandlers[];
+ boolean mSuccess[];
+
+ public void go() {
+ Broadcaster b = new Broadcaster();
+ mHandlers = new Handler[N];
+ mSuccess = new boolean[N];
+ for (int i = 0; i < N; i++) {
+ mHandlers[i] = new H();
+ mSuccess[i] = false;
+ b.request(MESSAGE_A, mHandlers[i], MESSAGE_B + i);
+ }
+
+ Message msg = new Message();
+ msg.what = MESSAGE_A;
+
+ b.broadcast(msg);
+ }
+
+ public void handleMessage(Message msg) {
+ int index = msg.what - MESSAGE_B;
+ if (index < 0 || index >= N) {
+ failure();
+ } else {
+ if (msg.getTarget() == mHandlers[index]) {
+ mSuccess[index] = true;
+ }
+ }
+ boolean winner = true;
+ for (int i = 0; i < N; i++) {
+ if (!mSuccess[i]) {
+ winner = false;
+ }
+ }
+ if (winner) {
+ success();
+ }
+ }
+ }
+
+ @MediumTest
+ public void test2() throws Exception {
+ /*
+ * 2 handlers request the same message, with different translations
+ */
+ HandlerTester tester = new Tests2and3(2);
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void test3() throws Exception {
+ /*
+ * 1000 handlers request the same message, with different translations
+ */
+ HandlerTester tester = new Tests2and3(10);
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void test4() throws Exception {
+ /*
+ * Two handlers request different messages, with translations, sending
+ * only one. The other one should never get sent.
+ */
+ HandlerTester tester = new HandlerTester() {
+ Handler h1;
+ Handler h2;
+
+ public void go() {
+ Broadcaster b = new Broadcaster();
+ h1 = new H();
+ h2 = new H();
+
+ b.request(MESSAGE_A, h1, MESSAGE_C);
+ b.request(MESSAGE_B, h2, MESSAGE_D);
+
+ Message msg = new Message();
+ msg.what = MESSAGE_A;
+
+ b.broadcast(msg);
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == MESSAGE_C && msg.getTarget() == h1) {
+ success();
+ } else {
+ failure();
+ }
+ }
+ };
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void test5() throws Exception {
+ /*
+ * Two handlers request different messages, with translations, sending
+ * only one. The other one should never get sent.
+ */
+ HandlerTester tester = new HandlerTester() {
+ Handler h1;
+ Handler h2;
+
+ public void go() {
+ Broadcaster b = new Broadcaster();
+ h1 = new H();
+ h2 = new H();
+
+ b.request(MESSAGE_A, h1, MESSAGE_C);
+ b.request(MESSAGE_B, h2, MESSAGE_D);
+
+ Message msg = new Message();
+ msg.what = MESSAGE_B;
+
+ b.broadcast(msg);
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == MESSAGE_D && msg.getTarget() == h2) {
+ success();
+ } else {
+ failure();
+ }
+ }
+ };
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void test6() throws Exception {
+ /*
+ * Two handlers request same message. Cancel the request for the
+ * 2nd handler, make sure the first still works.
+ */
+ HandlerTester tester = new HandlerTester() {
+ Handler h1;
+ Handler h2;
+
+ public void go() {
+ Broadcaster b = new Broadcaster();
+ h1 = new H();
+ h2 = new H();
+
+ b.request(MESSAGE_A, h1, MESSAGE_C);
+ b.request(MESSAGE_A, h2, MESSAGE_D);
+ b.cancelRequest(MESSAGE_A, h2, MESSAGE_D);
+
+ Message msg = new Message();
+ msg.what = MESSAGE_A;
+
+ b.broadcast(msg);
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == MESSAGE_C && msg.getTarget() == h1) {
+ success();
+ } else {
+ failure();
+ }
+ }
+ };
+ tester.doTest(1000);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
new file mode 100644
index 0000000..a504cd3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileObserverTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Maps;
+
+import android.os.FileObserver;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+public class FileObserverTest extends AndroidTestCase {
+ private Observer mObserver;
+ private File mTestFile;
+
+ private static class Observer extends FileObserver {
+ public List<Map> events = Lists.newArrayList();
+ public int totalEvents = 0;
+
+ public Observer(String path) {
+ super(path);
+ }
+
+ public void onEvent(int event, String path) {
+ synchronized (this) {
+ totalEvents++;
+ Map<String, Object> map = Maps.newHashMap();
+
+ map.put("event", event);
+ map.put("path", path);
+
+ events.add(map);
+
+ this.notifyAll();
+ }
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ mTestFile = File.createTempFile(".file_observer_test", ".txt");
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mTestFile != null && mTestFile.exists()) {
+ mTestFile.delete();
+ }
+ }
+
+ @LargeTest
+ public void testRun() throws Exception {
+ // make file changes and wait for them
+ assertTrue(mTestFile.exists());
+ assertNotNull(mTestFile.getParent());
+
+ mObserver = new Observer(mTestFile.getParent());
+ mObserver.startWatching();
+
+ FileOutputStream out = new FileOutputStream(mTestFile);
+ try {
+ out.write(0x20);
+ waitForEvent(); // open
+ waitForEvent(); // modify
+
+ mTestFile.delete();
+ waitForEvent(); // delete
+
+ mObserver.stopWatching();
+
+ // Ensure that we have seen at least 3 events.
+ assertTrue(mObserver.totalEvents > 3);
+ } finally {
+ out.close();
+ }
+ }
+
+ private void waitForEvent() {
+ synchronized (mObserver) {
+ boolean done = false;
+ while (!done) {
+ try {
+ mObserver.wait(2000);
+ done = true;
+ } catch (InterruptedException e) {
+ }
+ }
+
+ Iterator<Map> it = mObserver.events.iterator();
+
+ while (it.hasNext()) {
+ Map map = it.next();
+ Log.i("FileObserverTest", "event: " + map.get("event").toString() + " path: " + map.get("path"));
+ }
+
+ mObserver.events.clear();
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java
new file mode 100644
index 0000000..f2c9293
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/FileUtilsTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.content.Context;
+import android.os.FileUtils;
+import android.os.FileUtils.FileStatus;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import junit.framework.Assert;
+
+public class FileUtilsTest extends AndroidTestCase {
+ private static final String TEST_DATA =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+ private File mTestFile;
+ private File mCopyFile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ File testDir = getContext().getDir("testing", Context.MODE_PRIVATE);
+ mTestFile = new File(testDir, "test.file");
+ mCopyFile = new File(testDir, "copy.file");
+ FileWriter writer = new FileWriter(mTestFile);
+ try {
+ writer.write(TEST_DATA, 0, TEST_DATA.length());
+ } finally {
+ writer.close();
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mTestFile.exists()) mTestFile.delete();
+ if (mCopyFile.exists()) mCopyFile.delete();
+ }
+
+ @LargeTest
+ public void testGetFileStatus() {
+ final byte[] MAGIC = { 0xB, 0xE, 0x0, 0x5 };
+
+ try {
+ // truncate test file and write MAGIC (4 bytes) to it.
+ FileOutputStream os = new FileOutputStream(mTestFile, false);
+ os.write(MAGIC, 0, 4);
+ os.flush();
+ os.close();
+ } catch (FileNotFoundException e) {
+ Assert.fail("File was removed durning test" + e);
+ } catch (IOException e) {
+ Assert.fail("Unexpected IOException: " + e);
+ }
+
+ Assert.assertTrue(mTestFile.exists());
+ Assert.assertTrue(FileUtils.getFileStatus(mTestFile.getPath(), null));
+
+ FileStatus status1 = new FileStatus();
+ FileUtils.getFileStatus(mTestFile.getPath(), status1);
+
+ Assert.assertEquals(4, status1.size);
+
+ // Sleep for at least one second so that the modification time will be different.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) {
+ }
+
+ try {
+ // append so we don't change the creation time.
+ FileOutputStream os = new FileOutputStream(mTestFile, true);
+ os.write(MAGIC, 0, 4);
+ os.flush();
+ os.close();
+ } catch (FileNotFoundException e) {
+ Assert.fail("File was removed durning test" + e);
+ } catch (IOException e) {
+ Assert.fail("Unexpected IOException: " + e);
+ }
+
+ FileStatus status2 = new FileStatus();
+ FileUtils.getFileStatus(mTestFile.getPath(), status2);
+
+ Assert.assertEquals(8, status2.size);
+ Assert.assertTrue(status2.mtime > status1.mtime);
+
+ mTestFile.delete();
+
+ Assert.assertFalse(mTestFile.exists());
+ Assert.assertFalse(FileUtils.getFileStatus(mTestFile.getPath(), null));
+ }
+
+ // TODO: test setPermissions(), getPermissions()
+
+ @MediumTest
+ public void testCopyFile() throws Exception {
+ assertFalse(mCopyFile.exists());
+ FileUtils.copyFile(mTestFile, mCopyFile);
+ assertTrue(mCopyFile.exists());
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mCopyFile, 0, null));
+ }
+
+ @MediumTest
+ public void testCopyToFile() throws Exception {
+ final String s = "Foo Bar";
+ assertFalse(mCopyFile.exists());
+ FileUtils.copyToFile(new ByteArrayInputStream(s.getBytes()), mCopyFile); assertTrue(mCopyFile.exists());
+ assertEquals(s, FileUtils.readTextFile(mCopyFile, 0, null));
+ }
+
+ @MediumTest
+ public void testIsFilenameSafe() throws Exception {
+ assertTrue(FileUtils.isFilenameSafe(new File("foobar")));
+ assertTrue(FileUtils.isFilenameSafe(new File("a_b-c=d.e/0,1+23")));
+ assertFalse(FileUtils.isFilenameSafe(new File("foo*bar")));
+ assertFalse(FileUtils.isFilenameSafe(new File("foo\nbar")));
+ }
+
+ @MediumTest
+ public void testReadTextFile() throws Exception {
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 0, null));
+
+ assertEquals("ABCDE", FileUtils.readTextFile(mTestFile, 5, null));
+ assertEquals("ABCDE<>", FileUtils.readTextFile(mTestFile, 5, "<>"));
+ assertEquals(TEST_DATA.substring(0, 51) + "<>",
+ FileUtils.readTextFile(mTestFile, 51, "<>"));
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 52, "<>"));
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, 100, "<>"));
+
+ assertEquals("vwxyz", FileUtils.readTextFile(mTestFile, -5, null));
+ assertEquals("<>vwxyz", FileUtils.readTextFile(mTestFile, -5, "<>"));
+ assertEquals("<>" + TEST_DATA.substring(1, 52),
+ FileUtils.readTextFile(mTestFile, -51, "<>"));
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -52, "<>"));
+ assertEquals(TEST_DATA, FileUtils.readTextFile(mTestFile, -100, "<>"));
+ }
+
+ @MediumTest
+ public void testReadTextFileWithZeroLengthFile() throws Exception {
+ new FileOutputStream(mTestFile).close(); // Zero out the file
+ assertEquals("", FileUtils.readTextFile(mTestFile, 0, null));
+ assertEquals("", FileUtils.readTextFile(mTestFile, 1, "<>"));
+ assertEquals("", FileUtils.readTextFile(mTestFile, 10, "<>"));
+ assertEquals("", FileUtils.readTextFile(mTestFile, -1, "<>"));
+ assertEquals("", FileUtils.readTextFile(mTestFile, -10, "<>"));
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java
new file mode 100644
index 0000000..29045a3
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerStateMachineTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import junit.framework.TestCase;
+import java.util.Vector;
+
+import android.os.Handler;
+import android.os.HandlerState;
+import android.os.HandlerStateMachine;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Process;
+import android.os.Message;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import android.util.Log;
+
+public class HandlerStateMachineTest extends TestCase {
+ private static final int TEST_WHAT_1 = 1;
+ private static final int TEST_WHAT_2 = 2;
+
+ private static final boolean DBG = false;
+ private static final String TAG = "HandlerStateMachineTest";
+
+ private boolean mDidEnter = false;
+ private boolean mDidExit = false;
+ private Vector<Integer> mGotMessagesWhat = new Vector<Integer>();
+
+ /**
+ * This test statemachine has two states, it receives
+ * two messages in state mS1 deferring them until what == TEST_WHAT_2
+ * and then transitions to state mS2. State mS2 should then receive
+ * both of the deferred messages first TEST_WHAT_1 and then TEST_WHAT_2.
+ * When TEST_WHAT_2 is received it invokes notifyAll so the test can
+ * conclude.
+ */
+ class StateMachine1 extends HandlerStateMachine {
+ StateMachine1(String name) {
+ super(name);
+ mThisSm = this;
+ setDbg(DBG);
+ setInitialState(mS1);
+ }
+
+ class S1 extends HandlerState {
+ @Override public void enter(Message message) {
+ mDidEnter = true;
+ }
+
+ @Override public void processMessage(Message message) {
+ deferMessage(message);
+ if (message.what == TEST_WHAT_2) {
+ transitionTo(mS2);
+ }
+ }
+
+ @Override public void exit(Message message) {
+ mDidExit = true;
+ }
+ }
+
+ class S2 extends HandlerState {
+ @Override public void processMessage(Message message) {
+ mGotMessagesWhat.add(message.what);
+ if (message.what == TEST_WHAT_2) {
+ synchronized (mThisSm) {
+ mThisSm.notifyAll();
+ }
+ }
+ }
+ }
+
+ private StateMachine1 mThisSm;
+ private S1 mS1 = new S1();
+ private S2 mS2 = new S2();
+ }
+
+ @SmallTest
+ public void testStateMachine1() throws Exception {
+ StateMachine1 sm1 = new StateMachine1("sm1");
+ if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 E");
+
+ synchronized (sm1) {
+ // Send two messages
+ sm1.sendMessage(sm1.obtainMessage(TEST_WHAT_1));
+ sm1.sendMessage(sm1.obtainMessage(TEST_WHAT_2));
+
+ try {
+ // wait for the messages to be handled
+ sm1.wait();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "testStateMachine1: exception while waiting " + e.getMessage());
+ }
+ }
+
+ assertTrue(mDidEnter);
+ assertTrue(mDidExit);
+ assertTrue(mGotMessagesWhat.size() == 2);
+ assertTrue(mGotMessagesWhat.get(0) == TEST_WHAT_1);
+ assertTrue(mGotMessagesWhat.get(1) == TEST_WHAT_2);
+ if (sm1.isDbg()) Log.d(TAG, "testStateMachine1 X");
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java
new file mode 100644
index 0000000..303245f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerTester.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
+public abstract class HandlerTester extends Thread {
+ public abstract void go();
+ public abstract void handleMessage(Message msg);
+
+ public HandlerTester() {
+ }
+
+ public void doTest(long timeout) {
+ start();
+
+ synchronized (this) {
+ try {
+ wait(timeout);
+ quit();
+ }
+ catch (InterruptedException e) {
+ }
+ }
+
+ if (!mDone) {
+ throw new RuntimeException("test timed out");
+ }
+ if (!mSuccess) {
+ throw new RuntimeException("test failed");
+ }
+ }
+
+ public void success() {
+ mDone = true;
+ mSuccess = true;
+ }
+
+ public void failure() {
+ mDone = true;
+ mSuccess = false;
+ }
+
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ go();
+ Looper.loop();
+ }
+
+ protected class H extends Handler {
+ public void handleMessage(Message msg) {
+ synchronized (HandlerTester.this) {
+ // Call into them with our monitor locked, so they don't have
+ // to deal with other races.
+ HandlerTester.this.handleMessage(msg);
+ if (mDone) {
+ HandlerTester.this.notify();
+ quit();
+ }
+ }
+ }
+ }
+
+ private void quit() {
+ mLooper.quit();
+ }
+
+ private boolean mDone = false;
+ private boolean mSuccess = false;
+ private Looper mLooper;
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
new file mode 100644
index 0000000..c62f94f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/HandlerThreadTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import junit.framework.TestCase;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.os.Process;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class HandlerThreadTest extends TestCase {
+ private static final int TEST_WHAT = 1;
+
+ private boolean mGotMessage = false;
+ private int mGotMessageWhat = -1;
+ private volatile boolean mDidSetup = false;
+ private volatile int mLooperTid = -1;
+
+ @MediumTest
+ public void testHandlerThread() throws Exception {
+ HandlerThread th1 = new HandlerThread("HandlerThreadTest") {
+ protected void onLooperPrepared() {
+ mDidSetup = true;
+ mLooperTid = Process.myTid();
+ }
+ };
+
+ assertFalse(th1.isAlive());
+ assertNull(th1.getLooper());
+
+ th1.start();
+
+ assertTrue(th1.isAlive());
+ assertNotNull(th1.getLooper());
+
+ /*
+ * Since getLooper() will block until the HandlerThread is setup, we are guaranteed
+ * that mDidSetup and mLooperTid will have been initalized. If they have not, then
+ * this test should fail
+ */
+ // Make sure that the onLooperPrepared() was called on a different thread.
+ assertNotSame(Process.myTid(), mLooperTid);
+ assertTrue(mDidSetup);
+
+ final Handler h1 = new Handler(th1.getLooper()) {
+ public void handleMessage(Message msg) {
+ assertEquals(TEST_WHAT, msg.what);
+ // Ensure that we are running on the same thread in which the looper was setup on.
+ assertEquals(mLooperTid, Process.myTid());
+
+ mGotMessageWhat = msg.what;
+ mGotMessage = true;
+ synchronized(this) {
+ notifyAll();
+ }
+ }
+ };
+
+ Message msg = h1.obtainMessage(TEST_WHAT);
+
+ synchronized (h1) {
+ // wait until we have the lock before sending the message.
+ h1.sendMessage(msg);
+ try {
+ // wait for the message to be handled
+ h1.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+
+ assertTrue(mGotMessage);
+ assertEquals(TEST_WHAT, mGotMessageWhat);
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl
new file mode 100644
index 0000000..94c39ff
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/IAidlTest.aidl
@@ -0,0 +1,47 @@
+/* //device/apps/AndroidTests/src/com.android.unit_tests/IAidlTest.aidl
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package com.android.unit_tests.os;
+
+import com.android.unit_tests.os.AidlTest;
+
+interface IAidlTest {
+ int intMethod(int a);
+
+ AidlTest.TestParcelable parcelableIn(in AidlTest.TestParcelable p);
+ AidlTest.TestParcelable parcelableOut(out AidlTest.TestParcelable p);
+ AidlTest.TestParcelable parcelableInOut(inout AidlTest.TestParcelable p);
+
+ AidlTest.TestParcelable listParcelableLonger(
+ inout List<AidlTest.TestParcelable> list, int index);
+ int listParcelableShorter(
+ inout List<AidlTest.TestParcelable> list, int index);
+
+ boolean[] booleanArray(in boolean[] a0, out boolean[] a1, inout boolean[] a2);
+ char[] charArray(in char[] a0, out char[] a1, inout char[] a2);
+ int[] intArray(in int[] a0, out int[] a1, inout int[] a2);
+ long[] longArray(in long[] a0, out long[] a1, inout long[] a2);
+ float[] floatArray(in float[] a0, out float[] a1, inout float[] a2);
+ double[] doubleArray(in double[] a0, out double[] a1, inout double[] a2);
+ String[] stringArray(in String[] a0, out String[] a1, inout String[] a2);
+ AidlTest.TestParcelable[] parcelableArray(in AidlTest.TestParcelable[] a0,
+ out AidlTest.TestParcelable[] a1,
+ inout AidlTest.TestParcelable[] a2);
+
+ void voidSecurityException();
+ int intSecurityException();
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java
new file mode 100644
index 0000000..fc3b007
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/IdleHandlerTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue.IdleHandler;
+import android.test.suitebuilder.annotation.MediumTest;
+import junit.framework.TestCase;
+
+public class IdleHandlerTest extends TestCase {
+
+ private static class BaseTestHandler extends TestHandlerThread {
+ Handler mHandler;
+
+ public BaseTestHandler() {
+ }
+
+ public void go() {
+ mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ BaseTestHandler.this.handleMessage(msg);
+ }
+ };
+ }
+
+ public void addIdleHandler() {
+ Looper.myQueue().addIdleHandler(new IdleHandler() {
+ public boolean queueIdle() {
+ return BaseTestHandler.this.queueIdle();
+ }
+ });
+ }
+
+ public void handleMessage(Message msg) {
+ }
+
+ public boolean queueIdle() {
+ return false;
+ }
+ }
+
+ @MediumTest
+ public void testOneShotFirst() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ int mCount;
+
+ public void go() {
+ super.go();
+ mCount = 0;
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100);
+ addIdleHandler();
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+ } else if (msg.what == 1) {
+ if (mCount == 1) {
+ success();
+ } else {
+ failure(new RuntimeException(
+ "Idle handler called " + mCount + " times"));
+ }
+ }
+ }
+
+ public boolean queueIdle() {
+ mCount++;
+ return false;
+ }
+ };
+
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void testOneShotLater() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ int mCount;
+
+ public void go() {
+ super.go();
+ mCount = 0;
+ mHandler.sendMessage(mHandler.obtainMessage(0));
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ addIdleHandler();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+ } else if (msg.what == 1) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100);
+ } else if (msg.what == 2) {
+ if (mCount == 1) {
+ success();
+ } else {
+ failure(new RuntimeException(
+ "Idle handler called " + mCount + " times"));
+ }
+ }
+ }
+
+ public boolean queueIdle() {
+ mCount++;
+ return false;
+ }
+ };
+
+ tester.doTest(1000);
+ }
+
+
+ @MediumTest
+ public void testRepeatedFirst() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ int mCount;
+
+ public void go() {
+ super.go();
+ mCount = 0;
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(0), 100);
+ addIdleHandler();
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+ } else if (msg.what == 1) {
+ if (mCount == 2) {
+ success();
+ } else {
+ failure(new RuntimeException(
+ "Idle handler called " + mCount + " times"));
+ }
+ }
+ }
+
+ public boolean queueIdle() {
+ mCount++;
+ return true;
+ }
+ };
+
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void testRepeatedLater() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ int mCount;
+
+ public void go() {
+ super.go();
+ mCount = 0;
+ mHandler.sendMessage(mHandler.obtainMessage(0));
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.what == 0) {
+ addIdleHandler();
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(1), 100);
+ } else if (msg.what == 1) {
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(2), 100);
+ } else if (msg.what == 2) {
+ if (mCount == 2) {
+ success();
+ } else {
+ failure(new RuntimeException(
+ "Idle handler called " + mCount + " times"));
+ }
+ }
+ }
+
+ public boolean queueIdle() {
+ mCount++;
+ return true;
+ }
+ };
+
+ tester.doTest(1000);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
new file mode 100644
index 0000000..508afcf
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MemoryFileTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.MemoryFile;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class MemoryFileTest extends TestCase {
+
+ private void compareBuffers(byte[] buffer1, byte[] buffer2, int length) throws Exception {
+ for (int i = 0; i < length; i++) {
+ if (buffer1[i] != buffer2[i]) {
+ throw new Exception("readBytes did not read back what writeBytes wrote");
+ }
+ }
+ }
+
+ /**
+ * Keep allocating new files till the system purges them.
+ */
+ @MediumTest
+ public void testPurge() throws Exception {
+ List<MemoryFile> files = new ArrayList<MemoryFile>();
+ while (true) {
+ MemoryFile newFile = new MemoryFile("MemoryFileTest", 1000000);
+ newFile.allowPurging(true);
+ newFile.writeBytes(testString, 0, 0, testString.length);
+ files.add(newFile);
+ for (MemoryFile file : files) {
+ try {
+ file.readBytes(testString, 0, 0, testString.length);
+ } catch (IOException e) {
+ // Expected
+ for (MemoryFile fileToClose : files) {
+ fileToClose.close();
+ }
+ return;
+ }
+ }
+ }
+ }
+
+ @SmallTest
+ public void testRun() throws Exception {
+ MemoryFile file = new MemoryFile("MemoryFileTest", 1000000);
+
+ byte[] buffer = new byte[testString.length];
+
+ // check low level accessors
+ file.writeBytes(testString, 0, 2000, testString.length);
+ file.readBytes(buffer, 2000, 0, testString.length);
+ compareBuffers(testString, buffer, testString.length);
+
+ // check streams
+ buffer = new byte[testString.length];
+
+ OutputStream os = file.getOutputStream();
+ os.write(testString);
+
+ InputStream is = file.getInputStream();
+ is.mark(testString.length);
+ is.read(buffer);
+ compareBuffers(testString, buffer, testString.length);
+
+ // test mark/reset
+ buffer = new byte[testString.length];
+ is.reset();
+ is.read(buffer);
+ compareBuffers(testString, buffer, testString.length);
+
+ file.close();
+ }
+
+ private static final byte[] testString = new byte[] {
+ 3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9, 3, 2, 3, 8, 4, 6, 2, 6, 4, 3, 3, 8, 3, 2, 7, 9, 5, 0, 2, 8, 8, 4, 1, 9, 7, 1, 6, 9, 3, 9, 9, 3, 7, 5, 1, 0, 5, 8, 2, 0, 9, 7, 4, 9, 4, 4, 5, 9, 2, 3, 0, 7, 8, 1, 6, 4,
+ 0, 6, 2, 8, 6, 2, 0, 8, 9, 9, 8, 6, 2, 8, 0, 3, 4, 8, 2, 5, 3, 4, 2, 1, 1, 7, 0, 6, 7, 9, 8, 2, 1, 4, 8, 0, 8, 6, 5, 1, 3, 2, 8, 2, 3, 0, 6, 6, 4, 7, 0, 9, 3, 8, 4, 4, 6, 0, 9, 5, 5, 0, 5, 8, 2, 2, 3, 1, 7, 2,
+ 5, 3, 5, 9, 4, 0, 8, 1, 2, 8, 4, 8, 1, 1, 1, 7, 4, 5, 0, 2, 8, 4, 1, 0, 2, 7, 0, 1, 9, 3, 8, 5, 2, 1, 1, 0, 5, 5, 5, 9, 6, 4, 4, 6, 2, 2, 9, 4, 8, 9, 5, 4, 9, 3, 0, 3, 8, 1, 9, 6, 4, 4, 2, 8, 8, 1, 0, 9, 7, 5,
+ 6, 6, 5, 9, 3, 3, 4, 4, 6, 1, 2, 8, 4, 7, 5, 6, 4, 8, 2, 3, 3, 7, 8, 6, 7, 8, 3, 1, 6, 5, 2, 7, 1, 2, 0, 1, 9, 0, 9, 1, 4, 5, 6, 4, 8, 5, 6, 6, 9, 2, 3, 4, 6, 0, 3, 4, 8, 6, 1, 0, 4, 5, 4, 3, 2, 6, 6, 4, 8, 2,
+ 1, 3, 3, 9, 3, 6, 0, 7, 2, 6, 0, 2, 4, 9, 1, 4, 1, 2, 7, 3, 7, 2, 4, 5, 8, 7, 0, 0, 6, 6, 0, 6, 3, 1, 5, 5, 8, 8, 1, 7, 4, 8, 8, 1, 5, 2, 0, 9, 2, 0, 9, 6, 2, 8, 2, 9, 2, 5, 4, 0, 9, 1, 7, 1, 5, 3, 6, 4, 3, 6,
+ 7, 8, 9, 2, 5, 9, 0, 3, 6, 0, 0, 1, 1, 3, 3, 0, 5, 3, 0, 5, 4, 8, 8, 2, 0, 4, 6, 6, 5, 2, 1, 3, 8, 4, 1, 4, 6, 9, 5, 1, 9, 4, 1, 5, 1, 1, 6, 0, 9, 4, 3, 3, 0, 5, 7, 2, 7, 0, 3, 6, 5, 7, 5, 9, 5, 9, 1, 9, 5, 3,
+ 0, 9, 2, 1, 8, 6, 1, 1, 7, 3, 8, 1, 9, 3, 2, 6, 1, 1, 7, 9, 3, 1, 0, 5, 1, 1, 8, 5, 4, 8, 0, 7, 4, 4, 6, 2, 3, 7, 9, 9, 6, 2, 7, 4, 9, 5, 6, 7, 3, 5, 1, 8, 8, 5, 7, 5, 2, 7, 2, 4, 8, 9, 1, 2, 2, 7, 9, 3, 8, 1,
+ 8, 3, 0, 1, 1, 9, 4, 9, 1, 2, 9, 8, 3, 3, 6, 7, 3, 3, 6, 2, 4, 4, 0, 6, 5, 6, 6, 4, 3, 0, 8, 6, 0, 2, 1, 3, 9, 4, 9, 4, 6, 3, 9, 5, 2, 2, 4, 7, 3, 7, 1, 9, 0, 7, 0, 2, 1, 7, 9, 8, 6, 0, 9, 4, 3, 7, 0, 2, 7, 7,
+ 0, 5, 3, 9, 2, 1, 7, 1, 7, 6, 2, 9, 3, 1, 7, 6, 7, 5, 2, 3, 8, 4, 6, 7, 4, 8, 1, 8, 4, 6, 7, 6, 6, 9, 4, 0, 5, 1, 3, 2, 0, 0, 0, 5, 6, 8, 1, 2, 7, 1, 4, 5, 2, 6, 3, 5, 6, 0, 8, 2, 7, 7, 8, 5, 7, 7, 1, 3, 4, 2,
+ 7, 5, 7, 7, 8, 9, 6, 0, 9, 1, 7, 3, 6, 3, 7, 1, 7, 8, 7, 2, 1, 4, 6, 8, 4, 4, 0, 9, 0, 1, 2, 2, 4, 9, 5, 3, 4, 3, 0, 1, 4, 6, 5, 4, 9, 5, 8, 5, 3, 7, 1, 0, 5, 0, 7, 9, 2, 2, 7, 9, 6, 8, 9, 2, 5, 8, 9, 2, 3, 5,
+ 4, 2, 0, 1, 9, 9, 5, 6, 1, 1, 2, 1, 2, 9, 0, 2, 1, 9, 6, 0, 8, 6, 4, 0, 3, 4, 4, 1, 8, 1, 5, 9, 8, 1, 3, 6, 2, 9, 7, 7, 4, 7, 7, 1, 3, 0, 9, 9, 6, 0, 5, 1, 8, 7, 0, 7, 2, 1, 1, 3, 4, 9, 9, 9, 9, 9, 9, 8, 3, 7,
+ 2, 9, 7, 8, 0, 4, 9, 9, 5, 1, 0, 5, 9, 7, 3, 1, 7, 3, 2, 8, 1, 6, 0, 9, 6, 3, 1, 8, 5, 9, 5, 0, 2, 4, 4, 5, 9, 4, 5, 5, 3, 4, 6, 9, 0, 8, 3, 0, 2, 6, 4, 2, 5, 2, 2, 3, 0, 8, 2, 5, 3, 3, 4, 4, 6, 8, 5, 0, 3, 5,
+ 2, 6, 1, 9, 3, 1, 1, 8, 8, 1, 7, 1, 0, 1, 0, 0, 0, 3, 1, 3, 7, 8, 3, 8, 7, 5, 2, 8, 8, 6, 5, 8, 7, 5, 3, 3, 2, 0, 8, 3, 8, 1, 4, 2, 0, 6, 1, 7, 1, 7, 7, 6, 6, 9, 1, 4, 7, 3, 0, 3, 5, 9, 8, 2, 5, 3, 4, 9, 0, 4,
+ 2, 8, 7, 5, 5, 4, 6, 8, 7, 3, 1, 1, 5, 9, 5, 6, 2, 8, 6, 3, 8, 8, 2, 3, 5, 3, 7, 8, 7, 5, 9, 3, 7, 5, 1, 9, 5, 7, 7, 8, 1, 8, 5, 7, 7, 8, 0, 5, 3, 2, 1, 7, 1, 2, 2, 6, 8, 0, 6, 6, 1, 3, 0, 0, 1, 9, 2, 7, 8, 7,
+ 6, 6, 1, 1, 1, 9, 5, 9, 0, 9, 2, 1, 6, 4, 2, 0, 1, 9, 8, 9, 3, 8, 0, 9, 5, 2, 5, 7, 2, 0, 1, 0, 6, 5, 4, 8, 5, 8, 6, 3, 2, 7, 8, 8, 6, 5, 9, 3, 6, 1, 5, 3, 3, 8, 1, 8, 2, 7, 9, 6, 8, 2, 3, 0, 3, 0, 1, 9, 5, 2,
+ 0, 3, 5, 3, 0, 1, 8, 5, 2, 9, 6, 8, 9, 9, 5, 7, 7, 3, 6, 2, 2, 5, 9, 9, 4, 1, 3, 8, 9, 1, 2, 4, 9, 7, 2, 1, 7, 7, 5, 2, 8, 3, 4, 7, 9, 1, 3, 1, 5, 1, 5, 5, 7, 4, 8, 5, 7, 2, 4, 2, 4, 5, 4, 1, 5, 0, 6, 9, 5, 9,
+ 5, 0, 8, 2, 9, 5, 3, 3, 1, 1, 6, 8, 6, 1, 7, 2, 7, 8, 5, 5, 8, 8, 9, 0, 7, 5, 0, 9, 8, 3, 8, 1, 7, 5, 4, 6, 3, 7, 4, 6, 4, 9, 3, 9, 3, 1, 9, 2, 5, 5, 0, 6, 0, 4, 0, 0, 9, 2, 7, 7, 0, 1, 6, 7, 1, 1, 3, 9, 0, 0,
+ 9, 8, 4, 8, 8, 2, 4, 0, 1, 2, 8, 5, 8, 3, 6, 1, 6, 0, 3, 5, 6, 3, 7, 0, 7, 6, 6, 0, 1, 0, 4, 7, 1, 0, 1, 8, 1, 9, 4, 2, 9, 5, 5, 5, 9, 6, 1, 9, 8, 9, 4, 6, 7, 6, 7, 8, 3, 7, 4, 4, 9, 4, 4, 8, 2, 5, 5, 3, 7, 9,
+ 7, 7, 4, 7, 2, 6, 8, 4, 7, 1, 0, 4, 0, 4, 7, 5, 3, 4, 6, 4, 6, 2, 0, 8, 0, 4, 6, 6, 8, 4, 2, 5, 9, 0, 6, 9, 4, 9, 1, 2, 9, 3, 3, 1, 3, 6, 7, 7, 0, 2, 8, 9, 8, 9, 1, 5, 2, 1, 0, 4, 7, 5, 2, 1, 6, 2, 0, 5, 6, 9,
+ 6, 6, 0, 2, 4, 0, 5, 8, 0, 3, 8, 1, 5, 0, 1, 9, 3, 5, 1, 1, 2, 5, 3, 3, 8, 2, 4, 3, 0, 0, 3, 5, 5, 8, 7, 6, 4, 0, 2, 4, 7, 4, 9, 6, 4, 7, 3, 2, 6, 3, 9, 1, 4, 1, 9, 9, 2, 7, 2, 6, 0, 4, 2, 6, 9, 9, 2, 2, 7, 9,
+ 6, 7, 8, 2, 3, 5, 4, 7, 8, 1, 6, 3, 6, 0, 0, 9, 3, 4, 1, 7, 2, 1, 6, 4, 1, 2, 1, 9, 9, 2, 4, 5, 8, 6, 3, 1, 5, 0, 3, 0, 2, 8, 6, 1, 8, 2, 9, 7, 4, 5, 5, 5, 7, 0, 6, 7, 4, 9, 8, 3, 8, 5, 0, 5, 4, 9, 4, 5, 8, 8,
+ 5, 8, 6, 9, 2, 6, 9, 9, 5, 6, 9, 0, 9, 2, 7, 2, 1, 0, 7, 9, 7, 5, 0, 9, 3, 0, 2, 9, 5, 5, 3, 2, 1, 1, 6, 5, 3, 4, 4, 9, 8, 7, 2, 0, 2, 7, 5, 5, 9, 6, 0, 2, 3, 6, 4, 8, 0, 6, 6, 5, 4, 9, 9, 1, 1, 9, 8, 8, 1, 8,
+ 3, 4, 7, 9, 7, 7, 5, 3, 5, 6, 6, 3, 6, 9, 8, 0, 7, 4, 2, 6, 5, 4, 2, 5, 2, 7, 8, 6, 2, 5, 5, 1, 8, 1, 8, 4, 1, 7, 5, 7, 4, 6, 7, 2, 8, 9, 0, 9, 7, 7, 7, 7, 2, 7, 9, 3, 8, 0, 0, 0, 8, 1, 6, 4, 7, 0, 6, 0, 0, 1,
+ 6, 1, 4, 5, 2, 4, 9, 1, 9, 2, 1, 7, 3, 2, 1, 7, 2, 1, 4, 7, 7, 2, 3, 5, 0, 1, 4, 1, 4, 4, 1, 9, 7, 3, 5, 6, 8, 5, 4, 8, 1, 6, 1, 3, 6, 1, 1, 5, 7, 3, 5, 2, 5, 5, 2, 1, 3, 3, 4, 7, 5, 7, 4, 1, 8, 4, 9, 4, 6, 8,
+ 4, 3, 8, 5, 2, 3, 3, 2, 3, 9, 0, 7, 3, 9, 4, 1, 4, 3, 3, 3, 4, 5, 4, 7, 7, 6, 2, 4, 1, 6, 8, 6, 2, 5, 1, 8, 9, 8, 3, 5, 6, 9, 4, 8, 5, 5, 6, 2, 0, 9, 9, 2, 1, 9, 2, 2, 2, 1, 8, 4, 2, 7, 2, 5, 5, 0, 2, 5, 4, 2,
+ 5, 6, 8, 8, 7, 6, 7, 1, 7, 9, 0, 4, 9, 4, 6, 0, 1, 6, 5, 3, 4, 6, 6, 8, 0, 4, 9, 8, 8, 6, 2, 7, 2, 3, 2, 7, 9, 1, 7, 8, 6, 0, 8, 5, 7, 8, 4, 3, 8, 3, 8, 2, 7, 9, 6, 7, 9, 7, 6, 6, 8, 1, 4, 5, 4, 1, 0, 0, 9, 5,
+ 3, 8, 8, 3, 7, 8, 6, 3, 6, 0, 9, 5, 0, 6, 8, 0, 0, 6, 4, 2, 2, 5, 1, 2, 5, 2, 0, 5, 1, 1, 7, 3, 9, 2, 9, 8, 4, 8, 9, 6, 0, 8, 4, 1, 2, 8, 4, 8, 8, 6, 2, 6, 9, 4, 5, 6, 0, 4, 2, 4, 1, 9, 6, 5, 2, 8, 5, 0, 2, 2,
+ 2, 1, 0, 6, 6, 1, 1, 8, 6, 3, 0, 6, 7, 4, 4, 2, 7, 8, 6, 2, 2, 0, 3, 9, 1, 9, 4, 9, 4, 5, 0, 4, 7, 1, 2, 3, 7, 1, 3, 7, 8, 6, 9, 6, 0, 9, 5, 6, 3, 6, 4, 3, 7, 1, 9, 1, 7, 2, 8, 7, 4, 6, 7, 7, 6, 4, 6, 5, 7, 5,
+ 7, 3, 9, 6, 2, 4, 1, 3, 8, 9, 0, 8, 6, 5, 8, 3, 2, 6, 4, 5, 9, 9, 5, 8, 1, 3, 3, 9, 0, 4, 7, 8, 0, 2, 7, 5, 9, 0, 0, 9, 9, 4, 6, 5, 7, 6, 4, 0, 7, 8, 9, 5, 1, 2, 6, 9, 4, 6, 8, 3, 9, 8, 3, 5, 2, 5, 9, 5, 7, 0,
+ 9, 8, 2, 5, 8, 2, 2, 6, 2, 0, 5, 2, 2, 4, 8, 9, 4, 0, 7, 7, 2, 6, 7, 1, 9, 4, 7, 8, 2, 6, 8, 4, 8, 2, 6, 0, 1, 4, 7, 6, 9, 9, 0, 9, 0, 2, 6, 4, 0, 1, 3, 6, 3, 9, 4, 4, 3, 7, 4, 5, 5, 3, 0, 5, 0, 6, 8, 2, 0, 3,
+ 4, 9, 6, 2, 5, 2, 4, 5, 1, 7, 4, 9, 3, 9, 9, 6, 5, 1, 4, 3, 1, 4, 2, 9, 8, 0, 9, 1, 9, 0, 6, 5, 9, 2, 5, 0, 9, 3, 7, 2, 2, 1, 6, 9, 6, 4, 6, 1, 5, 1, 5, 7, 0, 9, 8, 5, 8, 3, 8, 7, 4, 1, 0, 5, 9, 7, 8, 8, 5, 9,
+ 5, 9, 7, 7, 2, 9, 7, 5, 4, 9, 8, 9, 3, 0, 1, 6, 1, 7, 5, 3, 9, 2, 8, 4, 6, 8, 1, 3, 8, 2, 6, 8, 6, 8, 3, 8, 6, 8, 9, 4, 2, 7, 7, 4, 1, 5, 5, 9, 9, 1, 8, 5, 5, 9, 2, 5, 2, 4, 5, 9, 5, 3, 9, 5, 9, 4, 3, 1, 0, 4,
+ 9, 9, 7, 2, 5, 2, 4, 6, 8, 0, 8, 4, 5, 9, 8, 7, 2, 7, 3, 6, 4, 4, 6, 9, 5, 8, 4, 8, 6, 5, 3, 8, 3, 6, 7, 3, 6, 2, 2, 2, 6, 2, 6, 0, 9, 9, 1, 2, 4, 6, 0, 8, 0, 5, 1, 2, 4, 3, 8, 8, 4, 3, 9, 0, 4, 5, 1, 2, 4, 4,
+ 1, 3, 6, 5, 4, 9, 7, 6, 2, 7, 8, 0, 7, 9, 7, 7, 1, 5, 6, 9, 1, 4, 3, 5, 9, 9, 7, 7, 0, 0, 1, 2, 9, 6, 1, 6, 0, 8, 9, 4, 4, 1, 6, 9, 4, 8, 6, 8, 5, 5, 5, 8, 4, 8, 4, 0, 6, 3, 5, 3, 4, 2, 2, 0, 7, 2, 2, 2, 5, 8,
+ 2, 8, 4, 8, 8, 6, 4, 8, 1, 5, 8, 4, 5, 6, 0, 2, 8, 5, 0, 6, 0, 1, 6, 8, 4, 2, 7, 3, 9, 4, 5, 2, 2, 6, 7, 4, 6, 7, 6, 7, 8, 8, 9, 5, 2, 5, 2, 1, 3, 8, 5, 2, 2, 5, 4, 9, 9, 5, 4, 6, 6, 6, 7, 2, 7, 8, 2, 3, 9, 8,
+ 6, 4, 5, 6, 5, 9, 6, 1, 1, 6, 3, 5, 4, 8, 8, 6, 2, 3, 0, 5, 7, 7, 4, 5, 6, 4, 9, 8, 0, 3, 5, 5, 9, 3, 6, 3, 4, 5, 6, 8, 1, 7, 4, 3, 2, 4, 1, 1, 2, 5, 1, 5, 0, 7, 6, 0, 6, 9, 4, 7, 9, 4, 5, 1, 0, 9, 6, 5, 9, 6,
+ 0, 9, 4, 0, 2, 5, 2, 2, 8, 8, 7, 9, 7, 1, 0, 8, 9, 3, 1, 4, 5, 6, 6, 9, 1, 3, 6, 8, 6, 7, 2, 2, 8, 7, 4, 8, 9, 4, 0, 5, 6, 0, 1, 0, 1, 5, 0, 3, 3, 0, 8, 6, 1, 7, 9, 2, 8, 6, 8, 0, 9, 2, 0, 8, 7, 4, 7, 6, 0, 9,
+ 1, 7, 8, 2, 4, 9, 3, 8, 5, 8, 9, 0, 0, 9, 7, 1, 4, 9, 0, 9, 6, 7, 5, 9, 8, 5, 2, 6, 1, 3, 6, 5, 5, 4, 9, 7, 8, 1, 8, 9, 3, 1, 2, 9, 7, 8, 4, 8, 2, 1, 6, 8, 2, 9, 9, 8, 9, 4, 8, 7, 2, 2, 6, 5, 8, 8, 0, 4, 8, 5,
+ 7, 5, 6, 4, 0, 1, 4, 2, 7, 0, 4, 7, 7, 5, 5, 5, 1, 3, 2, 3, 7, 9, 6, 4, 1, 4, 5, 1, 5, 2, 3, 7, 4, 6, 2, 3, 4, 3, 6, 4, 5, 4, 2, 8, 5, 8, 4, 4, 4, 7, 9, 5, 2, 6, 5, 8, 6, 7, 8, 2, 1, 0, 5, 1, 1, 4, 1, 3, 5, 4,
+ 7, 3, 5, 7, 3, 9, 5, 2, 3, 1, 1, 3, 4, 2, 7, 1, 6, 6, 1, 0, 2, 1, 3, 5, 9, 6, 9, 5, 3, 6, 2, 3, 1, 4, 4, 2, 9, 5, 2, 4, 8, 4, 9, 3, 7, 1, 8, 7, 1, 1, 0, 1, 4, 5, 7, 6, 5, 4, 0, 3, 5, 9, 0, 2, 7, 9, 9, 3, 4, 4,
+ 0, 3, 7, 4, 2, 0, 0, 7, 3, 1, 0, 5, 7, 8, 5, 3, 9, 0, 6, 2, 1, 9, 8, 3, 8, 7, 4, 4, 7, 8, 0, 8, 4, 7, 8, 4, 8, 9, 6, 8, 3, 3, 2, 1, 4, 4, 5, 7, 1, 3, 8, 6, 8, 7, 5, 1, 9, 4, 3, 5, 0, 6, 4, 3, 0, 2, 1, 8, 4, 5,
+ 3, 1, 9, 1, 0, 4, 8, 4, 8, 1, 0, 0, 5, 3, 7, 0, 6, 1, 4, 6, 8, 0, 6, 7, 4, 9, 1, 9, 2, 7, 8, 1, 9, 1, 1, 9, 7, 9, 3, 9, 9, 5, 2, 0, 6, 1, 4, 1, 9, 6, 6, 3, 4, 2, 8, 7, 5, 4, 4, 4, 0, 6, 4, 3, 7, 4, 5, 1, 2, 3,
+ 7, 1, 8, 1, 9, 2, 1, 7, 9, 9, 9, 8, 3, 9, 1, 0, 1, 5, 9, 1, 9, 5, 6, 1, 8, 1, 4, 6, 7, 5, 1, 4, 2, 6, 9, 1, 2, 3, 9, 7, 4, 8, 9, 4, 0, 9, 0, 7, 1, 8, 6, 4, 9, 4, 2, 3, 1, 9, 6, 1, 5, 6, 7, 9, 4, 5, 2, 0, 8, 0,
+ 9, 5, 1, 4, 6, 5, 5, 0, 2, 2, 5, 2, 3, 1, 6, 0, 3, 8, 8, 1, 9, 3, 0, 1, 4, 2, 0, 9, 3, 7, 6, 2, 1, 3, 7, 8, 5, 5, 9, 5, 6, 6, 3, 8, 9, 3, 7, 7, 8, 7, 0, 8, 3, 0, 3, 9, 0, 6, 9, 7, 9, 2, 0, 7, 7, 3, 4, 6, 7, 2,
+ 2, 1, 8, 2, 5, 6, 2, 5, 9, 9, 6, 6, 1, 5, 0, 1, 4, 2, 1, 5, 0, 3, 0, 6, 8, 0, 3, 8, 4, 4, 7, 7, 3, 4, 5, 4, 9, 2, 0, 2, 6, 0, 5, 4, 1, 4, 6, 6, 5, 9, 2, 5, 2, 0, 1, 4, 9, 7, 4, 4, 2, 8, 5, 0, 7, 3, 2, 5, 1, 8,
+ 6, 6, 6, 0, 0, 2, 1, 3, 2, 4, 3, 4, 0, 8, 8, 1, 9, 0, 7, 1, 0, 4, 8, 6, 3, 3, 1, 7, 3, 4, 6, 4, 9, 6, 5, 1, 4, 5, 3, 9, 0, 5, 7, 9, 6, 2, 6, 8, 5, 6, 1, 0, 0, 5, 5, 0, 8, 1, 0, 6, 6, 5, 8, 7, 9, 6, 9, 9, 8, 1,
+ 6, 3, 5, 7, 4, 7, 3, 6, 3, 8, 4, 0, 5, 2, 5, 7, 1, 4, 5, 9, 1, 0, 2, 8, 9, 7, 0, 6, 4, 1, 4, 0, 1, 1, 0, 9, 7, 1, 2, 0, 6, 2, 8, 0, 4, 3, 9, 0, 3, 9, 7, 5, 9, 5, 1, 5, 6, 7, 7, 1, 5, 7, 7, 0, 0, 4, 2, 0, 3, 3,
+ 7, 8, 6, 9, 9, 3, 6, 0, 0, 7, 2, 3, 0, 5, 5, 8, 7, 6, 3, 1, 7, 6, 3, 5, 9, 4, 2, 1, 8, 7, 3, 1, 2, 5, 1, 4, 7, 1, 2, 0, 5, 3, 2, 9, 2, 8, 1, 9, 1, 8, 2, 6, 1, 8, 6, 1, 2, 5, 8, 6, 7, 3, 2, 1, 5, 7, 9, 1, 9, 8,
+ 4, 1, 4, 8, 4, 8, 8, 2, 9, 1, 6, 4, 4, 7, 0, 6, 0, 9, 5, 7, 5, 2, 7, 0, 6, 9, 5, 7, 2, 2, 0, 9, 1, 7, 5, 6, 7, 1, 1, 6, 7, 2, 2, 9, 1, 0, 9, 8, 1, 6, 9, 0, 9, 1, 5, 2, 8, 0, 1, 7, 3, 5, 0, 6, 7, 1, 2, 7, 4, 8,
+ 5, 8, 3, 2, 2, 2, 8, 7, 1, 8, 3, 5, 2, 0, 9, 3, 5, 3, 9, 6, 5, 7, 2, 5, 1, 2, 1, 0, 8, 3, 5, 7, 9, 1, 5, 1, 3, 6, 9, 8, 8, 2, 0, 9, 1, 4, 4, 4, 2, 1, 0, 0, 6, 7, 5, 1, 0, 3, 3, 4, 6, 7, 1, 1, 0, 3, 1, 4, 1, 2,
+ 6, 7, 1, 1, 1, 3, 6, 9, 9, 0, 8, 6, 5, 8, 5, 1, 6, 3, 9, 8, 3, 1, 5, 0, 1, 9, 7, 0, 1, 6, 5, 1, 5, 1, 1, 6, 8, 5, 1, 7, 1, 4, 3, 7, 6, 5, 7, 6, 1, 8, 3, 5, 1, 5, 5, 6, 5, 0, 8, 8, 4, 9, 0, 9, 9, 8, 9, 8, 5, 9,
+ 9, 8, 2, 3, 8, 7, 3, 4, 5, 5, 2, 8, 3, 3, 1, 6, 3, 5, 5, 0, 7, 6, 4, 7, 9, 1, 8, 5, 3, 5, 8, 9, 3, 2, 2, 6, 1, 8, 5, 4, 8, 9, 6, 3, 2, 1, 3, 2, 9, 3, 3, 0, 8, 9, 8, 5, 7, 0, 6, 4, 2, 0, 4, 6, 7, 5, 2, 5, 9, 0,
+ 7, 0, 9, 1, 5, 4, 8, 1, 4, 1, 6, 5, 4, 9, 8, 5, 9, 4, 6, 1, 6, 3, 7, 1, 8, 0, 2, 7, 0, 9, 8, 1, 9, 9, 4, 3, 0, 9, 9, 2, 4, 4, 8, 8, 9, 5, 7, 5, 7, 1, 2, 8, 2, 8, 9, 0, 5, 9, 2, 3, 2, 3, 3, 2, 6, 0, 9, 7, 2, 9,
+ 9, 7, 1, 2, 0, 8, 4, 4, 3, 3, 5, 7, 3, 2, 6, 5, 4, 8, 9, 3, 8, 2, 3, 9, 1, 1, 9, 3, 2, 5, 9, 7, 4, 6, 3, 6, 6, 7, 3, 0, 5, 8, 3, 6, 0, 4, 1, 4, 2, 8, 1, 3, 8, 8, 3, 0, 3, 2, 0, 3, 8, 2, 4, 9, 0, 3, 7, 5, 8, 9,
+ 8, 5, 2, 4, 3, 7, 4, 4, 1, 7, 0, 2, 9, 1, 3, 2, 7, 6, 5, 6, 1, 8, 0, 9, 3, 7, 7, 3, 4, 4, 4, 0, 3, 0, 7, 0, 7, 4, 6, 9, 2, 1, 1, 2, 0, 1, 9, 1, 3, 0, 2, 0, 3, 3, 0, 3, 8, 0, 1, 9, 7, 6, 2, 1, 1, 0, 1, 1, 0, 0,
+ 4, 4, 9, 2, 9, 3, 2, 1, 5, 1, 6, 0, 8, 4, 2, 4, 4, 4, 8, 5, 9, 6, 3, 7, 6, 6, 9, 8, 3, 8, 9, 5, 2, 2, 8, 6, 8, 4, 7, 8, 3, 1, 2, 3, 5, 5, 2, 6, 5, 8, 2, 1, 3, 1, 4, 4, 9, 5, 7, 6, 8, 5, 7, 2, 6, 2, 4, 3, 3, 4,
+ 4, 1, 8, 9, 3, 0, 3, 9, 6, 8, 6, 4, 2, 6, 2, 4, 3, 4, 1, 0, 7, 7, 3, 2, 2, 6, 9, 7, 8, 0, 2, 8, 0, 7, 3, 1, 8, 9, 1, 5, 4, 4, 1, 1, 0, 1, 0, 4, 4, 6, 8, 2, 3, 2, 5, 2, 7, 1, 6, 2, 0, 1, 0, 5, 2, 6, 5, 2, 2, 7,
+ 2, 1, 1, 1, 6, 6, 0, 3, 9, 6, 6, 6, 5, 5, 7, 3, 0, 9, 2, 5, 4, 7, 1, 1, 0, 5, 5, 7, 8, 5, 3, 7, 6, 3, 4, 6, 6, 8, 2, 0, 6, 5, 3, 1, 0, 9, 8, 9, 6, 5, 2, 6, 9, 1, 8, 6, 2, 0, 5, 6, 4, 7, 6, 9, 3, 1, 2, 5, 7, 0,
+ 5, 8, 6, 3, 5, 6, 6, 2, 0, 1, 8, 5, 5, 8, 1, 0, 0, 7, 2, 9, 3, 6, 0, 6, 5, 9, 8, 7, 6, 4, 8, 6, 1, 1, 7, 9, 1, 0, 4, 5, 3, 3, 4, 8, 8, 5, 0, 3, 4, 6, 1, 1, 3, 6, 5, 7, 6, 8, 6, 7, 5, 3, 2, 4, 9, 4, 4, 1, 6, 6,
+ 8, 0, 3, 9, 6, 2, 6, 5, 7, 9, 7, 8, 7, 7, 1, 8, 5, 5, 6, 0, 8, 4, 5, 5, 2, 9, 6, 5, 4, 1, 2, 6, 6, 5, 4, 0, 8, 5, 3, 0, 6, 1, 4, 3, 4, 4, 4, 3, 1, 8, 5, 8, 6, 7, 6, 9, 7, 5, 1, 4, 5, 6, 6, 1, 4, 0, 6, 8, 0, 0,
+ 7, 0, 0, 2, 3, 7, 8, 7, 7, 6, 5, 9, 1, 3, 4, 4, 0, 1, 7, 1, 2, 7, 4, 9, 4, 7, 0, 4, 2, 0, 5, 6, 2, 2, 3, 0, 5, 3, 8, 9, 9, 4, 5, 6, 1, 3, 1, 4, 0, 7, 1, 1, 2, 7, 0, 0, 0, 4, 0, 7, 8, 5, 4, 7, 3, 3, 2, 6, 9, 9,
+ 3, 9, 0, 8, 1, 4, 5, 4, 6, 6, 4, 6, 4, 5, 8, 8, 0, 7, 9, 7, 2, 7, 0, 8, 2, 6, 6, 8, 3, 0, 6, 3, 4, 3, 2, 8, 5, 8, 7, 8, 5, 6, 9, 8, 3, 0, 5, 2, 3, 5, 8, 0, 8, 9, 3, 3, 0, 6, 5, 7, 5, 7, 4, 0, 6, 7, 9, 5, 4, 5,
+ 7, 1, 6, 3, 7, 7, 5, 2, 5, 4, 2, 0, 2, 1, 1, 4, 9, 5, 5, 7, 6, 1, 5, 8, 1, 4, 0, 0, 2, 5, 0, 1, 2, 6, 2, 2, 8, 5, 9, 4, 1, 3, 0, 2, 1, 6, 4, 7, 1, 5, 5, 0, 9, 7, 9, 2, 5, 9, 2, 3, 0, 9, 9, 0, 7, 9, 6, 5, 4, 7,
+ 3, 7, 6, 1, 2, 5, 5, 1, 7, 6, 5, 6, 7, 5, 1, 3, 5, 7, 5, 1, 7, 8, 2, 9, 6, 6, 6, 4, 5, 4, 7, 7, 9, 1, 7, 4, 5, 0, 1, 1, 2, 9, 9, 6, 1, 4, 8, 9, 0, 3, 0, 4, 6, 3, 9, 9, 4, 7, 1, 3, 2, 9, 6, 2, 1, 0, 7, 3, 4, 0,
+ 4, 3, 7, 5, 1, 8, 9, 5, 7, 3, 5, 9, 6, 1, 4, 5, 8, 9, 0, 1, 9, 3, 8, 9, 7, 1, 3, 1, 1, 1, 7, 9, 0, 4, 2, 9, 7, 8, 2, 8, 5, 6, 4, 7, 5, 0, 3, 2, 0, 3, 1, 9, 8, 6, 9, 1, 5, 1, 4, 0, 2, 8, 7, 0, 8, 0, 8, 5, 9, 9,
+ 0, 4, 8, 0, 1, 0, 9, 4, 1, 2, 1, 4, 7, 2, 2, 1, 3, 1, 7, 9, 4, 7, 6, 4, 7, 7, 7, 2, 6, 2, 2, 4, 1, 4, 2, 5, 4, 8, 5, 4, 5, 4, 0, 3, 3, 2, 1, 5, 7, 1, 8, 5, 3, 0, 6, 1, 4, 2, 2, 8, 8, 1, 3, 7, 5, 8, 5, 0, 4, 3,
+ 0, 6, 3, 3, 2, 1, 7, 5, 1, 8, 2, 9, 7, 9, 8, 6, 6, 2, 2, 3, 7, 1, 7, 2, 1, 5, 9, 1, 6, 0, 7, 7, 1, 6, 6, 9, 2, 5, 4, 7, 4, 8, 7, 3, 8, 9, 8, 6, 6, 5, 4, 9, 4, 9, 4, 5, 0, 1, 1, 4, 6, 5, 4, 0, 6, 2, 8, 4, 3, 3,
+ 6, 6, 3, 9, 3, 7, 9, 0, 0, 3, 9, 7, 6, 9, 2, 6, 5, 6, 7, 2, 1, 4, 6, 3, 8, 5, 3, 0, 6, 7, 3, 6, 0, 9, 6, 5, 7, 1, 2, 0, 9, 1, 8, 0, 7, 6, 3, 8, 3, 2, 7, 1, 6, 6, 4, 1, 6, 2, 7, 4, 8, 8, 8, 8, 0, 0, 7, 8, 6, 9,
+ 2, 5, 6, 0, 2, 9, 0, 2, 2, 8, 4, 7, 2, 1, 0, 4, 0, 3, 1, 7, 2, 1, 1, 8, 6, 0, 8, 2, 0, 4, 1, 9, 0, 0, 0, 4, 2, 2, 9, 6, 6, 1, 7, 1, 1, 9, 6, 3, 7, 7, 9, 2, 1, 3, 3, 7, 5, 7, 5, 1, 1, 4, 9, 5, 9, 5, 0, 1, 5, 6,
+ 6, 0, 4, 9, 6, 3, 1, 8, 6, 2, 9, 4, 7, 2, 6, 5, 4, 7, 3, 6, 4, 2, 5, 2, 3, 0, 8, 1, 7, 7, 0, 3, 6, 7, 5, 1, 5, 9, 0, 6, 7, 3, 5, 0, 2, 3, 5, 0, 7, 2, 8, 3, 5, 4, 0, 5, 6, 7, 0, 4, 0, 3, 8, 6, 7, 4, 3, 5, 1, 3,
+ 6, 2, 2, 2, 2, 4, 7, 7, 1, 5, 8, 9, 1, 5, 0, 4, 9, 5, 3, 0, 9, 8, 4, 4, 4, 8, 9, 3, 3, 3, 0, 9, 6, 3, 4, 0, 8, 7, 8, 0, 7, 6, 9, 3, 2, 5, 9, 9, 3, 9, 7, 8, 0, 5, 4, 1, 9, 3, 4, 1, 4, 4, 7, 3, 7, 7, 4, 4, 1, 8,
+ 4, 2, 6, 3, 1, 2, 9, 8, 6, 0, 8, 0, 9, 9, 8, 8, 8, 6, 8, 7, 4, 1, 3, 2, 6, 0, 4, 7, 2, 1, 5, 6, 9, 5, 1, 6, 2, 3, 9, 6, 5, 8, 6, 4, 5, 7, 3, 0, 2, 1, 6, 3, 1, 5, 9, 8, 1, 9, 3, 1, 9, 5, 1, 6, 7, 3, 5, 3, 8, 1,
+ 2, 9, 7, 4, 1, 6, 7, 7, 2, 9, 4, 7, 8, 6, 7, 2, 4, 2, 2, 9, 2, 4, 6, 5, 4, 3, 6, 6, 8, 0, 0, 9, 8, 0, 6, 7, 6, 9, 2, 8, 2, 3, 8, 2, 8, 0, 6, 8, 9, 9, 6, 4, 0, 0, 4, 8, 2, 4, 3, 5, 4, 0, 3, 7, 0, 1, 4, 1, 6, 3,
+ 1, 4, 9, 6, 5, 8, 9, 7, 9, 4, 0, 9, 2, 4, 3, 2, 3, 7, 8, 9, 6, 9, 0, 7, 0, 6, 9, 7, 7, 9, 4, 2, 2, 3, 6, 2, 5, 0, 8, 2, 2, 1, 6, 8, 8, 9, 5, 7, 3, 8, 3, 7, 9, 8, 6, 2, 3, 0, 0, 1, 5, 9, 3, 7, 7, 6, 4, 7, 1, 6,
+ 5, 1, 2, 2, 8, 9, 3, 5, 7, 8, 6, 0, 1, 5, 8, 8, 1, 6, 1, 7, 5, 5, 7, 8, 2, 9, 7, 3, 5, 2, 3, 3, 4, 4, 6, 0, 4, 2, 8, 1, 5, 1, 2, 6, 2, 7, 2, 0, 3, 7, 3, 4, 3, 1, 4, 6, 5, 3, 1, 9, 7, 7, 7, 7, 4, 1, 6, 0, 3, 1,
+ 9, 9, 0, 6, 6, 5, 5, 4, 1, 8, 7, 6, 3, 9, 7, 9, 2, 9, 3, 3, 4, 4, 1, 9, 5, 2, 1, 5, 4, 1, 3, 4, 1, 8, 9, 9, 4, 8, 5, 4, 4, 4, 7, 3, 4, 5, 6, 7, 3, 8, 3, 1, 6, 2, 4, 9, 9, 3, 4, 1, 9, 1, 3, 1, 8, 1, 4, 8, 0, 9,
+ 2, 7, 7, 7, 7, 1, 0, 3, 8, 6, 3, 8, 7, 7, 3, 4, 3, 1, 7, 7, 2, 0, 7, 5, 4, 5, 6, 5, 4, 5, 3, 2, 2, 0, 7, 7, 7, 0, 9, 2, 1, 2, 0, 1, 9, 0, 5, 1, 6, 6, 0, 9, 6, 2, 8, 0, 4, 9, 0, 9, 2, 6, 3, 6, 0, 1, 9, 7, 5, 9,
+ 8, 8, 2, 8, 1, 6, 1, 3, 3, 2, 3, 1, 6, 6, 6, 3, 6, 5, 2, 8, 6, 1, 9, 3, 2, 6, 6, 8, 6, 3, 3, 6, 0, 6, 2, 7, 3, 5, 6, 7, 6, 3, 0, 3, 5, 4, 4, 7, 7, 6, 2, 8, 0, 3, 5, 0, 4, 5, 0, 7, 7, 7, 2, 3, 5, 5, 4, 7, 1, 0,
+ 5, 8, 5, 9, 5, 4, 8, 7, 0, 2, 7, 9, 0, 8, 1, 4, 3, 5, 6, 2, 4, 0, 1, 4, 5, 1, 7, 1, 8, 0, 6, 2, 4, 6, 4, 3, 6, 2, 6, 7, 9, 4, 5, 6, 1, 2, 7, 5, 3, 1, 8, 1, 3, 4, 0, 7, 8, 3, 3, 0, 3, 3, 6, 2, 5, 4, 2, 3, 2, 7,
+ 8, 3, 9, 4, 4, 9, 7, 5, 3, 8, 2, 4, 3, 7, 2, 0, 5, 8, 3, 5, 3, 1, 1, 4, 7, 7, 1, 1, 9, 9, 2, 6, 0, 6, 3, 8, 1, 3, 3, 4, 6, 7, 7, 6, 8, 7, 9, 6, 9, 5, 9, 7, 0, 3, 0, 9, 8, 3, 3, 9, 1, 3, 0, 7, 7, 1, 0, 9, 8, 7,
+ 0, 4, 0, 8, 5, 9, 1, 3, 3, 7, 4, 6, 4, 1, 4, 4, 2, 8, 2, 2, 7, 7, 2, 6, 3, 4, 6, 5, 9, 4, 7, 0, 4, 7, 4, 5, 8, 7, 8, 4, 7, 7, 8, 7, 2, 0, 1, 9, 2, 7, 7, 1, 5, 2, 8, 0, 7, 3, 1, 7, 6, 7, 9, 0, 7, 7, 0, 7, 1, 5,
+ 7, 2, 1, 3, 4, 4, 4, 7, 3, 0, 6, 0, 5, 7, 0, 0, 7, 3, 3, 4, 9, 2, 4, 3, 6, 9, 3, 1, 1, 3, 8, 3, 5, 0, 4, 9, 3, 1, 6, 3, 1, 2, 8, 4, 0, 4, 2, 5, 1, 2, 1, 9, 2, 5, 6, 5, 1, 7, 9, 8, 0, 6, 9, 4, 1, 1, 3, 5, 2, 8,
+ 0, 1, 3, 1, 4, 7, 0, 1, 3, 0, 4, 7, 8, 1, 6, 4, 3, 7, 8, 8, 5, 1, 8, 5, 2, 9, 0, 9, 2, 8, 5, 4, 5, 2, 0, 1, 1, 6, 5, 8, 3, 9, 3, 4, 1, 9, 6, 5, 6, 2, 1, 3, 4, 9, 1, 4, 3, 4, 1, 5, 9, 5, 6, 2, 5, 8, 6, 5, 8, 6,
+ 5, 5, 7, 0, 5, 5, 2, 6, 9, 0, 4, 9, 6, 5, 2, 0, 9, 8, 5, 8, 0, 3, 3, 8, 5, 0, 7, 2, 2, 4, 2, 6, 4, 8, 2, 9, 3, 9, 7, 2, 8, 5, 8, 4, 7, 8, 3, 1, 6, 3, 0, 5, 7, 7, 7, 7, 5, 6, 0, 6, 8, 8, 8, 7, 6, 4, 4, 6, 2, 4,
+ 8, 2, 4, 6, 8, 5, 7, 9, 2, 6, 0, 3, 9, 5, 3, 5, 2, 7, 7, 3, 4, 8, 0, 3, 0, 4, 8, 0, 2, 9, 0, 0, 5, 8, 7, 6, 0, 7, 5, 8, 2, 5, 1, 0, 4, 7, 4, 7, 0, 9, 1, 6, 4, 3, 9, 6, 1, 3, 6, 2, 6, 7, 6, 0, 4, 4, 9, 2, 5, 6,
+ 2, 7, 4, 2, 0, 4, 2, 0, 8, 3, 2, 0, 8, 5, 6, 6, 1, 1, 9, 0, 6, 2, 5, 4, 5, 4, 3, 3, 7, 2, 1, 3, 1, 5, 3, 5, 9, 5, 8, 4, 5, 0, 6, 8, 7, 7, 2, 4, 6, 0, 2, 9, 0, 1, 6, 1, 8, 7, 6, 6, 7, 9, 5, 2, 4, 0, 6, 1, 6, 3,
+ 4, 2, 5, 2, 2, 5, 7, 7, 1, 9, 5, 4, 2, 9, 1, 6, 2, 9, 9, 1, 9, 3, 0, 6, 4, 5, 5, 3, 7, 7, 9, 9, 1, 4, 0, 3, 7, 3, 4, 0, 4, 3, 2, 8, 7, 5, 2, 6, 2, 8, 8, 8, 9, 6, 3, 9, 9, 5, 8, 7, 9, 4, 7, 5, 7, 2, 9, 1, 7, 4,
+ 6, 4, 2, 6, 3, 5, 7, 4, 5, 5, 2, 5, 4, 0, 7, 9, 0, 9, 1, 4, 5, 1, 3, 5, 7, 1, 1, 1, 3, 6, 9, 4, 1, 0, 9, 1, 1, 9, 3, 9, 3, 2, 5, 1, 9, 1, 0, 7, 6, 0, 2, 0, 8, 2, 5, 2, 0, 2, 6, 1, 8, 7, 9, 8, 5, 3, 1, 8, 8, 7,
+ 7, 0, 5, 8, 4, 2, 9, 7, 2, 5, 9, 1, 6, 7, 7, 8, 1, 3, 1, 4, 9, 6, 9, 9, 0, 0, 9, 0, 1, 9, 2, 1, 1, 6, 9, 7, 1, 7, 3, 7, 2, 7, 8, 4, 7, 6, 8, 4, 7, 2, 6, 8, 6, 0, 8, 4, 9, 0, 0, 3, 3, 7, 7, 0, 2, 4, 2, 4, 2, 9,
+ 1, 6, 5, 1, 3, 0, 0, 5, 0, 0, 5, 1, 6, 8, 3, 2, 3, 3, 6, 4, 3, 5, 0, 3, 8, 9, 5, 1, 7, 0, 2, 9, 8, 9, 3, 9, 2, 2, 3, 3, 4, 5, 1, 7, 2, 2, 0, 1, 3, 8, 1, 2, 8, 0, 6, 9, 6, 5, 0, 1, 1, 7, 8, 4, 4, 0, 8, 7, 4, 5,
+ 1, 9, 6, 0, 1, 2, 1, 2, 2, 8, 5, 9, 9, 3, 7, 1, 6, 2, 3, 1, 3, 0, 1, 7, 1, 1, 4, 4, 4, 8, 4, 6, 4, 0, 9, 0, 3, 8, 9, 0, 6, 4, 4, 9, 5, 4, 4, 4, 0, 0, 6, 1, 9, 8, 6, 9, 0, 7, 5, 4, 8, 5, 1, 6, 0, 2, 6, 3, 2, 7,
+ 5, 0, 5, 2, 9, 8, 3, 4, 9, 1, 8, 7, 4, 0, 7, 8, 6, 6, 8, 0, 8, 8, 1, 8, 3, 3, 8, 5, 1, 0, 2, 2, 8, 3, 3, 4, 5, 0, 8, 5, 0, 4, 8, 6, 0, 8, 2, 5, 0, 3, 9, 3, 0, 2, 1, 3, 3, 2, 1, 9, 7, 1, 5, 5, 1, 8, 4, 3, 0, 6,
+ 3, 5, 4, 5, 5, 0, 0, 7, 6, 6, 8, 2, 8, 2, 9, 4, 9, 3, 0, 4, 1, 3, 7, 7, 6, 5, 5, 2, 7, 9, 3, 9, 7, 5, 1, 7, 5, 4, 6, 1, 3, 9, 5, 3, 9, 8, 4, 6, 8, 3, 3, 9, 3, 6, 3, 8, 3, 0, 4, 7, 4, 6, 1, 1, 9, 9, 6, 6, 5, 3,
+ 8, 5, 8, 1, 5, 3, 8, 4, 2, 0, 5, 6, 8, 5, 3, 3, 8, 6, 2, 1, 8, 6, 7, 2, 5, 2, 3, 3, 4, 0, 2, 8, 3, 0, 8, 7, 1, 1, 2, 3, 2, 8, 2, 7, 8, 9, 2, 1, 2, 5, 0, 7, 7, 1, 2, 6, 2, 9, 4, 6, 3, 2, 2, 9, 5, 6, 3, 9, 8, 9,
+ 8, 9, 8, 9, 3, 5, 8, 2, 1, 1, 6, 7, 4, 5, 6, 2, 7, 0, 1, 0, 2, 1, 8, 3, 5, 6, 4, 6, 2, 2, 0, 1, 3, 4, 9, 6, 7, 1, 5, 1, 8, 8, 1, 9, 0, 9, 7, 3, 0, 3, 8, 1, 1, 9, 8, 0, 0, 4, 9, 7, 3, 4, 0, 7, 2, 3, 9, 6, 1, 0,
+ 3, 6, 8, 5, 4, 0, 6, 6, 4, 3, 1, 9, 3, 9, 5, 0, 9, 7, 9, 0, 1, 9, 0, 6, 9, 9, 6, 3, 9, 5, 5, 2, 4, 5, 3, 0, 0, 5, 4, 5, 0, 5, 8, 0, 6, 8, 5, 5, 0, 1, 9, 5, 6, 7, 3, 0, 2, 2, 9, 2, 1, 9, 1, 3, 9, 3, 3, 9, 1, 8,
+ 5, 6, 8, 0, 3, 4, 4, 9, 0, 3, 9, 8, 2, 0, 5, 9, 5, 5, 1, 0, 0, 2, 2, 6, 3, 5, 3, 5, 3, 6, 1, 9, 2, 0, 4, 1, 9, 9, 4, 7, 4, 5, 5, 3, 8, 5, 9, 3, 8, 1, 0, 2, 3, 4, 3, 9, 5, 5, 4, 4, 9, 5, 9, 7, 7, 8, 3, 7, 7, 9,
+ 0, 2, 3, 7, 4, 2, 1, 6, 1, 7, 2, 7, 1, 1, 1, 7, 2, 3, 6, 4, 3, 4, 3, 5, 4, 3, 9, 4, 7, 8, 2, 2, 1, 8, 1, 8, 5, 2, 8, 6, 2, 4, 0, 8, 5, 1, 4, 0, 0, 6, 6, 6, 0, 4, 4, 3, 3, 2, 5, 8, 8, 8, 5, 6, 9, 8, 6, 7, 0, 5,
+ 4, 3, 1, 5, 4, 7, 0, 6, 9, 6, 5, 7, 4, 7, 4, 5, 8, 5, 5, 0, 3, 3, 2, 3, 2, 3, 3, 4, 2, 1, 0, 7, 3, 0, 1, 5, 4, 5, 9, 4, 0, 5, 1, 6, 5, 5, 3, 7, 9, 0, 6, 8, 6, 6, 2, 7, 3, 3, 3, 7, 9, 9, 5, 8, 5, 1, 1, 5, 6, 2,
+ 5, 7, 8, 4, 3, 2, 2, 9, 8, 8, 2, 7, 3, 7, 2, 3, 1, 9, 8, 9, 8, 7, 5, 7, 1, 4, 1, 5, 9, 5, 7, 8, 1, 1, 1, 9, 6, 3, 5, 8, 3, 3, 0, 0, 5, 9, 4, 0, 8, 7, 3, 0, 6, 8, 1, 2, 1, 6, 0, 2, 8, 7, 6, 4, 9, 6, 2, 8, 6, 7,
+ 4, 4, 6, 0, 4, 7, 7, 4, 6, 4, 9, 1, 5, 9, 9, 5, 0, 5, 4, 9, 7, 3, 7, 4, 2, 5, 6, 2, 6, 9, 0, 1, 0, 4, 9, 0, 3, 7, 7, 8, 1, 9, 8, 6, 8, 3, 5, 9, 3, 8, 1, 4, 6, 5, 7, 4, 1, 2, 6, 8, 0, 4, 9, 2, 5, 6, 4, 8, 7, 9,
+ 8, 5, 5, 6, 1, 4, 5, 3, 7, 2, 3, 4, 7, 8, 6, 7, 3, 3, 0, 3, 9, 0, 4, 6, 8, 8, 3, 8, 3, 4, 3, 6, 3, 4, 6, 5, 5, 3, 7, 9, 4, 9, 8, 6, 4, 1, 9, 2, 7, 0, 5, 6, 3, 8, 7, 2, 9, 3, 1, 7, 4, 8, 7, 2, 3, 3, 2, 0, 8, 3,
+ 7, 6, 0, 1, 1, 2, 3, 0, 2, 9, 9, 1, 1, 3, 6, 7, 9, 3, 8, 6, 2, 7, 0, 8, 9, 4, 3, 8, 7, 9, 9, 3, 6, 2, 0, 1, 6, 2, 9, 5, 1, 5, 4, 1, 3, 3, 7, 1, 4, 2, 4, 8, 9, 2, 8, 3, 0, 7, 2, 2, 0, 1, 2, 6, 9, 0, 1, 4, 7, 5,
+ 4, 6, 6, 8, 4, 7, 6, 5, 3, 5, 7, 6, 1, 6, 4, 7, 7, 3, 7, 9, 4, 6, 7, 5, 2, 0, 0, 4, 9, 0, 7, 5, 7, 1, 5, 5, 5, 2, 7, 8, 1, 9, 6, 5, 3, 6, 2, 1, 3, 2, 3, 9, 2, 6, 4, 0, 6, 1, 6, 0, 1, 3, 6, 3, 5, 8, 1, 5, 5, 9,
+ 0, 7, 4, 2, 2, 0, 2, 0, 2, 0, 3, 1, 8, 7, 2, 7, 7, 6, 0, 5, 2, 7, 7, 2, 1, 9, 0, 0, 5, 5, 6, 1, 4, 8, 4, 2, 5, 5, 5, 1, 8, 7, 9, 2, 5, 3, 0, 3, 4, 3, 5, 1, 3, 9, 8, 4, 4, 2, 5, 3, 2, 2, 3, 4, 1, 5, 7, 6, 2, 3,
+ 3, 6, 1, 0, 6, 4, 2, 5, 0, 6, 3, 9, 0, 4, 9, 7, 5, 0, 0, 8, 6, 5, 6, 2, 7, 1, 0, 9, 5, 3, 5, 9, 1, 9, 4, 6, 5, 8, 9, 7, 5, 1, 4, 1, 3, 1, 0, 3, 4, 8, 2, 2, 7, 6, 9, 3, 0, 6, 2, 4, 7, 4, 3, 5, 3, 6, 3, 2, 5, 6,
+ 9, 1, 6, 0, 7, 8, 1, 5, 4, 7, 8, 1, 8, 1, 1, 5, 2, 8, 4, 3, 6, 6, 7, 9, 5, 7, 0, 6, 1, 1, 0, 8, 6, 1, 5, 3, 3, 1, 5, 0, 4, 4, 5, 2, 1, 2, 7, 4, 7, 3, 9, 2, 4, 5, 4, 4, 9, 4, 5, 4, 2, 3, 6, 8, 2, 8, 8, 6, 0, 6,
+ 1, 3, 4, 0, 8, 4, 1, 4, 8, 6, 3, 7, 7, 6, 7, 0, 0, 9, 6, 1, 2, 0, 7, 1, 5, 1, 2, 4, 9, 1, 4, 0, 4, 3, 0, 2, 7, 2, 5, 3, 8, 6, 0, 7, 6, 4, 8, 2, 3, 6, 3, 4, 1, 4, 3, 3, 4, 6, 2, 3, 5, 1, 8, 9, 7, 5, 7, 6, 6, 4,
+ 5, 2, 1, 6, 4, 1, 3, 7, 6, 7, 9, 6, 9, 0, 3, 1, 4, 9, 5, 0, 1, 9, 1, 0, 8, 5, 7, 5, 9, 8, 4, 4, 2, 3, 9, 1, 9, 8, 6, 2, 9, 1, 6, 4, 2, 1, 9, 3, 9, 9, 4, 9, 0, 7, 2, 3, 6, 2, 3, 4, 6, 4, 6, 8, 4, 4, 1, 1, 7, 3,
+ 9, 4, 0, 3, 2, 6, 5, 9, 1, 8, 4, 0, 4, 4, 3, 7, 8, 0, 5, 1, 3, 3, 3, 8, 9, 4, 5, 2, 5, 7, 4, 2, 3, 9, 9, 5, 0, 8, 2, 9, 6, 5, 9, 1, 2, 2, 8, 5, 0, 8, 5, 5, 5, 8, 2, 1, 5, 7, 2, 5, 0, 3, 1, 0, 7, 1, 2, 5, 7, 0,
+ 1, 2, 6, 6, 8, 3, 0, 2, 4, 0, 2, 9, 2, 9, 5, 2, 5, 2, 2, 0, 1, 1, 8, 7, 2, 6, 7, 6, 7, 5, 6, 2, 2, 0, 4, 1, 5, 4, 2, 0, 5, 1, 6, 1, 8, 4, 1, 6, 3, 4, 8, 4, 7, 5, 6, 5, 1, 6, 9, 9, 9, 8, 1, 1, 6, 1, 4, 1, 0, 1,
+ 0, 0, 2, 9, 9, 6, 0, 7, 8, 3, 8, 6, 9, 0, 9, 2, 9, 1, 6, 0, 3, 0, 2, 8, 8, 4, 0, 0, 2, 6, 9, 1, 0, 4, 1, 4, 0, 7, 9, 2, 8, 8, 6, 2, 1, 5, 0, 7, 8, 4, 2, 4, 5, 1, 6, 7, 0, 9, 0, 8, 7, 0, 0, 0, 6, 9, 9, 2, 8, 2,
+ 1, 2, 0, 6, 6, 0, 4, 1, 8, 3, 7, 1, 8, 0, 6, 5, 3, 5, 5, 6, 7, 2, 5, 2, 5, 3, 2, 5, 6, 7, 5, 3, 2, 8, 6, 1, 2, 9, 1, 0, 4, 2, 4, 8, 7, 7, 6, 1, 8, 2, 5, 8, 2, 9, 7, 6, 5, 1, 5, 7, 9, 5, 9, 8, 4, 7, 0, 3, 5, 6,
+ 2, 2, 2, 6, 2, 9, 3, 4, 8, 6, 0, 0, 3, 4, 1, 5, 8, 7, 2, 2, 9, 8, 0, 5, 3, 4, 9, 8, 9, 6, 5, 0, 2, 2, 6, 2, 9, 1, 7, 4, 8, 7, 8, 8, 2, 0, 2, 7, 3, 4, 2, 0, 9, 2, 2, 2, 2, 4, 5, 3, 3, 9, 8, 5, 6, 2, 6, 4, 7, 6,
+ 6, 9, 1, 4, 9, 0, 5, 5, 6, 2, 8, 4, 2, 5, 0, 3, 9, 1, 2, 7, 5, 7, 7, 1, 0, 2, 8, 4, 0, 2, 7, 9, 9, 8, 0, 6, 6, 3, 6, 5, 8, 2, 5, 4, 8, 8, 9, 2, 6, 4, 8, 8, 0, 2, 5, 4, 5, 6, 6, 1, 0, 1, 7, 2, 9, 6, 7, 0, 2, 6,
+ 6, 4, 0, 7, 6, 5, 5, 9, 0, 4, 2, 9, 0, 9, 9, 4, 5, 6, 8, 1, 5, 0, 6, 5, 2, 6, 5, 3, 0, 5, 3, 7, 1, 8, 2, 9, 4, 1, 2, 7, 0, 3, 3, 6, 9, 3, 1, 3, 7, 8, 5, 1, 7, 8, 6, 0, 9, 0, 4, 0, 7, 0, 8, 6, 6, 7, 1, 1, 4, 9,
+ 6, 5, 5, 8, 3, 4, 3, 4, 3, 4, 7, 6, 9, 3, 3, 8, 5, 7, 8, 1, 7, 1, 1, 3, 8, 6, 4, 5, 5, 8, 7, 3, 6, 7, 8, 1, 2, 3, 0, 1, 4, 5, 8, 7, 6, 8, 7, 1, 2, 6, 6, 0, 3, 4, 8, 9, 1, 3, 9, 0, 9, 5, 6, 2, 0, 0, 9, 9, 3, 9,
+ 3, 6, 1, 0, 3, 1, 0, 2, 9, 1, 6, 1, 6, 1, 5, 2, 8, 8, 1, 3, 8, 4, 3, 7, 9, 0, 9, 9, 0, 4, 2, 3, 1, 7, 4, 7, 3, 3, 6, 3, 9, 4, 8, 0, 4, 5, 7, 5, 9, 3, 1, 4, 9, 3, 1, 4, 0, 5, 2, 9, 7, 6, 3, 4, 7, 5, 7, 4, 8, 1,
+ 1, 9, 3, 5, 6, 7, 0, 9, 1, 1, 0, 1, 3, 7, 7, 5, 1, 7, 2, 1, 0, 0, 8, 0, 3, 1, 5, 5, 9, 0, 2, 4, 8, 5, 3, 0, 9, 0, 6, 6, 9, 2, 0, 3, 7, 6, 7, 1, 9, 2, 2, 0, 3, 3, 2, 2, 9, 0, 9, 4, 3, 3, 4, 6, 7, 6, 8, 5, 1, 4,
+ 2, 2, 1, 4, 4, 7, 7, 3, 7, 9, 3, 9, 3, 7, 5, 1, 7, 0, 3, 4, 4, 3, 6, 6, 1, 9, 9, 1, 0, 4, 0, 3, 3, 7, 5, 1, 1, 1, 7, 3, 5, 4, 7, 1, 9, 1, 8, 5, 5, 0, 4, 6, 4, 4, 9, 0, 2, 6, 3, 6, 5, 5, 1, 2, 8, 1, 6, 2, 2, 8,
+ 8, 2, 4, 4, 6, 2, 5, 7, 5, 9, 1, 6, 3, 3, 3, 0, 3, 9, 1, 0, 7, 2, 2, 5, 3, 8, 3, 7, 4, 2, 1, 8, 2, 1, 4, 0, 8, 8, 3, 5, 0, 8, 6, 5, 7, 3, 9, 1, 7, 7, 1, 5, 0, 9, 6, 8, 2, 8, 8, 7, 4, 7, 8, 2, 6, 5, 6, 9, 9, 5,
+ 9, 9, 5, 7, 4, 4, 9, 0, 6, 6, 1, 7, 5, 8, 3, 4, 4, 1, 3, 7, 5, 2, 2, 3, 9, 7, 0, 9, 6, 8, 3, 4, 0, 8, 0, 0, 5, 3, 5, 5, 9, 8, 4, 9, 1, 7, 5, 4, 1, 7, 3, 8, 1, 8, 8, 3, 9, 9, 9, 4, 4, 6, 9, 7, 4, 8, 6, 7, 6, 2,
+ 6, 5, 5, 1, 6, 5, 8, 2, 7, 6, 5, 8, 4, 8, 3, 5, 8, 8, 4, 5, 3, 1, 4, 2, 7, 7, 5, 6, 8, 7, 9, 0, 0, 2, 9, 0, 9, 5, 1, 7, 0, 2, 8, 3, 5, 2, 9, 7, 1, 6, 3, 4, 4, 5, 6, 2, 1, 2, 9, 6, 4, 0, 4, 3, 5, 2, 3, 1, 1, 7,
+ 6, 0, 0, 6, 6, 5, 1, 0, 1, 2, 4, 1, 2, 0, 0, 6, 5, 9, 7, 5, 5, 8, 5, 1, 2, 7, 6, 1, 7, 8, 5, 8, 3, 8, 2, 9, 2, 0, 4, 1, 9, 7, 4, 8, 4, 4, 2, 3, 6, 0, 8, 0, 0, 7, 1, 9, 3, 0, 4, 5, 7, 6, 1, 8, 9, 3, 2, 3, 4, 9,
+ 2, 2, 9, 2, 7, 9, 6, 5, 0, 1, 9, 8, 7, 5, 1, 8, 7, 2, 1, 2, 7, 2, 6, 7, 5, 0, 7, 9, 8, 1, 2, 5, 5, 4, 7, 0, 9, 5, 8, 9, 0, 4, 5, 5, 6, 3, 5, 7, 9, 2, 1, 2, 2, 1, 0, 3, 3, 3, 4, 6, 6, 9, 7, 4, 9, 9, 2, 3, 5, 6,
+ 3, 0, 2, 5, 4, 9, 4, 7, 8, 0, 2, 4, 9, 0, 1, 1, 4, 1, 9, 5, 2, 1, 2, 3, 8, 2, 8, 1, 5, 3, 0, 9, 1, 1, 4, 0, 7, 9, 0, 7, 3, 8, 6, 0, 2, 5, 1, 5, 2, 2, 7, 4, 2, 9, 9, 5, 8, 1, 8, 0, 7, 2, 4, 7, 1, 6, 2, 5, 9, 1,
+ 6, 6, 8, 5, 4, 5, 1, 3, 3, 3, 1, 2, 3, 9, 4, 8, 0, 4, 9, 4, 7, 0, 7, 9, 1, 1, 9, 1, 5, 3, 2, 6, 7, 3, 4, 3, 0, 2, 8, 2, 4, 4, 1, 8, 6, 0, 4, 1, 4, 2, 6, 3, 6, 3, 9, 5, 4, 8, 0, 0, 0, 4, 4, 8, 0, 0, 2, 6, 7, 0,
+ 4, 9, 6, 2, 4, 8, 2, 0, 1, 7, 9, 2, 8, 9, 6, 4, 7, 6, 6, 9, 7, 5, 8, 3, 1, 8, 3, 2, 7, 1, 3, 1, 4, 2, 5, 1, 7, 0, 2, 9, 6, 9, 2, 3, 4, 8, 8, 9, 6, 2, 7, 6, 6, 8, 4, 4, 0, 3, 2, 3, 2, 6, 0, 9, 2, 7, 5, 2, 4, 9,
+ 6, 0, 3, 5, 7, 9, 9, 6, 4, 6, 9, 2, 5, 6, 5, 0, 4, 9, 3, 6, 8, 1, 8, 3, 6, 0, 9, 0, 0, 3, 2, 3, 8, 0, 9, 2, 9, 3, 4, 5,
+ 9, 5, 8, 8, 9, 7, 0, 6, 9, 5, 3, 6, 5, 3, 4, 9, 4, 0, 6, 0, 3, 4, 0, 2, 1, 6, 6, 5, 4, 4, 3, 7, 5, 5, 8, 9, 0, 0, 4, 5, 6, 3, 2, 8, 8, 2, 2, 5, 0, 5, 4, 5, 2, 5, 5, 6, 4, 0, 5, 6, 4, 4, 8, 2, 4, 6, 5, 1, 5, 1,
+ 8, 7, 5, 4, 7, 1, 1, 9, 6, 2, 1, 8, 4, 4, 3, 9, 6, 5, 8, 2, 5, 3, 3, 7, 5, 4, 3, 8, 8, 5, 6, 9, 0, 9, 4, 1, 1, 3, 0, 3, 1, 5, 0, 9, 5, 2, 6, 1, 7, 9, 3, 7, 8, 0, 0, 2, 9, 7, 4, 1, 2, 0, 7, 6, 6, 5, 1, 4, 7, 9,
+ 3, 9, 4, 2, 5, 9, 0, 2, 9, 8, 9, 6, 9, 5, 9, 4, 6, 9, 9, 5, 5, 6, 5, 7, 6, 1, 2, 1, 8, 6, 5, 6, 1, 9, 6, 7, 3, 3, 7, 8, 6, 2, 3, 6, 2, 5, 6, 1, 2, 5, 2, 1, 6, 3, 2, 0, 8, 6, 2, 8, 6, 9, 2, 2, 2, 1, 0, 3, 2, 7,
+ 4, 8, 8, 9, 2, 1, 8, 6, 5, 4, 3, 6, 4, 8, 0, 2, 2, 9, 6, 7, 8, 0, 7, 0, 5, 7, 6, 5, 6, 1, 5, 1, 4, 4, 6, 3, 2, 0, 4, 6, 9, 2, 7, 9, 0, 6, 8, 2, 1, 2, 0, 7, 3, 8, 8, 3, 7, 7, 8, 1, 4, 2, 3, 3, 5, 6, 2, 8, 2, 3,
+ 6, 0, 8, 9, 6, 3, 2, 0, 8, 0, 6, 8, 2, 2, 2, 4, 6, 8, 0, 1, 2, 2, 4, 8, 2, 6, 1, 1, 7, 7, 1, 8, 5, 8, 9, 6, 3, 8, 1, 4, 0, 9, 1, 8, 3, 9, 0, 3, 6, 7, 3, 6, 7, 2, 2, 2, 0, 8, 8, 8, 3, 2, 1, 5, 1, 3, 7, 5, 5, 6,
+ 0, 0, 3, 7, 2, 7, 9, 8, 3, 9, 4, 0, 0, 4, 1, 5, 2, 9, 7, 0, 0, 2, 8, 7, 8, 3, 0, 7, 6, 6, 7, 0, 9, 4, 4, 4, 7, 4, 5, 6, 0, 1, 3, 4, 5, 5, 6, 4, 1, 7, 2, 5, 4, 3, 7, 0, 9, 0, 6, 9, 7, 9, 3, 9, 6, 1, 2, 2, 5, 7,
+ 1, 4, 2, 9, 8, 9, 4, 6, 7, 1, 5, 4, 3, 5, 7, 8, 4, 6, 8, 7, 8, 8, 6, 1, 4, 4, 4, 5, 8, 1, 2, 3, 1, 4, 5, 9, 3, 5, 7, 1, 9, 8, 4, 9, 2, 2, 5, 2, 8, 4, 7, 1, 6, 0, 5, 0, 4, 9, 2, 2, 1, 2, 4, 2, 4, 7, 0, 1, 4, 1,
+ 2, 1, 4, 7, 8, 0, 5, 7, 3, 4, 5, 5, 1, 0, 5, 0, 0, 8, 0, 1, 9, 0, 8, 6, 9, 9, 6, 0, 3, 3, 0, 2, 7, 6, 3, 4, 7, 8, 7, 0, 8, 1, 0, 8, 1, 7, 5, 4, 5, 0, 1, 1, 9, 3, 0, 7, 1, 4, 1, 2, 2, 3, 3, 9, 0, 8, 6, 6, 3, 9,
+ 3, 8, 3, 3, 9, 5, 2, 9, 4, 2, 5, 7, 8, 6, 9, 0, 5, 0, 7, 6, 4, 3, 1, 0, 0, 6, 3, 8, 3, 5, 1, 9, 8, 3, 4, 3, 8, 9, 3, 4, 1, 5, 9, 6, 1, 3, 1, 8, 5, 4, 3, 4, 7, 5, 4, 6, 4, 9, 5, 5, 6, 9, 7, 8, 1, 0, 3, 8, 2, 9,
+ 3, 0, 9, 7, 1, 6, 4, 6, 5, 1, 4, 3, 8, 4, 0, 7, 0, 0, 7, 0, 7, 3, 6, 0, 4, 1, 1, 2, 3, 7, 3, 5, 9, 9, 8, 4, 3, 4, 5, 2, 2, 5, 1, 6, 1, 0, 5, 0, 7, 0, 2, 7, 0, 5, 6, 2, 3, 5, 2, 6, 6, 0, 1, 2, 7, 6, 4, 8, 4, 8,
+ 3, 0, 8, 4, 0, 7, 6, 1, 1, 8, 3, 0, 1, 3, 0, 5, 2, 7, 9, 3, 2, 0, 5, 4, 2, 7, 4, 6, 2, 8, 6, 5, 4, 0, 3, 6, 0, 3, 6, 7, 4, 5, 3, 2, 8, 6, 5, 1, 0, 5, 7, 0, 6, 5, 8, 7, 4, 8, 8, 2, 2, 5, 6, 9, 8, 1, 5, 7, 9, 3,
+ 6, 7, 8, 9, 7, 6, 6, 9, 7, 4, 2, 2, 0, 5, 7, 5, 0, 5, 9, 6, 8, 3, 4, 4, 0, 8, 6, 9, 7, 3, 5, 0, 2, 0, 1, 4, 1, 0, 2, 0, 6, 7, 2, 3, 5, 8, 5, 0, 2, 0, 0, 7, 2, 4, 5, 2, 2, 5, 6, 3, 2, 6, 5, 1, 3, 4, 1, 0, 5, 5,
+ 9, 2, 4, 0, 1, 9, 0, 2, 7, 4, 2, 1, 6, 2, 4, 8, 4, 3, 9, 1, 4, 0, 3, 5, 9, 9, 8, 9, 5, 3, 5, 3, 9, 4, 5, 9, 0, 9, 4, 4, 0, 7, 0, 4, 6, 9, 1, 2, 0, 9, 1, 4, 0, 9, 3, 8, 7, 0, 0, 1, 2, 6, 4, 5, 6, 0, 0, 1, 6, 2,
+ 3, 7, 4, 2, 8, 8, 0, 2, 1, 0, 9, 2, 7, 6, 4, 5, 7, 9, 3, 1, 0, 6, 5, 7, 9, 2, 2, 9, 5, 5, 2, 4, 9, 8, 8, 7, 2, 7, 5, 8, 4, 6, 1, 0, 1, 2, 6, 4, 8, 3, 6, 9, 9, 9, 8, 9, 2, 2, 5, 6, 9, 5, 9, 6, 8, 8, 1, 5, 9, 2,
+ 0, 5, 6, 0, 0, 1, 0, 1, 6, 5, 5, 2, 5, 6, 3, 7, 5, 6, 7, 8
+ };
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java
new file mode 100644
index 0000000..155a247
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessageQueueTest.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Message;
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.MediumTest;
+import junit.framework.TestCase;
+
+public class MessageQueueTest extends TestCase {
+
+ private static class BaseTestHandler extends TestHandlerThread {
+ Handler mHandler;
+ int mLastMessage;
+ int mCount;
+
+ public BaseTestHandler() {
+ }
+
+ public void go() {
+ mHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ BaseTestHandler.this.handleMessage(msg);
+ }
+ };
+ }
+
+ public void handleMessage(Message msg) {
+ if (mCount <= mLastMessage) {
+ if (msg.what != mCount) {
+ failure(new RuntimeException(
+ "Expected message #" + mCount
+ + ", received #" + msg.what));
+ } else if (mCount == mLastMessage) {
+ success();
+ }
+ mCount++;
+ } else {
+ failure(new RuntimeException(
+ "Message received after done, #" + msg.what));
+ }
+ }
+ }
+
+ @MediumTest
+ public void testMessageOrder() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ public void go() {
+ super.go();
+ long now = SystemClock.uptimeMillis() + 200;
+ mLastMessage = 4;
+ mCount = 0;
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(2), now + 1);
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now + 2);
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(4), now + 2);
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(0), now + 0);
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(1), now + 0);
+ }
+ };
+
+ tester.doTest(1000);
+ }
+
+ @MediumTest
+ public void testAtFrontOfQueue() throws Exception {
+ TestHandlerThread tester = new BaseTestHandler() {
+ public void go() {
+ super.go();
+ long now = SystemClock.uptimeMillis() + 200;
+ mLastMessage = 3;
+ mCount = 0;
+ mHandler.sendMessageAtTime(mHandler.obtainMessage(3), now);
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(2));
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(0));
+ }
+
+ public void handleMessage(Message msg) {
+ super.handleMessage(msg);
+ if (msg.what == 0) {
+ mHandler.sendMessageAtFrontOfQueue(mHandler.obtainMessage(1));
+ }
+ }
+ };
+
+ tester.doTest(1000);
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java
new file mode 100644
index 0000000..9228a43f
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerService.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.RemoteException;
+import android.os.IBinder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Messenger;
+
+public class MessengerService extends Service {
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ Message reply = Message.obtain();
+ reply.copyFrom(msg);
+ try {
+ msg.replyTo.send(reply);
+ } catch (RemoteException e) {
+ }
+ }
+ };
+
+ private final Messenger mMessenger = new Messenger(mHandler);
+
+ public MessengerService() {
+ }
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mMessenger.getBinder();
+ }
+}
+
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java
new file mode 100644
index 0000000..2a3e204d
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/MessengerTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.RemoteException;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.Messenger;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class MessengerTest extends AndroidTestCase {
+ private Messenger mServiceMessenger;
+
+ private ServiceConnection mConnection = new ServiceConnection() {
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ synchronized (MessengerTest.this) {
+ mServiceMessenger = new Messenger(service);
+ MessengerTest.this.notifyAll();
+ }
+ }
+ public void onServiceDisconnected(ComponentName name) {
+ mServiceMessenger = null;
+ }
+ };
+
+ private class TestThread extends TestHandlerThread {
+ private Handler mTestHandler;
+ private Messenger mTestMessenger;
+
+ public void go() {
+ synchronized (MessengerTest.this) {
+ mTestHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ TestThread.this.handleMessage(msg);
+ }
+ };
+ mTestMessenger = new Messenger(mTestHandler);
+ TestThread.this.executeTest();
+ }
+ }
+
+ public void executeTest() {
+ Message msg = Message.obtain();
+ msg.arg1 = 100;
+ msg.arg2 = 1000;
+ msg.replyTo = mTestMessenger;
+ try {
+ mServiceMessenger.send(msg);
+ } catch (RemoteException e) {
+ }
+ }
+
+ public void handleMessage(Message msg) {
+ if (msg.arg1 != 100) {
+ failure(new RuntimeException(
+ "Message.arg1 is not 100: " + msg.arg1));
+ return;
+ }
+ if (msg.arg2 != 1000) {
+ failure(new RuntimeException(
+ "Message.arg2 is not 1000: " + msg.arg2));
+ return;
+ }
+ if (!mTestMessenger.equals(msg.replyTo)) {
+ failure(new RuntimeException(
+ "Message.replyTo is not me: " + msg.replyTo));
+ return;
+ }
+ success();
+ }
+ };
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ getContext().bindService(new Intent(mContext, MessengerService.class),
+ mConnection, Context.BIND_AUTO_CREATE);
+ synchronized (this) {
+ while (mServiceMessenger == null) {
+ try {
+ wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ getContext().unbindService(mConnection);
+ }
+
+ @MediumTest
+ public void testSend() {
+ (new TestThread()).doTest(1000);
+
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java
new file mode 100644
index 0000000..bf02509
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/OsTests.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import com.google.android.collect.Lists;
+import junit.framework.TestSuite;
+
+import java.util.Enumeration;
+import java.util.List;
+
+public class OsTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(OsTests.class.getName());
+
+ suite.addTestSuite(AidlTest.class);
+ suite.addTestSuite(BroadcasterTest.class);
+ suite.addTestSuite(FileObserverTest.class);
+ suite.addTestSuite(IdleHandlerTest.class);
+ suite.addTestSuite(MemoryFileTest.class);
+ suite.addTestSuite(MessageQueueTest.class);
+ suite.addTestSuite(MessengerTest.class);
+ suite.addTestSuite(PowerManagerTest.class);
+ suite.addTestSuite(SystemPropertiesTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java
new file mode 100644
index 0000000..bd5c955
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/PowerManagerTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.content.Context;
+import android.os.PowerManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class PowerManagerTest extends AndroidTestCase {
+
+ private PowerManager mPm;
+
+ /**
+ * Setup any common data for the upcoming tests.
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mPm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
+ }
+
+ /**
+ * Confirm that the setup is good.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testPreconditions() throws Exception {
+ assertNotNull(mPm);
+ }
+
+ /**
+ * Confirm that we can create functional wakelocks.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testNewWakeLock() throws Exception {
+ PowerManager.WakeLock wl = mPm.newWakeLock(PowerManager.FULL_WAKE_LOCK, "FULL_WAKE_LOCK");
+ doTestWakeLock(wl);
+
+ wl = mPm.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK, "SCREEN_BRIGHT_WAKE_LOCK");
+ doTestWakeLock(wl);
+
+ wl = mPm.newWakeLock(PowerManager.SCREEN_DIM_WAKE_LOCK, "SCREEN_DIM_WAKE_LOCK");
+ doTestWakeLock(wl);
+
+ wl = mPm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "PARTIAL_WAKE_LOCK");
+ doTestWakeLock(wl);
+
+ // TODO: Some sort of functional test (maybe not in the unit test here?)
+ // that confirms that things are really happening e.g. screen power, keyboard power.
+}
+
+ /**
+ * Confirm that we can't create dysfunctional wakelocks.
+ *
+ * @throws Exception
+ */
+ @MediumTest
+ public void testBadNewWakeLock() throws Exception {
+
+ final int badFlags = PowerManager.SCREEN_BRIGHT_WAKE_LOCK
+ | PowerManager.SCREEN_DIM_WAKE_LOCK;
+ // wrap in try because we want the error here
+ try {
+ PowerManager.WakeLock wl = mPm.newWakeLock(badFlags, "foo");
+ } catch (IllegalArgumentException e) {
+ return;
+ }
+ fail("Bad WakeLock flag was not caught.");
+ }
+
+ /**
+ * Apply a few tests to a wakelock to make sure it's healthy.
+ *
+ * @param wl The wakelock to be tested.
+ */
+ private void doTestWakeLock(PowerManager.WakeLock wl) {
+ // First try simple acquire/release
+ wl.acquire();
+ assertTrue(wl.isHeld());
+ wl.release();
+ assertFalse(wl.isHeld());
+
+ // Try ref-counted acquire/release
+ wl.setReferenceCounted(true);
+ wl.acquire();
+ assertTrue(wl.isHeld());
+ wl.acquire();
+ assertTrue(wl.isHeld());
+ wl.release();
+ assertTrue(wl.isHeld());
+ wl.release();
+ assertFalse(wl.isHeld());
+
+ // Try non-ref-counted
+ wl.setReferenceCounted(false);
+ wl.acquire();
+ assertTrue(wl.isHeld());
+ wl.acquire();
+ assertTrue(wl.isHeld());
+ wl.release();
+ assertFalse(wl.isHeld());
+
+ // TODO: Threaded test (needs handler) to make sure timed wakelocks work too
+ }
+
+
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java
new file mode 100644
index 0000000..df08bb9
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/SystemPropertiesTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import static junit.framework.Assert.assertEquals;
+import junit.framework.TestCase;
+
+import android.os.SystemProperties;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class SystemPropertiesTest extends TestCase {
+ private static final String KEY = "com.android.unit_tests";
+ @SmallTest
+ public void testProperties() throws Exception {
+ if (false) {
+ String value;
+
+ SystemProperties.set(KEY, "");
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
+ SystemProperties.set(KEY, "AAA");
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("AAA", value);
+
+ value = SystemProperties.get(KEY);
+ assertEquals("AAA", value);
+
+ SystemProperties.set(KEY, "");
+ value = SystemProperties.get(KEY, "default");
+ assertEquals("default", value);
+
+ value = SystemProperties.get(KEY);
+ assertEquals("", value);
+ }
+ }
+}
diff --git a/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java
new file mode 100644
index 0000000..dba8dde
--- /dev/null
+++ b/tests/AndroidTests/src/com/android/unit_tests/os/TestHandlerThread.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.unit_tests.os;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.MessageQueue.IdleHandler;
+
+abstract class TestHandlerThread {
+ private boolean mDone = false;
+ private boolean mSuccess = false;
+ private RuntimeException mFailure = null;
+ private Looper mLooper;
+
+ public abstract void go();
+
+ public TestHandlerThread() {
+ }
+
+ public void doTest(long timeout) {
+ (new LooperThread()).start();
+
+ synchronized (this) {
+ long now = System.currentTimeMillis();
+ long endTime = now + timeout;
+ while (!mDone && now < endTime) {
+ try {
+ wait(endTime-now);
+ }
+ catch (InterruptedException e) {
+ }
+ now = System.currentTimeMillis();
+ }
+ }
+
+ mLooper.quit();
+
+ if (!mDone) {
+ throw new RuntimeException("test timed out");
+ }
+ if (!mSuccess) {
+ throw mFailure;
+ }
+ }
+
+ public Looper getLooper() {
+ return mLooper;
+ }
+
+ public void success() {
+ synchronized (this) {
+ mSuccess = true;
+ quit();
+ }
+ }
+
+ public void failure(RuntimeException failure) {
+ synchronized (this) {
+ mSuccess = false;
+ mFailure = failure;
+ quit();
+ }
+ }
+
+ class LooperThread extends Thread {
+ public void run() {
+ Looper.prepare();
+ mLooper = Looper.myLooper();
+ go();
+ Looper.loop();
+
+ synchronized (TestHandlerThread.this) {
+ mDone = true;
+ if (!mSuccess && mFailure == null) {
+ mFailure = new RuntimeException("no failure exception set");
+ }
+ TestHandlerThread.this.notifyAll();
+ }
+ }
+
+ }
+
+ private void quit() {
+ synchronized (this) {
+ mDone = true;
+ notifyAll();
+ }
+ }
+}
diff --git a/tests/CoreTests/Android.mk b/tests/CoreTests/Android.mk
new file mode 100644
index 0000000..8338432
--- /dev/null
+++ b/tests/CoreTests/Android.mk
@@ -0,0 +1,2 @@
+include $(call all-subdir-makefiles)
+
diff --git a/tests/CoreTests/MODULE_LICENSE_APACHE2 b/tests/CoreTests/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/CoreTests/MODULE_LICENSE_APACHE2
diff --git a/tests/CoreTests/android/Android.mk b/tests/CoreTests/android/Android.mk
new file mode 100644
index 0000000..e6b5c45
--- /dev/null
+++ b/tests/CoreTests/android/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := \
+ $(call all-subdir-java-files)
+LOCAL_SRC_FILES += \
+ $(call all-java-files-under, ../com)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := CoreTests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/CoreTests/android/AndroidManifest.xml b/tests/CoreTests/android/AndroidManifest.xml
new file mode 100644
index 0000000..4809f844
--- /dev/null
+++ b/tests/CoreTests/android/AndroidManifest.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.core">
+ <uses-permission android:name="android.permission.RECEIVE_SMS"/>
+ <uses-permission android:name="android.permission.INTERNET" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+ <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+
+ <!-- location test permissions -->
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
+ <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
+ <uses-permission android:name="android.permission.WRITE_SETTINGS"/>
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.FOR_TESTS_ONLY"/>
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.test.TestBrowserTests" android:label="Test Browser Tests">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.UNIT_TEST"/>
+ </intent-filter>
+ </activity>
+ </application>
+
+ <instrumentation
+ android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="android.core"
+ android:label="Core Tests" />
+</manifest>
diff --git a/tests/CoreTests/android/content/ObserverNodeTest.java b/tests/CoreTests/android/content/ObserverNodeTest.java
new file mode 100644
index 0000000..68cc75b
--- /dev/null
+++ b/tests/CoreTests/android/content/ObserverNodeTest.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import java.util.ArrayList;
+
+import android.content.ContentService.ObserverCall;
+import android.content.ContentService.ObserverNode;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class ObserverNodeTest extends AndroidTestCase {
+ static class TestObserver extends ContentObserver {
+ public TestObserver() {
+ super(new Handler());
+ }
+ }
+
+ public void testUri() {
+ ObserverNode root = new ObserverNode("");
+ Uri[] uris = new Uri[] {
+ Uri.parse("content://c/a/"),
+ Uri.parse("content://c/"),
+ Uri.parse("content://x/"),
+ Uri.parse("content://c/b/"),
+ Uri.parse("content://c/a/a1/1/"),
+ Uri.parse("content://c/a/a1/2/"),
+ Uri.parse("content://c/b/1/"),
+ Uri.parse("content://c/b/2/"),
+ };
+
+ int[] nums = new int[] {4, 7, 1, 4, 2, 2, 3, 3};
+
+ // special case
+ root.addObserver(uris[0], new TestObserver().getContentObserver(), false);
+ for(int i = 1; i < uris.length; i++) {
+ root.addObserver(uris[i], new TestObserver().getContentObserver(), true);
+ }
+
+ ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
+
+ for (int i = nums.length - 1; i >=0; --i) {
+ root.collectObservers(uris[i], 0, null, false, calls);
+ assertEquals(nums[i], calls.size());
+ calls.clear();
+ }
+ }
+
+ public void testUriNotNotify() {
+ ObserverNode root = new ObserverNode("");
+ Uri[] uris = new Uri[] {
+ Uri.parse("content://c/"),
+ Uri.parse("content://x/"),
+ Uri.parse("content://c/a/"),
+ Uri.parse("content://c/b/"),
+ Uri.parse("content://c/a/1/"),
+ Uri.parse("content://c/a/2/"),
+ Uri.parse("content://c/b/1/"),
+ Uri.parse("content://c/b/2/"),
+ };
+ int[] nums = new int[] {7, 1, 3, 3, 1, 1, 1, 1};
+
+ for(int i = 0; i < uris.length; i++) {
+ root.addObserver(uris[i], new TestObserver().getContentObserver(), false);
+ }
+
+ ArrayList<ObserverCall> calls = new ArrayList<ObserverCall>();
+
+ for (int i = uris.length - 1; i >=0; --i) {
+ root.collectObservers(uris[i], 0, null, false, calls);
+ assertEquals(nums[i], calls.size());
+ calls.clear();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/content/SyncStorageEngineTest.java b/tests/CoreTests/android/content/SyncStorageEngineTest.java
new file mode 100644
index 0000000..36805b1
--- /dev/null
+++ b/tests/CoreTests/android/content/SyncStorageEngineTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.test.AndroidTestCase;
+import android.test.RenamingDelegatingContext;
+import android.test.mock.MockContext;
+import android.test.mock.MockContentResolver;
+import android.provider.Sync;
+
+public class SyncStorageEngineTest extends AndroidTestCase {
+
+ /**
+ * Test that we handle the case of a history row being old enough to purge before the
+ * correcponding sync is finished. This can happen if the clock changes while we are syncing.
+ */
+ public void testPurgeActiveSync() throws Exception {
+ final String account = "a@example.com";
+ final String authority = "testprovider";
+
+ MockContentResolver mockResolver = new MockContentResolver();
+
+ SyncStorageEngine engine = SyncStorageEngine.newTestInstance(
+ new TestContext(mockResolver, getContext()));
+
+ long time0 = 1000;
+ long historyId = engine.insertStartSyncEvent(
+ account, authority, time0, Sync.History.SOURCE_LOCAL);
+ long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
+ engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
+ }
+}
+
+class TestContext extends ContextWrapper {
+
+ ContentResolver mResolver;
+
+ public TestContext(ContentResolver resolver, Context realContext) {
+ super(new RenamingDelegatingContext(new MockContext(), realContext, "test."));
+ mResolver = resolver;
+ }
+
+ @Override
+ public void enforceCallingOrSelfPermission(String permission, String message) {
+ }
+
+
+ @Override
+ public ContentResolver getContentResolver() {
+ return mResolver;
+ }
+}
diff --git a/tests/CoreTests/android/core/AbstractJDBCDriverTest.java b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java
new file mode 100644
index 0000000..e381a5e
--- /dev/null
+++ b/tests/CoreTests/android/core/AbstractJDBCDriverTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests for the most commonly used methods of sql like creating a connection,
+ * inserting, selecting, updating.
+ */
+public abstract class AbstractJDBCDriverTest extends TestCase {
+
+ @MediumTest
+ public void testJDBCDriver() throws Exception {
+ Connection firstConnection = null;
+ Connection secondConnection = null;
+ File dbFile = getDbFile();
+ String connectionURL = getConnectionURL();
+ Statement firstStmt = null;
+ Statement secondStmt = null;
+ try {
+ Class.forName(getJDBCDriverClassName());
+ firstConnection = DriverManager.getConnection(connectionURL);
+ secondConnection = DriverManager.getConnection(connectionURL);
+
+ String[] ones = {"hello!", "goodbye"};
+ short[] twos = {10, 20};
+ String[] onesUpdated = new String[ones.length];
+ for (int i = 0; i < ones.length; i++) {
+ onesUpdated[i] = ones[i] + twos[i];
+ }
+ firstStmt = firstConnection.createStatement();
+ firstStmt.execute("create table tbl1(one varchar(10), two smallint)");
+ secondStmt = secondConnection.createStatement();
+
+ autoCommitInsertSelectTest(firstStmt, ones, twos);
+ updateSelectCommitSelectTest(firstStmt, secondStmt, ones, onesUpdated, twos);
+ updateSelectRollbackSelectTest(firstStmt, secondStmt, onesUpdated, ones, twos);
+ } finally {
+ closeConnections(firstConnection, secondConnection, dbFile, firstStmt, secondStmt);
+ }
+ }
+
+ protected abstract String getJDBCDriverClassName();
+ protected abstract String getConnectionURL();
+ protected abstract File getDbFile();
+
+ private void closeConnections(Connection firstConnection, Connection secondConnection,
+ File dbFile, Statement firstStmt, Statement secondStmt) {
+ String failText = null;
+ try {
+ if (firstStmt != null) {
+ firstStmt.execute("drop table tbl1");
+ }
+ } catch (SQLException e) {
+ failText = e.getLocalizedMessage();
+ }
+ try {
+ if (firstStmt != null) {
+ firstStmt.close();
+ }
+ } catch (SQLException e) {
+ failText = e.getLocalizedMessage();
+ }
+ try {
+ if (firstConnection != null) {
+ firstConnection.close();
+ }
+ } catch (SQLException e) {
+ failText = e.getLocalizedMessage();
+ }
+ try {
+ if (secondStmt != null) {
+ secondStmt.close();
+ }
+ } catch (SQLException e) {
+ failText = e.getLocalizedMessage();
+ }
+ try {
+ if (secondConnection != null) {
+ secondConnection.close();
+ }
+ } catch (SQLException e) {
+ failText = e.getLocalizedMessage();
+ }
+ dbFile.delete();
+ assertNull(failText, failText);
+ }
+
+ /**
+ * Inserts the values from 'ones' with the values from 'twos' into 'tbl1'
+ * @param stmt the statement to use for the inserts.
+ * @param ones the string values to insert into tbl1.
+ * @param twos the corresponding numerical values to insert into tbl1.
+ * @throws SQLException in case of a problem during insert.
+ */
+ private void autoCommitInsertSelectTest(Statement stmt, String[] ones,
+ short[] twos) throws SQLException {
+ for (int i = 0; i < ones.length; i++) {
+ stmt.execute("insert into tbl1 values('" + ones[i] + "'," + twos[i]
+ + ")");
+ }
+ assertAllFromTbl1(stmt, ones, twos);
+ }
+
+ /**
+ * Asserts that all values that where added to tbl1 are actually in tbl1.
+ * @param stmt the statement to use for the select.
+ * @param ones the string values that where added.
+ * @param twos the numerical values that where added.
+ * @throws SQLException in case of a problem during select.
+ */
+ private void assertAllFromTbl1(Statement stmt, String[] ones, short[] twos)
+ throws SQLException {
+ ResultSet rs = stmt.executeQuery("select * from tbl1");
+ int i = 0;
+ for (; rs.next(); i++) {
+ assertTrue(i < ones.length);
+ assertEquals(ones[i], rs.getString("one"));
+ assertEquals(twos[i], rs.getShort("two"));
+ }
+ assertEquals(i, ones.length);
+ }
+
+ /**
+ * Tests the results of an update followed bz a select on a diffrent statement.
+ * After that the first statement commits its update. and now the second
+ * statement should also be able to see the changed values in a select.
+ * @param firstStmt the statement to use for the update and commit.
+ * @param secondStmt the statement that should be used to check if the commit works
+ * @param ones the original string values.
+ * @param onesUpdated the updated string values.
+ * @param twos the numerical values.
+ * @throws SQLException in case of a problem during any of the executed commands.
+ */
+ private void updateSelectCommitSelectTest(Statement firstStmt,
+ Statement secondStmt, String[] ones, String[] onesUpdated,
+ short[] twos) throws SQLException {
+ firstStmt.getConnection().setAutoCommit(false);
+ try {
+ updateOnes(firstStmt, onesUpdated, twos);
+ assertAllFromTbl1(secondStmt, ones, twos);
+ firstStmt.getConnection().commit();
+ assertAllFromTbl1(secondStmt, onesUpdated, twos);
+ } finally {
+ firstStmt.getConnection().setAutoCommit(true);
+ }
+ }
+
+ /**
+ * Tests if an update followed by a select works. After that a rollback will
+ * be made and again a select should show that the rollback worked.
+ * @param firstStmt the statement to use for the update and the rollback
+ * @param secondStmt the statement to use for checking if the rollback worked as intended.
+ * @param ones the original string values.
+ * @param onesUpdated the updated string values.
+ * @param twos the nomerical values.
+ * @throws SQLException in case of a problem during any command.
+ */
+ private void updateSelectRollbackSelectTest(Statement firstStmt,
+ Statement secondStmt, String[] ones, String[] onesUpdated,
+ short[] twos) throws SQLException {
+ firstStmt.getConnection().setAutoCommit(false);
+ try {
+ updateOnes(firstStmt, onesUpdated, twos);
+ assertAllFromTbl1(secondStmt, ones, twos);
+ firstStmt.getConnection().rollback();
+ assertAllFromTbl1(secondStmt, ones, twos);
+ } finally {
+ firstStmt.getConnection().setAutoCommit(true);
+ }
+ }
+
+ /**
+ * updates the sring values. the original values are stored in 'ones'
+ * and the updated values in 'ones_updated'
+ * @param stmt the statement to use for the update.
+ * @param onesUpdated the new string values.
+ * @param twos the numerical values.
+ * @throws SQLException in case of a problem during update.
+ */
+ private void updateOnes(Statement stmt, String[] onesUpdated, short[] twos)
+ throws SQLException {
+ for (int i = 0; i < onesUpdated.length; i++) {
+ stmt.execute("UPDATE tbl1 SET one = '" + onesUpdated[i]
+ + "' WHERE two = " + twos[i]);
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/ArrayListTest.java b/tests/CoreTests/android/core/ArrayListTest.java
new file mode 100644
index 0000000..763bf99
--- /dev/null
+++ b/tests/CoreTests/android/core/ArrayListTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * This test case tests several often used functionality of ArrayLists.
+ */
+public class ArrayListTest extends TestCase {
+
+ @SuppressWarnings("unchecked")
+ @SmallTest
+ public void testArrayList() throws Exception {
+ ArrayList array = new ArrayList();
+ assertEquals(0, array.size());
+ assertTrue(array.isEmpty());
+
+ array.add(new Integer(0));
+ array.add(0, new Integer(1));
+ array.add(1, new Integer(2));
+ array.add(new Integer(3));
+ array.add(new Integer(1));
+
+ assertEquals(5, array.size());
+ assertFalse(array.isEmpty());
+
+ assertEquals(1, ((Integer) array.get(0)).intValue());
+ assertEquals(2, ((Integer) array.get(1)).intValue());
+ assertEquals(0, ((Integer) array.get(2)).intValue());
+ assertEquals(3, ((Integer) array.get(3)).intValue());
+ assertEquals(1, ((Integer) array.get(4)).intValue());
+
+ assertFalse(array.contains(null));
+ assertTrue(array.contains(new Integer(2)));
+ assertEquals(0, array.indexOf(new Integer(1)));
+ assertEquals(4, array.lastIndexOf(new Integer(1)));
+ assertTrue(array.indexOf(new Integer(5)) < 0);
+ assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+
+ array.remove(1);
+ array.remove(1);
+
+ assertEquals(3, array.size());
+ assertFalse(array.isEmpty());
+ assertEquals(1, ((Integer) array.get(0)).intValue());
+ assertEquals(3, ((Integer) array.get(1)).intValue());
+ assertEquals(1, ((Integer) array.get(2)).intValue());
+
+ assertFalse(array.contains(null));
+ assertFalse(array.contains(new Integer(2)));
+ assertEquals(0, array.indexOf(new Integer(1)));
+ assertEquals(2, array.lastIndexOf(new Integer(1)));
+ assertTrue(array.indexOf(new Integer(5)) < 0);
+ assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+ array.clear();
+
+ assertEquals(0, array.size());
+ assertTrue(array.isEmpty());
+ assertTrue(array.indexOf(new Integer(5)) < 0);
+ assertTrue(array.lastIndexOf(new Integer(5)) < 0);
+
+ ArrayList al = new ArrayList();
+
+ assertFalse(al.remove(null));
+ assertFalse(al.remove("string"));
+
+ al.add("string");
+ al.add(null);
+
+ assertTrue(al.remove(null));
+ assertTrue(al.remove("string"));
+ }
+}
+
diff --git a/tests/CoreTests/android/core/AtParserTest.java b/tests/CoreTests/android/core/AtParserTest.java
new file mode 100644
index 0000000..09cb6e9
--- /dev/null
+++ b/tests/CoreTests/android/core/AtParserTest.java
@@ -0,0 +1,348 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.bluetooth.AtCommandHandler;
+import android.bluetooth.AtCommandResult;
+import android.bluetooth.AtParser;
+
+import java.util.*;
+import junit.framework.*;
+
+public class AtParserTest extends TestCase {
+
+ /* An AtCommandHandler instrumented for testing purposes
+ */
+ private class HandlerTest extends AtCommandHandler {
+ boolean mBasicCalled, mActionCalled, mReadCalled, mTestCalled,
+ mSetCalled;
+ int mBasicReturn, mActionReturn, mReadReturn, mTestReturn, mSetReturn;
+ Object[] mSetArgs;
+ String mBasicArgs;
+
+ HandlerTest() {
+ this(AtCommandResult.ERROR, AtCommandResult.ERROR,
+ AtCommandResult.ERROR, AtCommandResult.ERROR,
+ AtCommandResult.ERROR);
+ }
+
+ HandlerTest(int a, int b, int c, int d, int e) {
+ mBasicReturn = a;
+ mActionReturn = b;
+ mReadReturn = c;
+ mSetReturn = d;
+ mTestReturn = e;
+ reset();
+ }
+ public void reset() {
+ mBasicCalled = false;
+ mActionCalled = false;
+ mReadCalled = false;
+ mSetCalled = false;
+ mTestCalled = false;
+ mSetArgs = null;
+ mBasicArgs = null;
+ }
+ public boolean wasCalled() { // helper
+ return mBasicCalled || mActionCalled || mReadCalled ||
+ mTestCalled || mSetCalled;
+ }
+ @Override
+ public AtCommandResult handleBasicCommand(String args) {
+ mBasicCalled = true;
+ mBasicArgs = args;
+ return new AtCommandResult(mBasicReturn);
+ }
+ @Override
+ public AtCommandResult handleActionCommand() {
+ mActionCalled = true;
+ return new AtCommandResult(mActionReturn);
+ }
+ @Override
+ public AtCommandResult handleReadCommand() {
+ mReadCalled = true;
+ return new AtCommandResult(mReadReturn);
+ }
+ @Override
+ public AtCommandResult handleSetCommand(Object[] args) {
+ mSetCalled = true;
+ mSetArgs = args;
+ return new AtCommandResult(mSetReturn);
+ }
+ @Override
+ public AtCommandResult handleTestCommand() {
+ mTestCalled = true;
+ return new AtCommandResult(mTestReturn);
+ }
+ }
+
+ private AtParser mParser;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mParser = new AtParser();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ }
+
+
+ /* Test that the right method is being called
+ */
+/* public void testBasic1() throws Exception {
+ HandlerTest D = new HandlerTest(0, 1, 1, 1, 1);
+ HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+ mParser.register('D', D);
+ mParser.register('A', A);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process(" A T D = ? T 1 2 3 4 ").toStrings()));
+ assertTrue(D.mBasicCalled);
+ assertFalse(D.mActionCalled);
+ assertFalse(D.mTestCalled);
+ assertFalse(D.mSetCalled);
+ assertFalse(D.mReadCalled);
+ assertFalse(A.wasCalled());
+ assertEquals("=?T1234", D.mBasicArgs);
+ }
+*/
+ /* Test some crazy strings
+ *//*
+ public void testBasic2() throws Exception {
+ HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+ mParser.register('A', A);
+
+ assertTrue(Arrays.equals(
+ new String[]{},
+ mParser.process(" ").toStrings()));
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process(" a T a t \"\" 1 2 3 a 4 ")
+ .toStrings()));
+ assertEquals("T\"\"123A4", A.mBasicArgs);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process(" a T a t \"foo BaR12Z\" 1 2 3 a 4 ")
+ .toStrings()));
+ assertEquals("T\"foo BaR12Z\"123A4", A.mBasicArgs);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("ATA\"").toStrings()));
+ assertEquals("\"\"", A.mBasicArgs);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("ATA\"a").toStrings()));
+ assertEquals("\"a\"", A.mBasicArgs);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("ATa\" ").toStrings()));
+ assertEquals("\" \"", A.mBasicArgs);
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("ATA \"one \" two \"t hr ee ")
+ .toStrings()));
+ assertEquals("\"one \"TWO\"t hr ee \"", A.mBasicArgs);
+ }*/
+
+ /* Simple extended commands
+ *//*
+ public void testExt1() throws Exception {
+ HandlerTest A = new HandlerTest(1, 0, 0, 0, 0);
+ mParser.register("+A", A);
+
+ assertTrue(Arrays.equals(
+ new String[]{"ERROR"},
+ mParser.process("AT+B").toStrings()));
+ assertFalse(A.wasCalled());
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+A").toStrings()));
+ assertTrue(A.mActionCalled);
+ A.mActionCalled = false;
+ assertFalse(A.wasCalled());
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+A=").toStrings()));
+ assertTrue(A.mSetCalled);
+ A.mSetCalled = false;
+ assertFalse(A.wasCalled());
+ assertEquals(1, A.mSetArgs.length);
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+A=?").toStrings()));
+ assertTrue(A.mTestCalled);
+ A.mTestCalled = false;
+ assertFalse(A.wasCalled());
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+A?").toStrings()));
+ assertTrue(A.mReadCalled);
+ A.mReadCalled = false;
+ assertFalse(A.wasCalled());
+ A.reset();
+ }
+*/
+
+
+ /* Test chained commands
+ *//*
+ public void testChain1() throws Exception {
+ HandlerTest A = new HandlerTest(0, 1, 1, 1, 1);
+ HandlerTest B = new HandlerTest(1, 0, 0, 0, 0);
+ HandlerTest C = new HandlerTest(1, 1, 1, 1, 1);
+ mParser.register('A', A);
+ mParser.register("+B", B);
+ mParser.register("+C", C);
+
+ assertTrue(Arrays.equals(
+ new String[]{"ERROR"},
+ mParser.process("AT+B;+C").toStrings()));
+ assertTrue(B.mActionCalled);
+ assertTrue(C.mActionCalled);
+ B.reset();
+ C.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"ERROR"},
+ mParser.process("AT+C;+B").toStrings()));
+ assertFalse(B.wasCalled());
+ assertTrue(C.mActionCalled);
+ B.reset();
+ C.reset();
+ }*/
+
+ /* Test Set command
+ *//*
+ public void testSet1() throws Exception {
+ HandlerTest A = new HandlerTest(1, 1, 1, 0, 1);
+ mParser.register("+AAAA", A);
+ Object[] expectedResult;
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=1").toStrings()));
+ expectedResult = new Object[]{(Integer)1};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=1,2,3").toStrings()));
+ expectedResult = new Object[]{(Integer)1, (Integer)2, (Integer)3};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=3,0,0,1").toStrings()));
+ expectedResult = new Object[]{(Integer)3, (Integer)0, (Integer)0,
+ (Integer)1};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=\"foo\",1,\"b,ar").toStrings()));
+ expectedResult = new Object[]{"\"foo\"", 1, "\"b,ar\""};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=").toStrings()));
+ expectedResult = new Object[]{""};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=,").toStrings()));
+ expectedResult = new Object[]{"", ""};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=,,,").toStrings()));
+ expectedResult = new Object[]{"", "", "", ""};
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("AT+AAAA=,1,,\"foo\",").toStrings()));
+ expectedResult = new Object[]{"", 1, "", "\"foo\"", ""};
+ assertEquals(5, A.mSetArgs.length);
+ assertTrue(Arrays.equals(expectedResult, A.mSetArgs));
+ A.reset();
+ }*/
+
+ /* Test repeat command "A/"
+ *//*
+ public void testRepeat() throws Exception {
+ HandlerTest A = new HandlerTest(0, 0, 0, 0, 0);
+ mParser.register('A', A);
+
+ // Try repeated command on fresh parser
+ assertTrue(Arrays.equals(
+ new String[]{},
+ mParser.process("A/").toStrings()));
+ assertFalse(A.wasCalled());
+ A.reset();
+
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("ATA").toStrings()));
+ assertTrue(A.mBasicCalled);
+ assertEquals("", A.mBasicArgs);
+ A.reset();
+
+ // Now repeat the command
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("A/").toStrings()));
+ assertTrue(A.mBasicCalled);
+ assertEquals("", A.mBasicArgs);
+ A.reset();
+
+ // Multiple repeats
+ assertTrue(Arrays.equals(
+ new String[]{"OK"},
+ mParser.process("A/").toStrings()));
+ assertTrue(A.mBasicCalled);
+ assertEquals("", A.mBasicArgs);
+ A.reset();
+
+ }*/
+}
diff --git a/tests/CoreTests/android/core/BooleanTest.java b/tests/CoreTests/android/core/BooleanTest.java
new file mode 100644
index 0000000..211947e
--- /dev/null
+++ b/tests/CoreTests/android/core/BooleanTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests some basic functionality of Booleans.
+ */
+public class BooleanTest extends TestCase {
+
+ @SmallTest
+ public void testBoolean() throws Exception {
+ Boolean a = new Boolean(true);
+ Boolean b = new Boolean("True");
+ Boolean c = new Boolean(false);
+ Boolean d = new Boolean("Yes");
+
+ assertEquals(a, b);
+ assertEquals(c, d);
+ assertTrue(a.booleanValue());
+ assertFalse(c.booleanValue());
+ assertEquals("true", a.toString());
+ assertEquals("false", c.toString());
+ assertEquals(Boolean.TRUE, a);
+ assertEquals(Boolean.FALSE, c);
+ assertSame(Boolean.valueOf(true), Boolean.TRUE);
+ assertSame(Boolean.valueOf(false), Boolean.FALSE);
+ }
+}
+
diff --git a/tests/CoreTests/android/core/BufferedInputStreamTest.java b/tests/CoreTests/android/core/BufferedInputStreamTest.java
new file mode 100644
index 0000000..1ad95a1
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedInputStreamTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedInputStreams.
+ */
+public class BufferedInputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testBufferedInputStream() throws Exception {
+ String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+ ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ea = new ByteArrayInputStream(str.getBytes());
+
+ BufferedInputStream a = new BufferedInputStream(aa, 6);
+ try {
+ assertEquals(str, IOUtil.read(a));
+ } finally {
+ a.close();
+ }
+
+ BufferedInputStream b = new BufferedInputStream(ba, 7);
+ try {
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ BufferedInputStream c = new BufferedInputStream(ca, 9);
+ try {
+ assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+
+ BufferedInputStream d = new BufferedInputStream(da, 9);
+ try {
+ assertEquals('A', d.read());
+ d.mark(15);
+ assertEquals('b', d.read());
+ assertEquals('C', d.read());
+ d.reset();
+ assertEquals('b', d.read());
+ } finally {
+ d.close();
+ }
+
+ BufferedInputStream e = new BufferedInputStream(ea, 11);
+ try {
+ // test that we can ask for more than is present, and that we'll get
+ // back only what is there.
+ assertEquals(str, IOUtil.read(e, 10000));
+ } finally {
+ e.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/BufferedOutputStreamTest.java b/tests/CoreTests/android/core/BufferedOutputStreamTest.java
new file mode 100644
index 0000000..cd8ec08
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedOutputStreamTest.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedOutputStream;
+import java.io.ByteArrayOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedOutputStreams.
+ */
+public class BufferedOutputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testBufferedOutputStream() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ ByteArrayOutputStream aa = new ByteArrayOutputStream();
+ BufferedOutputStream a = new BufferedOutputStream(aa, 15);
+ try {
+ a.write(str.getBytes(), 0, 26);
+ a.write('A');
+
+ assertEquals(26, aa.size());
+ assertEquals(aa.toString(), str);
+
+ a.flush();
+
+ assertEquals(27, aa.size());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString());
+ } finally {
+ a.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/BufferedReaderTest.java b/tests/CoreTests/android/core/BufferedReaderTest.java
new file mode 100644
index 0000000..a94ca02
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedReaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests to verify that simple functionality works for BufferedReaders.
+ */
+public class BufferedReaderTest extends TestCase {
+
+ @MediumTest
+ public void testBufferedReader() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ StringReader aa = new StringReader(str);
+ StringReader ba = new StringReader(str);
+ StringReader ca = new StringReader(str);
+ StringReader da = new StringReader(str);
+
+ BufferedReader a = new BufferedReader(aa, 5);
+ try {
+ assertEquals(str, IOUtil.read(a));
+ } finally {
+ a.close();
+ }
+
+ BufferedReader b = new BufferedReader(ba, 15);
+ try {
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ BufferedReader c = new BufferedReader(ca);
+ try {
+ assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+
+ BufferedReader d = new BufferedReader(da);
+ try {
+ assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+ } finally {
+ d.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/BufferedWriterTest.java b/tests/CoreTests/android/core/BufferedWriterTest.java
new file mode 100644
index 0000000..12dfcef2
--- /dev/null
+++ b/tests/CoreTests/android/core/BufferedWriterTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedWriter;
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Some basic tests for BufferedWriter.
+ */
+public class BufferedWriterTest extends TestCase {
+
+ @SmallTest
+ public void testBufferedWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ StringWriter aa = new StringWriter();
+
+ BufferedWriter a = new BufferedWriter(aa, 20);
+ try {
+ a.write(str.toCharArray(), 0, 26);
+ a.write('X');
+ a.flush();
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString());
+
+ a.write("alphabravodelta", 5, 5);
+ a.flush();
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo", aa.toString());
+ a.newLine();
+ a.write("I'm on a new line.");
+ a.flush();
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravo\nI\'m on a new line.", aa.toString());
+ } finally {
+ a.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/ByteArrayInputStreamTest.java b/tests/CoreTests/android/core/ByteArrayInputStreamTest.java
new file mode 100644
index 0000000..d964102
--- /dev/null
+++ b/tests/CoreTests/android/core/ByteArrayInputStreamTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests to verify that simple functionality works for ByteArrayInputStreams.
+ */
+public class ByteArrayInputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testByteArrayInputStream() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+
+ ByteArrayInputStream a = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream b = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream c = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream d = new ByteArrayInputStream(str.getBytes());
+
+ assertEquals(str, IOUtil.read(a));
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+ assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+ }
+}
diff --git a/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java
new file mode 100644
index 0000000..e605214
--- /dev/null
+++ b/tests/CoreTests/android/core/ByteArrayOutputStreamTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * A basic test for ByteArrayOutputStraem.
+ */
+public class ByteArrayOutputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testByteArrayOutputStream() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ ByteArrayOutputStream a = new ByteArrayOutputStream();
+ ByteArrayOutputStream b = new ByteArrayOutputStream(10);
+
+ a.write(str.getBytes(), 0, 26);
+ a.write('X');
+ a.writeTo(b);
+
+ assertEquals(27, a.size());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", b.toString());
+ }
+}
diff --git a/tests/CoreTests/android/core/CharArrayReaderTest.java b/tests/CoreTests/android/core/CharArrayReaderTest.java
new file mode 100644
index 0000000..50a217a
--- /dev/null
+++ b/tests/CoreTests/android/core/CharArrayReaderTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.CharArrayReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for CharArrayReader.
+ */
+public class CharArrayReaderTest extends TestCase {
+
+ @SmallTest
+ public void testCharArrayReader() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ CharArrayReader a = new CharArrayReader(str.toCharArray());
+ CharArrayReader b = new CharArrayReader(str.toCharArray());
+ CharArrayReader c = new CharArrayReader(str.toCharArray());
+ CharArrayReader d = new CharArrayReader(str.toCharArray());
+
+ assertEquals(str, IOUtil.read(a));
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+ assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+ }
+}
diff --git a/tests/CoreTests/android/core/CharArrayWriterTest.java b/tests/CoreTests/android/core/CharArrayWriterTest.java
new file mode 100644
index 0000000..0aae1e4
--- /dev/null
+++ b/tests/CoreTests/android/core/CharArrayWriterTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.CharArrayWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for CharArrayWriter.
+ */
+public class CharArrayWriterTest extends TestCase {
+
+ @SmallTest
+ public void testCharArrayWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ CharArrayWriter a = new CharArrayWriter();
+ CharArrayWriter b = new CharArrayWriter();
+
+ a.write(str, 0, 26);
+ a.write('X');
+ a.writeTo(b);
+
+ assertEquals(27, a.size());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+
+ b.write("alphabravodelta", 5, 5);
+ b.append('X');
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", b.toString());
+ b.append("omega");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", b.toString());
+ }
+}
diff --git a/tests/CoreTests/android/core/ChecksumTest.java b/tests/CoreTests/android/core/ChecksumTest.java
new file mode 100644
index 0000000..24fb739
--- /dev/null
+++ b/tests/CoreTests/android/core/ChecksumTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.util.zip.Adler32;
+import java.util.zip.CRC32;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * tests for CRC32 and Adler32 checksum algorithms.
+ */
+public class ChecksumTest extends TestCase {
+
+ @SmallTest
+ public void testChecksum() throws Exception {
+ /*
+ * Values computed experimentally, using C interfaces.
+ */
+ adler32Test(mTestString, 0x9de210dbL);
+ cRC32Test(mTestString, 0x939f04afL);
+
+ // Test for issue 1016037
+ wrongChecksumWithAdler32Test();
+ }
+
+ private void adler32Test(byte[] values, long expected) {
+ Adler32 adler = new Adler32();
+
+ // try it all at once
+ adler.update(values);
+ assertEquals(adler.getValue(), expected);
+
+ // try resetting and computing one byte at a time
+ adler.reset();
+ for (int i = 0; i < values.length; i++) {
+ adler.update(values[i]);
+ }
+ assertEquals(adler.getValue(), expected);
+ }
+
+ private void cRC32Test(byte[] values, long expected) {
+ CRC32 crc = new CRC32();
+
+ // try it all at once
+ crc.update(values);
+ assertEquals(crc.getValue(), expected);
+
+ // try resetting and computing one byte at a time
+ crc.reset();
+ for (int i = 0; i < values.length; i++) {
+ crc.update(values[i]);
+ }
+ assertEquals(crc.getValue(), expected);
+ }
+
+ // "The quick brown fox jumped over the lazy dogs\n"
+ private static byte[] mTestString = {
+ 0x54, 0x68, 0x65, 0x20, 0x71, 0x75, 0x69, 0x63,
+ 0x6b, 0x20, 0x62, 0x72, 0x6f, 0x77, 0x6e, 0x20,
+ 0x66, 0x6f, 0x78, 0x20, 0x6a, 0x75, 0x6d, 0x70,
+ 0x65, 0x64, 0x20, 0x6f, 0x76, 0x65, 0x72, 0x20,
+ 0x74, 0x68, 0x65, 0x20, 0x6c, 0x61, 0x7a, 0x79,
+ 0x20, 0x64, 0x6f, 0x67, 0x73, 0x2e, 0x0a
+ };
+
+
+ // Test for issue 1016037
+ private void wrongChecksumWithAdler32Test() {
+ byte[] bytes = {1, 0, 5, 0, 15, 0, 1, 11, 0, 1};
+ Adler32 adler = new Adler32();
+ adler.update(bytes);
+ long arrayChecksum = adler.getValue();
+ adler.reset();
+ for (int i = 0; i < bytes.length; i++) {
+ adler.update(bytes[i]);
+ }
+ assertEquals("Checksums not equal: expected: " + arrayChecksum +
+ " actual: " + adler.getValue(), arrayChecksum, adler.getValue());
+ }
+}
+
diff --git a/tests/CoreTests/android/core/ClassLoaderTest.java b/tests/CoreTests/android/core/ClassLoaderTest.java
new file mode 100644
index 0000000..5e7f5a48
--- /dev/null
+++ b/tests/CoreTests/android/core/ClassLoaderTest.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Test for basic ClassLoader functionality.
+ */
+@Suppress
+public class ClassLoaderTest extends TestCase {
+ /*
+ package my.pkg;
+ public class CLTest {
+ public CLTest() {}
+
+ public String test() { return "This is test 1"; }
+ }
+ */
+ static private byte[] test1class = {
+ (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31,
+ (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08,
+ (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00,
+ (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10,
+ (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c,
+ (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74,
+ (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+ (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01,
+ (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f,
+ (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e,
+ (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d,
+ (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54,
+ (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65,
+ (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+ (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29,
+ (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+ (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61,
+ (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53,
+ (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e,
+ (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75,
+ (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46,
+ (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c,
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+ (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05,
+ (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69,
+ (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73,
+ (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x20, (byte) 0x31, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79,
+ (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67,
+ (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+ (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61,
+ (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c,
+ (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f,
+ (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65,
+ (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
+ (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01,
+ (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12,
+ (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c
+ };
+
+ /*
+ package my.pkg;
+ public class CLTest {
+ public CLTest() {}
+
+ public String test() { return "This is test 2"; }
+ }
+ */
+ static private byte[] test2class = {
+ (byte) 0xca, (byte) 0xfe, (byte) 0xba, (byte) 0xbe,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x31,
+ (byte) 0x00, (byte) 0x11, (byte) 0x0a, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x0d, (byte) 0x08,
+ (byte) 0x00, (byte) 0x0e, (byte) 0x07, (byte) 0x00,
+ (byte) 0x0f, (byte) 0x07, (byte) 0x00, (byte) 0x10,
+ (byte) 0x01, (byte) 0x00, (byte) 0x06, (byte) 0x3c,
+ (byte) 0x69, (byte) 0x6e, (byte) 0x69, (byte) 0x74,
+ (byte) 0x3e, (byte) 0x01, (byte) 0x00, (byte) 0x03,
+ (byte) 0x28, (byte) 0x29, (byte) 0x56, (byte) 0x01,
+ (byte) 0x00, (byte) 0x04, (byte) 0x43, (byte) 0x6f,
+ (byte) 0x64, (byte) 0x65, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0f, (byte) 0x4c, (byte) 0x69, (byte) 0x6e,
+ (byte) 0x65, (byte) 0x4e, (byte) 0x75, (byte) 0x6d,
+ (byte) 0x62, (byte) 0x65, (byte) 0x72, (byte) 0x54,
+ (byte) 0x61, (byte) 0x62, (byte) 0x6c, (byte) 0x65,
+ (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x74,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+ (byte) 0x00, (byte) 0x14, (byte) 0x28, (byte) 0x29,
+ (byte) 0x4c, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+ (byte) 0x61, (byte) 0x2f, (byte) 0x6c, (byte) 0x61,
+ (byte) 0x6e, (byte) 0x67, (byte) 0x2f, (byte) 0x53,
+ (byte) 0x74, (byte) 0x72, (byte) 0x69, (byte) 0x6e,
+ (byte) 0x67, (byte) 0x3b, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0a, (byte) 0x53, (byte) 0x6f, (byte) 0x75,
+ (byte) 0x72, (byte) 0x63, (byte) 0x65, (byte) 0x46,
+ (byte) 0x69, (byte) 0x6c, (byte) 0x65, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x43, (byte) 0x4c,
+ (byte) 0x54, (byte) 0x65, (byte) 0x73, (byte) 0x74,
+ (byte) 0x2e, (byte) 0x6a, (byte) 0x61, (byte) 0x76,
+ (byte) 0x61, (byte) 0x0c, (byte) 0x00, (byte) 0x05,
+ (byte) 0x00, (byte) 0x06, (byte) 0x01, (byte) 0x00,
+ (byte) 0x0e, (byte) 0x54, (byte) 0x68, (byte) 0x69,
+ (byte) 0x73, (byte) 0x20, (byte) 0x69, (byte) 0x73,
+ (byte) 0x20, (byte) 0x74, (byte) 0x65, (byte) 0x73,
+ (byte) 0x74, (byte) 0x20, (byte) 0x32, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0d, (byte) 0x6d, (byte) 0x79,
+ (byte) 0x2f, (byte) 0x70, (byte) 0x6b, (byte) 0x67,
+ (byte) 0x2f, (byte) 0x43, (byte) 0x4c, (byte) 0x54,
+ (byte) 0x65, (byte) 0x73, (byte) 0x74, (byte) 0x01,
+ (byte) 0x00, (byte) 0x10, (byte) 0x6a, (byte) 0x61,
+ (byte) 0x76, (byte) 0x61, (byte) 0x2f, (byte) 0x6c,
+ (byte) 0x61, (byte) 0x6e, (byte) 0x67, (byte) 0x2f,
+ (byte) 0x4f, (byte) 0x62, (byte) 0x6a, (byte) 0x65,
+ (byte) 0x63, (byte) 0x74, (byte) 0x00, (byte) 0x21,
+ (byte) 0x00, (byte) 0x03, (byte) 0x00, (byte) 0x04,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x05, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x07,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x1d,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x05,
+ (byte) 0x2a, (byte) 0xb7, (byte) 0x00, (byte) 0x01,
+ (byte) 0xb1, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x08, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x06, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00,
+ (byte) 0x04, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x09, (byte) 0x00, (byte) 0x0a, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x07, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x1b, (byte) 0x00,
+ (byte) 0x01, (byte) 0x00, (byte) 0x01, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00, (byte) 0x03, (byte) 0x12,
+ (byte) 0x02, (byte) 0xb0, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x08,
+ (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x06,
+ (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x06, (byte) 0x00, (byte) 0x01,
+ (byte) 0x00, (byte) 0x0b, (byte) 0x00, (byte) 0x00,
+ (byte) 0x00, (byte) 0x02, (byte) 0x00, (byte) 0x0c
+ };
+
+ /*
+ * Custom class loader.
+ */
+ private class MyLoader extends ClassLoader {
+ public MyLoader(byte[] data) {
+ super();
+ mData = data;
+ }
+
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ assertEquals("my.pkg.CLTest", name);
+ return defineClass(name, mData, 0, mData.length);
+ }
+
+ byte[] mData;
+ }
+
+
+ /*
+ * Simple test: manually load two class files that have the same class
+ * name but different contents.
+ */
+ public void testClassLoader() throws Exception {
+ Class test1, test2;
+ MyLoader loader1 = new MyLoader(test1class);
+ MyLoader loader2 = new MyLoader(test2class);
+
+ test1 = loader1.loadClass("my.pkg.CLTest");
+ test2 = loader2.loadClass("my.pkg.CLTest");
+
+ methodTest(test1, "This is test 1");
+ methodTest(test2, "This is test 2");
+ }
+
+ /*
+ * Invoke the test() method and verify that the string returned
+ * matches what we expect.
+ */
+ private static void methodTest(Class clazz, String expect)
+ throws NoSuchMethodException, InstantiationException,
+ IllegalAccessException, InvocationTargetException {
+ Method meth = clazz.getMethod("test", (Class[]) null);
+ Object obj = clazz.newInstance();
+ Object result = meth.invoke(obj, (Object[]) null);
+
+ assertEquals(result, expect);
+ }
+}
+
diff --git a/tests/CoreTests/android/core/ClassTest.java b/tests/CoreTests/android/core/ClassTest.java
new file mode 100644
index 0000000..cc1b4ca
--- /dev/null
+++ b/tests/CoreTests/android/core/ClassTest.java
@@ -0,0 +1,337 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.widget.Button;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashSet;
+import java.util.Set;
+
+
+class ClassWithPrivateConstructor {
+ private ClassWithPrivateConstructor() {
+ }
+}
+
+public class ClassTest extends TestCase {
+
+ @SmallTest
+ public void testClass() throws Exception {
+ // Now, never mind the fact that most of this stuff has to work
+ // for the test harness to get this far....
+
+ //System.out.println("Class.forName()");
+ Class helloClass = Class.forName(ClassTest.class.getName());
+
+ //System.out.println("Class.newInstance()");
+ Object instance = helloClass.newInstance();
+ assertNotNull(instance);
+
+ //System.out.println("Class.forName() nonexisting class");
+ try {
+ Class.forName("this.class.DoesNotExist");
+ fail("unexpected success");
+ } catch (ClassNotFoundException ex) {
+ // expected
+ }
+
+ //System.out.println("Class.newInstance() private constructor");
+ try {
+ Class.forName("android.core.ClassWithPrivateConstructor").newInstance();
+ fail("unexpected success");
+ } catch (IllegalAccessException ex) {
+ // this is expected
+ }
+
+ //System.out.println("Class.getDeclaredMethod()");
+
+ Method method = helloClass.getDeclaredMethod("method", (Class[]) null);
+
+ method.invoke(new ClassTest(), (Object[]) null);
+
+ //System.out.println("Class.getDeclaredMethod() w/ args");
+
+ method = helloClass.getDeclaredMethod("methodWithArgs", Object.class);
+
+ Object invokeArgs[] = new Object[1];
+ invokeArgs[0] = "Hello";
+ Object ret = method.invoke(new ClassTest(), invokeArgs);
+ assertEquals(ret, invokeArgs[0]);
+
+ //System.out.println("Class.getDeclaredMethod() -- private");
+
+ method = helloClass.getDeclaredMethod("privateMethod", (Class[]) null);
+
+ method.invoke(new ClassTest(), (Object[]) null);
+ //fail("unexpected success");
+ // TODO: I think this actually *should* succeed, because the
+ // call to the private method is being made from the same class.
+ // This needs to be replaced with a private call to a different
+ // class.
+
+ //System.out.println("Class.getSuperclass");
+ Class objectClass = Class.forName("java.lang.Object");
+ assertEquals(helloClass.getSuperclass().getSuperclass().getSuperclass(), objectClass);
+
+ //System.out.println("Class.isAssignableFrom");
+ assertTrue(objectClass.isAssignableFrom(helloClass));
+ assertFalse(helloClass.isAssignableFrom(objectClass));
+
+ //System.out.println("Class.getConstructor");
+
+ Constructor constructor = helloClass.getConstructor((Class[]) null);
+ assertNotNull(constructor);
+
+ //System.out.println("Class.getModifiers");
+
+ assertTrue(Modifier.isPublic(helloClass.getModifiers()));
+ //System.out.println("Modifiers: " + Modifier.toString(helloClass.getModifiers()));
+
+ //System.out.println("Class.getMethod");
+
+ helloClass.getMethod("method", (Class[]) null);
+
+ try {
+ Class[] argTypes = new Class[1];
+ argTypes[0] = helloClass;
+ helloClass.getMethod("method", argTypes);
+ fail("unexpected success");
+ } catch (NoSuchMethodException ex) {
+ // exception expected
+ }
+
+ // Test for public tracker issue 14
+ SimpleClass obj = new SimpleClass();
+ Field field = obj.getClass().getDeclaredField("str");
+ field.set(obj, null);
+ }
+
+ public class SimpleClass {
+ public String str;
+ }
+
+ public Object methodWithArgs(Object o) {
+ return o;
+ }
+
+ boolean methodInvoked;
+
+ public void method() {
+ methodInvoked = true;
+ }
+
+ boolean privateMethodInvoked;
+
+ public void privateMethod() {
+ privateMethodInvoked = true;
+ }
+
+ // Regression for 1018067: Class.getMethods() returns the same method over
+ // and over again from all base classes
+ @MediumTest
+ public void testClassGetMethodsNoDupes() {
+ Method[] methods = Button.class.getMethods();
+ Set<String> set = new HashSet<String>();
+
+ for (int i = 0; i < methods.length; i++) {
+ String signature = methods[i].toString();
+
+ int par = signature.indexOf('(');
+ int dot = signature.lastIndexOf('.', par);
+
+ signature = signature.substring(dot + 1);
+
+ assertFalse("Duplicate " + signature, set.contains(signature));
+ set.add(signature);
+ }
+ }
+
+ interface MyInterface {
+ void foo();
+ }
+
+ interface MyOtherInterface extends MyInterface {
+ void bar();
+ }
+
+ abstract class MyClass implements MyOtherInterface {
+ public void gabba() {
+ }
+
+ public void hey() {
+ }
+ }
+
+ // Check if we also reflect methods from interfaces
+ @SmallTest
+ public void testGetMethodsInterfaces() {
+ Method[] methods = MyInterface.class.getMethods();
+ assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+
+ methods = MyOtherInterface.class.getMethods();
+ assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+ assertTrue("Interface method must be there", hasMethod(methods, ".bar("));
+
+ methods = MyClass.class.getMethods();
+ assertTrue("Interface method must be there", hasMethod(methods, ".foo("));
+ assertTrue("Interface method must be there", hasMethod(methods, ".bar("));
+
+ assertTrue("Declared method must be there", hasMethod(methods, ".gabba("));
+ assertTrue("Declared method must be there", hasMethod(methods, ".hey("));
+
+ assertTrue("Inherited method must be there", hasMethod(methods, ".toString("));
+ }
+
+ private boolean hasMethod(Method[] methods, String signature) {
+ for (int i = 0; i < methods.length; i++) {
+ if (methods[i].toString().contains(signature)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ // Test for Class.getPackage();
+ @SmallTest
+ public void testClassGetPackage() {
+ assertNotNull("Package must be non-null", getClass().getPackage());
+ assertEquals("Package must have expected name", "android.core", getClass().getPackage().getName());
+ assertEquals("Package must have expected title", "Unknown", getClass().getPackage().getSpecificationTitle());
+
+ Package p = java.lang.Object.class.getPackage();
+ assertNotNull("Package must be non-null", p);
+ assertEquals("Package must have expected name", "java.lang", p.getName());
+ assertSame("Package object must be same for each call", p, java.lang.Object.class.getPackage());
+ }
+
+ // Regression test for #1123708: Problem with getCanonicalName(),
+ // getSimpleName(), and getPackage().
+ //
+ // A couple of interesting cases need to be checked: Top-level classes,
+ // member classes, local classes, and anonymous classes. Also, boundary
+ // cases with '$' in the class names are checked, since the '$' is used
+ // as the separator between outer and inner class, so this might lead
+ // to problems (it did in the previous implementation).
+ //
+ // Caution: Adding local or anonymous classes elsewhere in this
+ // file might affect the test.
+ private class MemberClass {
+ // This space intentionally left blank.
+ }
+
+ private class Mi$o$oup {
+ // This space intentionally left blank.
+ }
+
+ @SmallTest
+ public void testVariousClassNames() {
+ Class<?> clazz = this.getClass();
+ String pkg = (clazz.getPackage() == null ? "" : clazz.getPackage().getName() + ".");
+
+ // Simple, top-level class
+
+ assertEquals("Top-level class name must be correct", pkg + "ClassTest", clazz.getName());
+ assertEquals("Top-level class simple name must be correct", "ClassTest", clazz.getSimpleName());
+ assertEquals("Top-level class canonical name must be correct", pkg + "ClassTest", clazz.getCanonicalName());
+
+ clazz = MemberClass.class;
+
+ assertEquals("Member class name must be correct", pkg + "ClassTest$MemberClass", clazz.getName());
+ assertEquals("Member class simple name must be correct", "MemberClass", clazz.getSimpleName());
+ assertEquals("Member class canonical name must be correct", pkg + "ClassTest.MemberClass", clazz.getCanonicalName());
+
+ class LocalClass {
+ // This space intentionally left blank.
+ }
+
+ clazz = LocalClass.class;
+
+ assertEquals("Local class name must be correct", pkg + "ClassTest$1LocalClass", clazz.getName());
+ assertEquals("Local class simple name must be correct", "LocalClass", clazz.getSimpleName());
+ assertNull("Local class canonical name must be null", clazz.getCanonicalName());
+
+ clazz = new Object() { }.getClass();
+
+ assertEquals("Anonymous class name must be correct", pkg + "ClassTest$1", clazz.getName());
+ assertEquals("Anonymous class simple name must be empty", "", clazz.getSimpleName());
+ assertNull("Anonymous class canonical name must be null", clazz.getCanonicalName());
+
+ // Weird special cases with dollar in name.
+
+ clazz = Mou$$aka.class;
+
+ assertEquals("Top-level class name must be correct", pkg + "Mou$$aka", clazz.getName());
+ assertEquals("Top-level class simple name must be correct", "Mou$$aka", clazz.getSimpleName());
+ assertEquals("Top-level class canonical name must be correct", pkg + "Mou$$aka", clazz.getCanonicalName());
+
+ clazz = Mi$o$oup.class;
+
+ assertEquals("Member class name must be correct", pkg + "ClassTest$Mi$o$oup", clazz.getName());
+ assertEquals("Member class simple name must be correct", "Mi$o$oup", clazz.getSimpleName());
+ assertEquals("Member class canonical name must be correct", pkg + "ClassTest.Mi$o$oup", clazz.getCanonicalName());
+
+ class Ma$hedPotatoe$ {
+ // This space intentionally left blank.
+ }
+
+ clazz = Ma$hedPotatoe$.class;
+
+ assertEquals("Member class name must be correct", pkg + "ClassTest$1Ma$hedPotatoe$", clazz.getName());
+ assertEquals("Member class simple name must be correct", "Ma$hedPotatoe$", clazz.getSimpleName());
+ assertNull("Member class canonical name must be null", clazz.getCanonicalName());
+ }
+
+ @SmallTest
+ public void testLocalMemberClass() {
+ Class<?> clazz = this.getClass();
+
+ assertFalse("Class must not be member", clazz.isMemberClass());
+ assertFalse("Class must not be local", clazz.isLocalClass());
+
+ clazz = MemberClass.class;
+
+ assertTrue("Class must be member", clazz.isMemberClass());
+ assertFalse("Class must not be local", clazz.isLocalClass());
+
+ class OtherLocalClass {
+ // This space intentionally left blank.
+ }
+
+ clazz = OtherLocalClass.class;
+
+ assertFalse("Class must not be member", clazz.isMemberClass());
+ assertTrue("Class must be local", clazz.isLocalClass());
+
+ clazz = new Object() { }.getClass();
+
+ assertFalse("Class must not be member", clazz.isMemberClass());
+ assertFalse("Class must not be local", clazz.isLocalClass());
+ }
+
+}
+
+class Mou$$aka {
+ // This space intentionally left blank.
+}
diff --git a/tests/CoreTests/android/core/CoreTests.java b/tests/CoreTests/android/core/CoreTests.java
new file mode 100644
index 0000000..e4f835c
--- /dev/null
+++ b/tests/CoreTests/android/core/CoreTests.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import com.android.internal.telephony.TelephonyTests;
+
+import junit.framework.TestSuite;
+
+import android.graphics.ColorStateListTest;
+import android.location.LocationManagerProximityTest;
+import android.location.LocationTest;
+import android.test.AndroidTestRunnerTest;
+import android.test.InstrumentationTestRunnerTest;
+import android.util.*;
+import android.view.FocusFinderTest;
+import android.view.ViewGroupAttributesTest;
+import android.webkit.*;
+
+public class CoreTests extends TestSuite {
+
+ /**
+ * To run these tests:
+ * $ mmm java/tests && adb sync
+ * $ adb shell am instrument -w \
+ * -e class android.core.CoreTests \
+ * android.core/android.test.InstrumentationTestRunner
+ */
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(CoreTests.class.getName());
+
+ // Re-enable StateListDrawableTest when we are running in the
+ // framework-test directory which allows access to package private
+ // access for MockView
+ // suite.addTestSuite(StateListDrawableTest.class);
+ suite.addTestSuite(DayOfMonthCursorTest.class);
+ suite.addTestSuite(MonthDisplayHelperTest.class);
+ suite.addTestSuite(StateSetTest.class);
+ suite.addTestSuite(ColorStateListTest.class);
+ suite.addTestSuite(FocusFinderTest.class);
+ suite.addTestSuite(ViewGroupAttributesTest.class);
+ suite.addTest(TelephonyTests.suite());
+ suite.addTestSuite(FloatMathTest.class);
+ suite.addTest(JavaTests.suite());
+ suite.addTestSuite(LocationTest.class);
+ suite.addTestSuite(LocationManagerProximityTest.class);
+ suite.addTestSuite(AndroidTestRunnerTest.class);
+ suite.addTestSuite(InstrumentationTestRunnerTest.class);
+ suite.addTestSuite(CookieTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/CoreTests/android/core/CryptoTest.java b/tests/CoreTests/android/core/CryptoTest.java
new file mode 100644
index 0000000..f00d49f
--- /dev/null
+++ b/tests/CoreTests/android/core/CryptoTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import org.apache.harmony.xnet.provider.jsse.OpenSSLMessageDigest;
+import org.bouncycastle.crypto.Digest;
+import org.bouncycastle.crypto.ExtendedDigest;
+import org.bouncycastle.crypto.digests.MD2Digest;
+import org.bouncycastle.crypto.digests.MD4Digest;
+import org.bouncycastle.crypto.digests.MD5Digest;
+import org.bouncycastle.crypto.digests.SHA1Digest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Implements unit tests for our JNI wrapper around OpenSSL. We use the
+ * existing Bouncy Castle implementation as our test oracle.
+ */
+public class CryptoTest extends TestCase {
+
+ /**
+ * Processes the two given message digests for the same data and checks
+ * the results. Requirement is that the results must be equal, the digest
+ * implementations must have the same properties, and the new implementation
+ * must be faster than the old one.
+ *
+ * @param oldDigest The old digest implementation, provided by Bouncy Castle
+ * @param newDigest The new digest implementation, provided by OpenSSL
+ */
+ public void doTestMessageDigest(Digest oldDigest, Digest newDigest) {
+ final int ITERATIONS = 10;
+
+ byte[] data = new byte[1024];
+
+ byte[] oldHash = new byte[oldDigest.getDigestSize()];
+ byte[] newHash = new byte[newDigest.getDigestSize()];
+
+ Assert.assertEquals("Hash names must be equal", oldDigest.getAlgorithmName(), newDigest.getAlgorithmName());
+ Assert.assertEquals("Hash sizes must be equal", oldHash.length, newHash.length);
+ Assert.assertEquals("Hash block sizes must be equal", ((ExtendedDigest)oldDigest).getByteLength(), ((ExtendedDigest)newDigest).getByteLength());
+ for (int i = 0; i < data.length; i++) {
+ data[i] = (byte)i;
+ }
+
+ long oldTime = 0;
+ long newTime = 0;
+
+ for (int j = 0; j < ITERATIONS; j++) {
+ long t0 = System.currentTimeMillis();
+ for (int i = 0; i < 4; i++) {
+ oldDigest.update(data, 0, data.length);
+ }
+ int oldLength = oldDigest.doFinal(oldHash, 0);
+ long t1 = System.currentTimeMillis();
+
+ oldTime = oldTime + (t1 - t0);
+
+ long t2 = System.currentTimeMillis();
+ for (int i = 0; i < 4; i++) {
+ newDigest.update(data, 0, data.length);
+ }
+ int newLength = newDigest.doFinal(newHash, 0);
+ long t3 = System.currentTimeMillis();
+
+ newTime = newTime + (t3 - t2);
+
+ Assert.assertEquals("Hash sizes must be equal", oldLength, newLength);
+
+ for (int i = 0; i < oldLength; i++) {
+ Assert.assertEquals("Hashes[" + i + "] must be equal", oldHash[i], newHash[i]);
+ }
+ }
+
+ android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x old hash processing: " + oldTime + " ms");
+ android.util.Log.d("CryptoTest", "Time for " + ITERATIONS + " x new hash processing: " + newTime + " ms");
+
+ // Assert.assertTrue("New hash should be faster", newTime < oldTime);
+ }
+
+ /**
+ * Tests the MD2 implementation.
+ */
+ @LargeTest
+ public void testMD2() {
+ Digest oldDigest = new MD2Digest();
+ Digest newDigest = OpenSSLMessageDigest.getInstance("MD2");
+ doTestMessageDigest(oldDigest, newDigest);
+ }
+
+ /**
+ * Tests the MD4 implementation.
+ */
+ @MediumTest
+ public void testMD4() {
+ Digest oldDigest = new MD4Digest();
+ Digest newDigest = OpenSSLMessageDigest.getInstance("MD4");
+ doTestMessageDigest(oldDigest, newDigest);
+ }
+
+ /**
+ * Tests the MD5 implementation.
+ */
+ @MediumTest
+ public void testMD5() {
+ Digest oldDigest = new MD5Digest();
+ Digest newDigest = OpenSSLMessageDigest.getInstance("MD5");
+ doTestMessageDigest(oldDigest, newDigest);
+ }
+
+ /**
+ * Tests the SHA-1 implementation.
+ */
+ @MediumTest
+ public void testSHA1() {
+ Digest oldDigest = new SHA1Digest();
+ Digest newDigest = OpenSSLMessageDigest.getInstance("SHA-1");
+ doTestMessageDigest(oldDigest, newDigest);
+ }
+
+}
diff --git a/tests/CoreTests/android/core/DataInputStreamTest.java b/tests/CoreTests/android/core/DataInputStreamTest.java
new file mode 100644
index 0000000..ca801d6
--- /dev/null
+++ b/tests/CoreTests/android/core/DataInputStreamTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class DataInputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testDataInputStream() throws Exception {
+ String str = "AbCdEfGhIjKlM\nOpQ\rStUvWxYz";
+ ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream da = new ByteArrayInputStream(str.getBytes());
+
+ DataInputStream a = new DataInputStream(aa);
+ try {
+ assertEquals(str, IOUtil.read(a));
+ } finally {
+ a.close();
+ }
+
+ DataInputStream b = new DataInputStream(ba);
+ try {
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ DataInputStream c = new DataInputStream(ca);
+ try {
+ assertEquals("bdfhjl\np\rtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+
+ DataInputStream d = new DataInputStream(da);
+ try {
+ assertEquals("AbCdEfGhIjKlM", d.readLine());
+ assertEquals("OpQ", d.readLine());
+ assertEquals("StUvWxYz", d.readLine());
+ } finally {
+ d.close();
+ }
+
+ ByteArrayOutputStream e = new ByteArrayOutputStream();
+ DataOutputStream f = new DataOutputStream(e);
+ try {
+ f.writeBoolean(true);
+ f.writeByte('a');
+ f.writeBytes("BCD");
+ f.writeChar('e');
+ f.writeChars("FGH");
+ f.writeUTF("ijklm");
+ f.writeDouble(1);
+ f.writeFloat(2);
+ f.writeInt(3);
+ f.writeLong(4);
+ f.writeShort(5);
+ } finally {
+ f.close();
+ }
+
+ ByteArrayInputStream ga = new ByteArrayInputStream(e.toByteArray());
+ DataInputStream g = new DataInputStream(ga);
+
+ try {
+ assertTrue(g.readBoolean());
+ assertEquals('a', g.readByte());
+ assertEquals(2, g.skipBytes(2));
+ assertEquals('D', g.readByte());
+ assertEquals('e', g.readChar());
+ assertEquals('F', g.readChar());
+ assertEquals('G', g.readChar());
+ assertEquals('H', g.readChar());
+ assertEquals("ijklm", g.readUTF());
+ assertEquals(1, g.readDouble(), 0);
+ assertEquals(2f, g.readFloat(), 0f);
+ assertEquals(3, g.readInt());
+ assertEquals(4, g.readLong());
+ assertEquals(5, g.readShort());
+ } finally {
+ g.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/DataOutputStreamTest.java b/tests/CoreTests/android/core/DataOutputStreamTest.java
new file mode 100644
index 0000000..95502b3
--- /dev/null
+++ b/tests/CoreTests/android/core/DataOutputStreamTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.DataOutputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Basic tests for DataOutputStreams.
+ */
+public class DataOutputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testDataOutputStream() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ ByteArrayOutputStream aa = new ByteArrayOutputStream();
+ DataOutputStream a = new DataOutputStream(aa);
+
+ try {
+ a.write(str.getBytes(), 0, 26);
+ a.write('A');
+
+ assertEquals(27, aa.size());
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzA", aa.toString());
+
+ a.writeByte('B');
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzAB", aa.toString());
+ a.writeBytes("BYTES");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzABBYTES", aa.toString());
+ } finally {
+ a.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/DatabaseSessionCache.java b/tests/CoreTests/android/core/DatabaseSessionCache.java
new file mode 100644
index 0000000..c344d9c
--- /dev/null
+++ b/tests/CoreTests/android/core/DatabaseSessionCache.java
@@ -0,0 +1,312 @@
+// Copyright 2009 The Android Open Source Project
+
+package android.core;
+
+import android.database.Cursor;
+import android.database.SQLException;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+import android.util.Log;
+import android.content.ContentValues;
+import android.content.Context;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLSession;
+
+/**
+ * Hook into harmony SSL cache to persist the SSL sessions.
+ *
+ * Current implementation is suitable for saving a small number of hosts -
+ * like google services. It can be extended with expiration and more features
+ * to support more hosts.
+ *
+ * {@hide}
+ */
+public class DatabaseSessionCache implements SSLClientSessionCache {
+ private static final String TAG = "SslSessionCache";
+ static DatabaseHelper sDefaultDatabaseHelper;
+
+ private DatabaseHelper mDatabaseHelper;
+
+ /**
+ * Table where sessions are stored.
+ */
+ public static final String SSL_CACHE_TABLE = "ssl_sessions";
+
+ private static final String SSL_CACHE_ID = "_id";
+
+ /**
+ * Key is host:port - port is not optional.
+ */
+ private static final String SSL_CACHE_HOSTPORT = "hostport";
+
+ /**
+ * Base64-encoded DER value of the session.
+ */
+ private static final String SSL_CACHE_SESSION = "session";
+
+ /**
+ * Time when the record was added - should be close to the time
+ * of the initial session negotiation.
+ */
+ private static final String SSL_CACHE_TIME_SEC = "time_sec";
+
+ public static final String DATABASE_NAME = "ssl_sessions.db";
+
+ public static final int DATABASE_VERSION = 1;
+
+ /** public for testing
+ */
+ public static final int SSL_CACHE_ID_COL = 0;
+ public static final int SSL_CACHE_HOSTPORT_COL = 1;
+ public static final int SSL_CACHE_SESSION_COL = 2;
+ public static final int SSL_CACHE_TIME_SEC_COL = 3;
+
+ private static final String SAVE_ON_ADD = "save_on_add";
+
+ static boolean sHookInitializationDone = false;
+
+ public static final int MAX_CACHE_SIZE = 256;
+
+ private static final Map<String, byte[]> mExternalCache =
+ new LinkedHashMap<String, byte[]>(MAX_CACHE_SIZE, 0.75f, true) {
+ @Override
+ public boolean removeEldestEntry(
+ Map.Entry<String, byte[]> eldest) {
+ boolean shouldDelete = this.size() > MAX_CACHE_SIZE;
+
+ // TODO: delete from DB
+ return shouldDelete;
+ }
+ };
+ static boolean mNeedsCacheLoad = true;
+
+ public static final String[] PROJECTION = new String[] {
+ SSL_CACHE_ID,
+ SSL_CACHE_HOSTPORT,
+ SSL_CACHE_SESSION,
+ SSL_CACHE_TIME_SEC
+ };
+
+ /**
+ * This class needs to be installed as a hook, if the security property
+ * is set. Getting the right classloader may be fun since we don't use
+ * Provider to get its classloader, but in android this is in same
+ * loader with AndroidHttpClient.
+ *
+ * This constructor will use the default database. You must
+ * call init() before to specify the context used for the database and
+ * check settings.
+ */
+ public DatabaseSessionCache() {
+ Log.v(TAG, "Instance created.");
+ // May be null if caching is disabled - no sessions will be persisted.
+ this.mDatabaseHelper = sDefaultDatabaseHelper;
+ }
+
+ /**
+ * Create a SslSessionCache instance, using the specified context to
+ * initialize the database.
+ *
+ * This constructor will use the default database - created the first
+ * time.
+ *
+ * @param activityContext
+ */
+ public DatabaseSessionCache(Context activityContext) {
+ // Static init - only one initialization will happen.
+ // Each SslSessionCache is using the same DB.
+ init(activityContext);
+ // May be null if caching is disabled - no sessions will be persisted.
+ this.mDatabaseHelper = sDefaultDatabaseHelper;
+ }
+
+ /**
+ * Create a SslSessionCache that uses a specific database.
+ *
+ * @param database
+ */
+ public DatabaseSessionCache(DatabaseHelper database) {
+ this.mDatabaseHelper = database;
+ }
+
+// public static boolean enabled(Context androidContext) {
+// String sslCache = Settings.Gservices.getString(androidContext.getContentResolver(),
+// Settings.Gservices.SSL_SESSION_CACHE);
+//
+// if (Log.isLoggable(TAG, Log.DEBUG)) {
+// Log.d(TAG, "enabled " + sslCache + " " + androidContext.getPackageName());
+// }
+//
+// return SAVE_ON_ADD.equals(sslCache);
+// }
+
+ /**
+ * You must call this method to enable SSL session caching for an app.
+ */
+ public synchronized static void init(Context activityContext) {
+ // It is possible that multiple provider will try to install this hook.
+ // We want a single db per VM.
+ if (sHookInitializationDone) {
+ return;
+ }
+
+
+// // More values can be added in future to provide different
+// // behaviours, like 'batch save'.
+// if (enabled(activityContext)) {
+ Context appContext = activityContext.getApplicationContext();
+ sDefaultDatabaseHelper = new DatabaseHelper(appContext);
+
+ // Set default SSLSocketFactory
+ // The property is defined in the javadocs for javax.net.SSLSocketFactory
+ // (no constant defined there)
+ // This should cover all code using SSLSocketFactory.getDefault(),
+ // including native http client and apache httpclient.
+ // MCS is using its own custom factory - will need special code.
+// Security.setProperty("ssl.SocketFactory.provider",
+// SslSocketFactoryWithCache.class.getName());
+// }
+
+ // Won't try again.
+ sHookInitializationDone = true;
+ }
+
+ public void putSessionData(SSLSession session, byte[] der) {
+ if (mDatabaseHelper == null) {
+ return;
+ }
+ if (mExternalCache.size() > MAX_CACHE_SIZE) {
+ // remove oldest.
+ Cursor byTime = mDatabaseHelper.getWritableDatabase().query(SSL_CACHE_TABLE,
+ PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC);
+ byTime.moveToFirst();
+ // TODO: can I do byTime.deleteRow() ?
+ String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL);
+
+ mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE,
+ SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort });
+ }
+ // Serialize native session to standard DER encoding
+ long t0 = System.currentTimeMillis();
+
+ String b64 = new String(Base64.encodeBase64(der));
+ String key = session.getPeerHost() + ":" + session.getPeerPort();
+
+ ContentValues values = new ContentValues();
+ values.put(SSL_CACHE_HOSTPORT, key);
+ values.put(SSL_CACHE_SESSION, b64);
+ values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000);
+
+ synchronized (this.getClass()) {
+ mExternalCache.put(key, der);
+
+ try {
+ mDatabaseHelper.getWritableDatabase().insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values);
+ } catch(SQLException ex) {
+ // Ignore - nothing we can do to recover, and caller shouldn't
+ // be affected.
+ Log.w(TAG, "Ignoring SQL exception when caching session", ex);
+ }
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "New SSL session " + session.getPeerHost() +
+ " DER len: " + der.length + " " + (t1 - t0));
+ }
+
+ }
+
+ public byte[] getSessionData(String host, int port) {
+ // Current (simple) implementation does a single lookup to DB, then saves
+ // all entries to the cache.
+
+ // This works for google services - i.e. small number of certs.
+ // If we extend this to all processes - we should hold a separate cache
+ // or do lookups to DB each time.
+ if (mDatabaseHelper == null) {
+ return null;
+ }
+ synchronized(this.getClass()) {
+ if (mNeedsCacheLoad) {
+ // Don't try to load again, if something is wrong on the first
+ // request it'll likely be wrong each time.
+ mNeedsCacheLoad = false;
+ long t0 = System.currentTimeMillis();
+
+ Cursor cur = null;
+ try {
+ cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, PROJECTION, null,
+ null, null, null, null);
+ if (cur.moveToFirst()) {
+ do {
+ String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL);
+ String value = cur.getString(SSL_CACHE_SESSION_COL);
+
+ if (hostPort == null || value == null) {
+ continue;
+ }
+ // TODO: blob support ?
+ byte[] der = Base64.decodeBase64(value.getBytes());
+ mExternalCache.put(hostPort, der);
+ } while (cur.moveToNext());
+
+ }
+ } catch (SQLException ex) {
+ Log.d(TAG, "Error loading SSL cached entries ", ex);
+ } finally {
+ if (cur != null) {
+ cur.close();
+ }
+ if (Log.isLoggable(TAG, Log.DEBUG)) {
+ long t1 = System.currentTimeMillis();
+ Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms");
+ }
+ }
+ }
+
+ String key = host + ":" + port;
+
+ return mExternalCache.get(key);
+ }
+ }
+
+ public byte[] getSessionData(byte[] id) {
+ // We support client side only - the cache will do nothing on client.
+ return null;
+ }
+
+ /** Visible for testing.
+ */
+ public static class DatabaseHelper extends SQLiteOpenHelper {
+
+ public DatabaseHelper(Context context) {
+ super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION);
+ }
+
+ @Override
+ public void onCreate(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" +
+ SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," +
+ SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," +
+ SSL_CACHE_SESSION + " TEXT," +
+ SSL_CACHE_TIME_SEC + " INTEGER" +
+ ");");
+ db.execSQL("CREATE INDEX ssl_sessions_idx1 ON ssl_sessions (" +
+ SSL_CACHE_HOSTPORT + ");");
+ }
+
+ @Override
+ public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE );
+ onCreate(db);
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/tests/CoreTests/android/core/DatagramTest.java b/tests/CoreTests/android/core/DatagramTest.java
new file mode 100644
index 0000000..355a267
--- /dev/null
+++ b/tests/CoreTests/android/core/DatagramTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.DatagramPacket;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.net.SocketTimeoutException;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Implements some simple tests for datagrams. Not as excessive as the core
+ * tests, but good enough for the harness.
+ */
+public class DatagramTest extends TestCase {
+
+ /**
+ * Helper class that listens to incoming datagrams and reflects them to the
+ * sender. Incoming datagram is interpreted as a String. It is uppercased
+ * before being sent back.
+ */
+
+ class Reflector extends Thread {
+ // Helper class for reflecting incoming datagrams.
+ DatagramSocket socket;
+
+ boolean alive = true;
+
+ byte[] buffer = new byte[256];
+
+ DatagramPacket packet;
+
+ /**
+ * Main loop. Receives datagrams and reflects them.
+ */
+ @Override
+ public void run() {
+ try {
+ while (alive) {
+ try {
+ packet.setLength(buffer.length);
+ socket.receive(packet);
+ String s = stringFromPacket(packet);
+ // System.out.println(s + " (from " + packet.getAddress() + ":" + packet.getPort() + ")");
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ // Ignore.
+ }
+
+ stringToPacket(s.toUpperCase(), packet);
+
+ packet.setAddress(InetAddress.getLocalHost());
+ packet.setPort(2345);
+
+ socket.send(packet);
+ } catch (java.io.InterruptedIOException e) {
+ }
+ }
+ } catch (java.io.IOException ex) {
+ ex.printStackTrace();
+ } finally {
+ socket.close();
+ }
+ }
+
+ /**
+ * Creates a new Relfector object for the given local address and port.
+ */
+ public Reflector(int port, InetAddress address) {
+ try {
+ packet = new DatagramPacket(buffer, buffer.length);
+ socket = new DatagramSocket(port, address);
+ } catch (IOException ex) {
+ throw new RuntimeException(
+ "Creating datagram reflector failed", ex);
+ }
+ }
+ }
+
+ /**
+ * Converts a given datagram packet's contents to a String.
+ */
+ static String stringFromPacket(DatagramPacket packet) {
+ return new String(packet.getData(), 0, packet.getLength());
+ }
+
+ /**
+ * Converts a given String into a datagram packet.
+ */
+ static void stringToPacket(String s, DatagramPacket packet) {
+ byte[] bytes = s.getBytes();
+ System.arraycopy(bytes, 0, packet.getData(), 0, bytes.length);
+ packet.setLength(bytes.length);
+ }
+
+ /**
+ * Implements the main part of the Datagram test.
+ */
+ @LargeTest
+ public void testDatagram() throws Exception {
+
+ Reflector reflector = null;
+ DatagramSocket socket = null;
+
+ try {
+ // Setup the reflector, so we have a partner to send to
+ reflector = new Reflector(1234, InetAddress.getLocalHost());
+ reflector.start();
+
+ byte[] buffer = new byte[256];
+
+ DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
+ socket = new DatagramSocket(2345, InetAddress.getLocalHost());
+
+ // Send ten simple packets and check for the expected responses.
+ for (int i = 1; i <= 10; i++) {
+ String s = "Hello, Android world #" + i + "!";
+ stringToPacket(s, packet);
+
+ packet.setAddress(InetAddress.getLocalHost());
+ packet.setPort(1234);
+
+ socket.send(packet);
+
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ // Ignore.
+ }
+
+ packet.setLength(buffer.length);
+ socket.receive(packet);
+ String t = stringFromPacket(packet);
+ // System.out.println(t + " (from " + packet.getAddress() + ":" + packet.getPort() + ")");
+
+ assertEquals(s.toUpperCase(), t);
+ }
+ } finally {
+ if (reflector != null) {
+ reflector.alive = false;
+ }
+
+ if (socket != null) {
+ socket.close();
+ }
+ }
+ }
+
+ // Regression test for issue 1018003: DatagramSocket ignored a set timeout.
+ @LargeTest
+ public void testDatagramSocketSetSOTimeout() throws Exception {
+ DatagramSocket sock = null;
+ int timeout = 5000;
+ long start = System.currentTimeMillis();
+ try {
+ sock = new DatagramSocket();
+ DatagramPacket pack = new DatagramPacket(new byte[100], 100);
+ sock.setSoTimeout(timeout);
+ sock.receive(pack);
+ } catch (SocketTimeoutException e) {
+ // expected
+ long delay = System.currentTimeMillis() - start;
+ if (Math.abs(delay - timeout) > 1000) {
+ fail("timeout was not accurate. expected: " + timeout
+ + " actual: " + delay + " miliseconds.");
+ }
+ } finally {
+ if (sock != null) {
+ sock.close();
+ }
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/DeflateTest.java b/tests/CoreTests/android/core/DeflateTest.java
new file mode 100644
index 0000000..d68d697
--- /dev/null
+++ b/tests/CoreTests/android/core/DeflateTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.UnsupportedEncodingException;
+import java.util.zip.DataFormatException;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class DeflateTest extends TestCase {
+
+ @LargeTest
+ public void testDeflate() throws Exception {
+ simpleTest();
+
+ bigTest(0, 1738149618);
+ bigTest(1, 934350518);
+ bigTest(2, -532869390);
+ }
+
+ /*
+ * Simple inflate/deflate test, taken from the reference docs for the
+ * Inflater/Deflater classes.
+ */
+ private void simpleTest()
+ throws UnsupportedEncodingException, DataFormatException {
+ // Encode a String into bytes
+ String inputString = "blahblahblah??";
+ byte[] input = inputString.getBytes("UTF-8");
+
+ // Compress the bytes
+ byte[] output = new byte[100];
+ Deflater compresser = new Deflater();
+ compresser.setInput(input);
+ compresser.finish();
+ int compressedDataLength = compresser.deflate(output);
+
+ // Decompress the bytes
+ Inflater decompresser = new Inflater();
+ decompresser.setInput(output, 0, compressedDataLength);
+ byte[] result = new byte[100];
+ int resultLength = decompresser.inflate(result);
+
+ // Decode the bytes into a String
+ String outputString = new String(result, 0, resultLength, "UTF-8");
+
+ assertEquals(inputString, outputString);
+ assertEquals(compresser.getAdler(), decompresser.getAdler());
+
+ decompresser.end();
+ }
+
+ /*
+ * "step" determines how compressible the data is.
+ *
+ * Note we must set "nowrap" to false, or the Adler-32 doesn't get
+ * computed.
+ */
+ private void bigTest(int step, int expectedAdler)
+ throws UnsupportedEncodingException, DataFormatException {
+ byte[] input = new byte[128 * 1024];
+ byte[] comp = new byte[128 * 1024 + 512];
+ byte[] output = new byte[128 * 1024 + 512];
+ Inflater inflater = new Inflater(false);
+ Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION, false);
+
+ createSample(input, step);
+
+ compress(deflater, input, comp);
+ expand(inflater, comp, (int) deflater.getBytesWritten(), output);
+
+ assertEquals(inflater.getBytesWritten(), input.length);
+ assertEquals(deflater.getAdler(), inflater.getAdler());
+ assertEquals(deflater.getAdler(), expectedAdler);
+ }
+
+ /*
+ * Create a large data sample.
+ * stepStep = 0 --> >99% compression
+ * stepStep = 1 --> ~30% compression
+ * stepStep = 2 --> no compression
+ */
+ private void createSample(byte[] sample, int stepStep) {
+ byte val, step;
+ int i, j, offset;
+
+ assertTrue(sample.length >= 128 * 1024);
+
+ val = 0;
+ step = 1;
+ offset = 0;
+ for (i = 0; i < (128 * 1024) / 256; i++) {
+ for (j = 0; j < 256; j++) {
+ sample[offset++] = val;
+ val += step;
+ }
+
+ step += stepStep;
+ }
+ }
+
+ private static final int LOCAL_BUF_SIZE = 256;
+
+ /*
+ * Compress all data in "in" to "out". We use a small window on input
+ * and output to exercise that part of the code.
+ *
+ * It's the caller's responsibility to ensure that "out" has enough
+ * space.
+ */
+ private void compress(Deflater deflater, byte[] inBuf, byte[] outBuf) {
+ int inCount = inBuf.length; // use all
+ int inPosn;
+ int outPosn;
+
+ inPosn = outPosn = 0;
+
+ //System.out.println("### starting compress");
+
+ while (!deflater.finished()) {
+ int want = -1, got;
+
+ // only read if the input buffer is empty
+ if (deflater.needsInput() && inCount != 0) {
+ want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
+
+ deflater.setInput(inBuf, inPosn, want);
+
+ inCount -= want;
+ inPosn += want;
+ if (inCount == 0) {
+ deflater.finish();
+ }
+ }
+
+ // deflate to current position in output buffer
+ int compCount;
+
+ compCount = deflater.deflate(outBuf, outPosn, LOCAL_BUF_SIZE);
+ outPosn += compCount;
+
+ //System.out.println("Compressed " + want + ", output " + compCount);
+ }
+ }
+
+ /*
+ * Expand data from "inBuf" to "outBuf". Uses a small window to better
+ * exercise the code.
+ */
+ private void expand(Inflater inflater, byte[] inBuf, int inCount,
+ byte[] outBuf) throws DataFormatException {
+ int inPosn;
+ int outPosn;
+
+ inPosn = outPosn = 0;
+
+ //System.out.println("### starting expand, inCount is " + inCount);
+
+ while (!inflater.finished()) {
+ int want = -1, got;
+
+ // only read if the input buffer is empty
+ if (inflater.needsInput() && inCount != 0) {
+ want = (inCount < LOCAL_BUF_SIZE) ? inCount : LOCAL_BUF_SIZE;
+
+ inflater.setInput(inBuf, inPosn, want);
+
+ inCount -= want;
+ inPosn += want;
+ }
+
+ // inflate to current position in output buffer
+ int compCount;
+
+ compCount = inflater.inflate(outBuf, outPosn, LOCAL_BUF_SIZE);
+ outPosn += compCount;
+
+ //System.out.println("Expanded " + want + ", output " + compCount);
+ }
+ }
+}
+
diff --git a/tests/CoreTests/android/core/EnumTest.java b/tests/CoreTests/android/core/EnumTest.java
new file mode 100644
index 0000000..d479491
--- /dev/null
+++ b/tests/CoreTests/android/core/EnumTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests basic behavior of enums.
+ */
+public class EnumTest extends TestCase {
+ enum MyEnum {
+ ZERO, ONE, TWO, THREE, FOUR {boolean isFour() {
+ return true;
+ }};
+
+ boolean isFour() {
+ return false;
+ }
+ }
+
+ enum MyEnumTwo {
+ FIVE, SIX
+ }
+
+ @SmallTest
+ public void testEnum() throws Exception {
+ assertTrue(MyEnum.ZERO.compareTo(MyEnum.ONE) < 0);
+ assertEquals(MyEnum.ZERO, MyEnum.ZERO);
+ assertTrue(MyEnum.TWO.compareTo(MyEnum.ONE) > 0);
+ assertTrue(MyEnum.FOUR.compareTo(MyEnum.ONE) > 0);
+
+ assertEquals("ONE", MyEnum.ONE.name());
+ assertSame(MyEnum.ONE.getDeclaringClass(), MyEnum.class);
+ assertSame(MyEnum.FOUR.getDeclaringClass(), MyEnum.class);
+
+ assertTrue(MyEnum.FOUR.isFour());
+
+ MyEnum e;
+
+ e = MyEnum.ZERO;
+
+ switch (e) {
+ case ZERO:
+ break;
+ default:
+ fail("wrong switch");
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/FileTest.java b/tests/CoreTests/android/core/FileTest.java
new file mode 100644
index 0000000..980452e
--- /dev/null
+++ b/tests/CoreTests/android/core/FileTest.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Checks creation and deletion of a file.
+ */
+public class FileTest extends TestCase {
+
+ @SmallTest
+ public void testFile() throws Exception {
+
+ File file = File.createTempFile(String.valueOf(System.currentTimeMillis()), null, null);
+
+ assertTrue(file.exists());
+ assertTrue(file.delete());
+ assertFalse(file.exists());
+ }
+}
diff --git a/tests/CoreTests/android/core/FloatDoubleTest.java b/tests/CoreTests/android/core/FloatDoubleTest.java
new file mode 100644
index 0000000..8c8455b
--- /dev/null
+++ b/tests/CoreTests/android/core/FloatDoubleTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for basic functionality of floats and doubles.
+ */
+public class FloatDoubleTest extends TestCase {
+
+ @SmallTest
+ public void testFloatDouble() throws Exception {
+ Double d = Double.valueOf(1.0);
+ Float f = Float.valueOf(1.0f);
+ Object o = new Object();
+
+ assertFalse(f.equals(d));
+ assertFalse(d.equals(f));
+ assertFalse(f.equals(o));
+ assertFalse(d.equals(o));
+ assertFalse(f.equals(null));
+ assertFalse(d.equals(null));
+ }
+
+ @SmallTest
+ public void testFloat() throws Exception {
+ float pz = 0.0f;
+ float nz = -0.0f;
+
+ float pzero = 1.0f / Float.POSITIVE_INFINITY;
+ float nzero = 1.0f / Float.NEGATIVE_INFINITY;
+
+ // Everything compares as '=='
+ assertTrue(pz == pz);
+ assertTrue(pz == nz);
+ assertTrue(pz == pzero);
+ assertTrue(pz == nzero);
+
+ assertTrue(nz == pz);
+ assertTrue(nz == nz);
+ assertTrue(nz == pzero);
+ assertTrue(nz == nzero);
+
+ assertTrue(pzero == pz);
+ assertTrue(pzero == nz);
+ assertTrue(pzero == pzero);
+ assertTrue(pzero == nzero);
+
+ assertTrue(nzero == pz);
+ assertTrue(nzero == nz);
+ assertTrue(nzero == pzero);
+ assertTrue(nzero == nzero);
+
+ // +-0 are distinct as Floats
+ assertEquals(Float.valueOf(pz), Float.valueOf(pz));
+ assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nz)));
+ assertEquals(Float.valueOf(pz), Float.valueOf(pzero));
+ assertTrue(!Float.valueOf(pz).equals(Float.valueOf(nzero)));
+
+ assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pz)));
+ assertEquals(Float.valueOf(nz), Float.valueOf(nz));
+ assertTrue(!Float.valueOf(nz).equals(Float.valueOf(pzero)));
+ assertEquals(Float.valueOf(nz), Float.valueOf(nzero));
+
+ assertEquals(Float.valueOf(pzero), Float.valueOf(pz));
+ assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nz)));
+ assertEquals(Float.valueOf(pzero), Float.valueOf(pzero));
+ assertTrue(!Float.valueOf(pzero).equals(Float.valueOf(nzero)));
+
+ assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pz)));
+ assertEquals(Float.valueOf(nzero), Float.valueOf(nz));
+ assertTrue(!Float.valueOf(nzero).equals(Float.valueOf(pzero)));
+ assertEquals(Float.valueOf(nzero), Float.valueOf(nzero));
+
+ // Nan's compare as equal
+ Float sqrtm2 = Float.valueOf((float) Math.sqrt(-2.0f));
+ Float sqrtm3 = Float.valueOf((float) Math.sqrt(-3.0f));
+ assertEquals(sqrtm2, sqrtm3);
+ }
+
+ @SmallTest
+ public void testDouble() throws Exception {
+ double pz = 0.0;
+ double nz = -0.0;
+
+ double pzero = 1.0 / Double.POSITIVE_INFINITY;
+ double nzero = 1.0 / Double.NEGATIVE_INFINITY;
+
+ // Everything compares as '=='
+ assertTrue(pz == pz);
+ assertTrue(pz == nz);
+ assertTrue(pz == pzero);
+ assertTrue(pz == nzero);
+
+ assertTrue(nz == pz);
+ assertTrue(nz == nz);
+ assertTrue(nz == pzero);
+ assertTrue(nz == nzero);
+
+ assertTrue(pzero == pz);
+ assertTrue(pzero == nz);
+ assertTrue(pzero == pzero);
+ assertTrue(pzero == nzero);
+
+ assertTrue(nzero == pz);
+ assertTrue(nzero == nz);
+ assertTrue(nzero == pzero);
+ assertTrue(nzero == nzero);
+
+ // +-0 are distinct as Doubles
+ assertEquals(Double.valueOf(pz), Double.valueOf(pz));
+ assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nz)));
+ assertEquals(Double.valueOf(pz), Double.valueOf(pzero));
+ assertTrue(!Double.valueOf(pz).equals(Double.valueOf(nzero)));
+
+ assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pz)));
+ assertEquals(Double.valueOf(nz), Double.valueOf(nz));
+ assertTrue(!Double.valueOf(nz).equals(Double.valueOf(pzero)));
+ assertEquals(Double.valueOf(nz), Double.valueOf(nzero));
+
+ assertEquals(Double.valueOf(pzero), Double.valueOf(pz));
+ assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nz)));
+ assertEquals(Double.valueOf(pzero), Double.valueOf(pzero));
+ assertTrue(!Double.valueOf(pzero).equals(Double.valueOf(nzero)));
+
+ assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pz)));
+ assertEquals(Double.valueOf(nzero), Double.valueOf(nz));
+ assertTrue(!Double.valueOf(nzero).equals(Double.valueOf(pzero)));
+ assertEquals(Double.valueOf(nzero), Double.valueOf(nzero));
+
+ // Nan's compare as equal
+ Double sqrtm2 = Double.valueOf(Math.sqrt(-2.0));
+ Double sqrtm3 = Double.valueOf(Math.sqrt(-3.0));
+ assertEquals(sqrtm2, sqrtm3);
+ }
+}
diff --git a/tests/CoreTests/android/core/GZIPStreamTest.java b/tests/CoreTests/android/core/GZIPStreamTest.java
new file mode 100644
index 0000000..dd56fb7
--- /dev/null
+++ b/tests/CoreTests/android/core/GZIPStreamTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.GZIPInputStream;
+import java.util.zip.GZIPOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Deflates and inflates some test data with GZipStreams
+ */
+public class GZIPStreamTest extends TestCase {
+
+ @MediumTest
+ public void testGZIPStream() throws Exception {
+ ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+ createGZIP(bytesOut);
+
+ byte[] zipData;
+ zipData = bytesOut.toByteArray();
+
+ /*
+ FileOutputStream outFile = new FileOutputStream("/tmp/foo.gz");
+ outFile.write(zipData, 0, zipData.length);
+ outFile.close();
+ */
+
+ /*
+ FileInputStream inFile = new FileInputStream("/tmp/foo.gz");
+ int inputLength = inFile.available();
+ zipData = new byte[inputLength];
+ if (inFile.read(zipData) != inputLength)
+ throw new RuntimeException();
+ inFile.close();
+ */
+
+ ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData);
+ scanGZIP(bytesIn);
+ }
+
+ /*
+ * stepStep == 0 --> >99% compression
+ * stepStep == 1 --> ~30% compression
+ * stepStep == 2 --> no compression
+ */
+ static byte[] makeSampleFile(int stepStep) throws IOException {
+ byte[] sample = new byte[128 * 1024];
+ byte val, step;
+ int i, j, offset;
+
+ val = 0;
+ step = 1;
+ offset = 0;
+ for (i = 0; i < (128 * 1024) / 256; i++) {
+ for (j = 0; j < 256; j++) {
+ sample[offset++] = val;
+ val += step;
+ }
+
+ step += stepStep;
+ }
+
+ return sample;
+ }
+
+ static void createGZIP(ByteArrayOutputStream bytesOut) throws IOException {
+ GZIPOutputStream out = new GZIPOutputStream(bytesOut);
+ try {
+ byte[] input = makeSampleFile(1);
+ out.write(input, 0, input.length);
+ //out.finish();
+ } finally {
+ out.close();
+ }
+ }
+
+ static void scanGZIP(ByteArrayInputStream bytesIn) throws IOException {
+ GZIPInputStream in = new GZIPInputStream(bytesIn);
+ try {
+ ByteArrayOutputStream contents = new ByteArrayOutputStream();
+ byte[] buf = new byte[4096];
+ int len, totalLen = 0;
+
+ while ((len = in.read(buf)) > 0) {
+ contents.write(buf, 0, len);
+ totalLen += len;
+ }
+
+ assertEquals(totalLen, 128 * 1024);
+ } finally {
+ in.close();
+ }
+ }
+}
+
diff --git a/tests/CoreTests/android/core/HashMapPerfTest.java b/tests/CoreTests/android/core/HashMapPerfTest.java
new file mode 100644
index 0000000..8475222
--- /dev/null
+++ b/tests/CoreTests/android/core/HashMapPerfTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.os.SystemClock;
+import android.test.suitebuilder.annotation.LargeTest;
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Random;
+
+/**
+ * Tests basic functionality of HashMaps and prints the time needed to System.out
+ */
+public class HashMapPerfTest extends TestCase {
+
+ private static final Random sRandom = new Random(1);
+
+ class StringThing {
+
+ String mId;
+
+ public StringThing() {
+ int len = sRandom.nextInt(20) + 1;
+ char[] chars = new char[len];
+ chars[0] = 't';
+ for (int i = 1; i < len; i++) {
+ chars[i] = (char) ('q' + sRandom.nextInt(4));
+ }
+ mId = new String(chars, 0, len);
+ }
+
+ public String getId() {
+ return mId;
+ }
+ }
+
+ private static final int NUM_ELTS = 1000;
+ private static final int ITERS = 100;
+
+ String[] keyCopies = new String[NUM_ELTS];
+
+ private static final boolean lookupByOriginals = false;
+
+ @LargeTest
+ public void testHashMapPerformance() throws Exception {
+ StringThing[] st = new StringThing[NUM_ELTS];
+ for (int i = 0; i < NUM_ELTS; i++) {
+ st[i] = new StringThing();
+ keyCopies[i] = st[i].getId();
+ }
+
+ // android.os.Debug.startMethodTracing();
+ long start = SystemClock.uptimeMillis();
+ for (int i = 0; i < ITERS; i++) {
+ HashMap<String, StringThing> map = new HashMap<String, StringThing>();
+ for (int j = 0; j < NUM_ELTS; j++) {
+ StringThing s = st[i];
+ map.put(s.getId(), s);
+ }
+ for (int j = 0; j < NUM_ELTS; j++) {
+ if (lookupByOriginals) {
+ StringThing s = st[i];
+ map.get(s.getId());
+ } else {
+ map.get(keyCopies[j]);
+ }
+ }
+ }
+ long finish = SystemClock.uptimeMillis();
+ // android.os.Debug.stopMethodTracing();
+
+ // This should be an assertion instead
+
+// System.out.println("time (" + NUM_ELTS +
+// ", elts, " + ITERS +
+// " iters) = " + (finish - start));
+ }
+}
diff --git a/tests/CoreTests/android/core/HashMapTest.java b/tests/CoreTests/android/core/HashMapTest.java
new file mode 100644
index 0000000..99b2a47
--- /dev/null
+++ b/tests/CoreTests/android/core/HashMapTest.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Iterator;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test cases for Hashmap.
+ */
+public class HashMapTest extends TestCase {
+ private static final Integer ONE = new Integer(1);
+ private static final Integer TWO = new Integer(2);
+ private static final Integer THREE = new Integer(3);
+ private static final Integer FOUR = new Integer(4);
+
+ private void addItems(HashMap map) {
+ map.put("one", ONE);
+ map.put("two", TWO);
+ map.put("three", THREE);
+ map.put("four", FOUR);
+
+ assertEquals(4, map.size());
+
+ assertEquals(ONE, map.get("one"));
+ assertEquals(TWO, map.get("two"));
+ assertEquals(THREE, map.get("three"));
+ assertEquals(FOUR, map.get("four"));
+ }
+
+ /**
+ * checks if simple adding elements works.
+ */
+ @SmallTest
+ public void testAdd() throws Exception {
+ HashMap map = new HashMap();
+ addItems(map);
+ }
+
+ /**
+ * checks if clearing the map works.
+ */
+ @SmallTest
+ public void testClear() throws Exception {
+ HashMap map = new HashMap();
+
+ addItems(map);
+ map.clear();
+ assertEquals(0, map.size());
+ }
+
+ /**
+ * checks if removing an elemt works.
+ */
+ @SmallTest
+ public void testRemove() throws Exception {
+ HashMap map = new HashMap();
+
+ addItems(map);
+ map.remove("three");
+ assertNull(map.get("three"));
+ }
+
+ /**
+ * does some manipulation with a filled HashMap and checks
+ * if they work as intended
+ */
+ @SmallTest
+ public void testManipulate() throws Exception {
+ HashMap map = new HashMap();
+
+ assertTrue(map.isEmpty());
+ assertEquals(0, map.size());
+ assertNull(map.get(null));
+ assertNull(map.get("one"));
+ assertFalse(map.containsKey("one"));
+ assertFalse(map.containsValue(new Integer(1)));
+ assertNull(map.remove(null));
+ assertNull(map.remove("one"));
+
+ assertNull(map.put(null, new Integer(-1)));
+ assertNull(map.put("one", new Integer(1)));
+ assertNull(map.put("two", new Integer(2)));
+ assertNull(map.put("three", new Integer(3)));
+ assertEquals(-1, ((Integer) map.put(null, new Integer(0))).intValue());
+
+ assertEquals(0, ((Integer) map.get(null)).intValue());
+ assertEquals(1, ((Integer) map.get("one")).intValue());
+ assertEquals(2, ((Integer) map.get("two")).intValue());
+ assertEquals(3, ((Integer) map.get("three")).intValue());
+
+ assertTrue(map.containsKey(null));
+ assertTrue(map.containsKey("one"));
+ assertTrue(map.containsKey("two"));
+ assertTrue(map.containsKey("three"));
+
+ assertTrue(map.containsValue(new Integer(0)));
+ assertTrue(map.containsValue(new Integer(1)));
+ assertTrue(map.containsValue(new Integer(2)));
+ assertTrue(map.containsValue(new Integer(3)));
+
+ assertEquals(0, ((Integer) map.remove(null)).intValue());
+ assertEquals(1, ((Integer) map.remove("one")).intValue());
+ assertEquals(2, ((Integer) map.remove("two")).intValue());
+ assertEquals(3, ((Integer) map.remove("three")).intValue());
+
+ assertTrue(map.isEmpty());
+ assertEquals(0, map.size());
+ assertNull(map.get(null));
+ assertNull(map.get("one"));
+ assertFalse(map.containsKey("one"));
+ assertFalse(map.containsValue(new Integer(1)));
+ assertNull(map.remove(null));
+ assertNull(map.remove("one"));
+ }
+
+ /**
+ * checks if the key iterator of HashMaps work.
+ */
+ @SmallTest
+ public void testKeyIterator() throws Exception {
+ HashMap map = new HashMap();
+
+ boolean[] slots = new boolean[4];
+
+ addItems(map);
+
+ Iterator iter = map.keySet().iterator();
+
+ while (iter.hasNext()) {
+ int slot = 0;
+ Object key = iter.next();
+
+ if (key.equals("one"))
+ slot = 0;
+ else if (key.equals("two"))
+ slot = 1;
+ else if (key.equals("three"))
+ slot = 2;
+ else if (key.equals("four"))
+ slot = 3;
+ else
+ fail("Unkown key in hashmap");
+
+ if (slots[slot])
+ fail("key returned more than once");
+ else
+ slots[slot] = true;
+ }
+
+ assertTrue(slots[0]);
+ assertTrue(slots[1]);
+ assertTrue(slots[2]);
+ assertTrue(slots[3]);
+ }
+
+ /**
+ * checks if the value iterator works.
+ */
+ @SmallTest
+ public void testValueIterator() throws Exception {
+ HashMap map = new HashMap();
+
+ boolean[] slots = new boolean[4];
+
+ addItems(map);
+
+ Iterator iter = map.values().iterator();
+
+ while (iter.hasNext()) {
+ int slot = 0;
+ Object value = iter.next();
+
+ if (value.equals(ONE))
+ slot = 0;
+ else if (value.equals(TWO))
+ slot = 1;
+ else if (value.equals(THREE))
+ slot = 2;
+ else if (value.equals(FOUR))
+ slot = 3;
+ else
+ fail("Unkown value in hashmap");
+
+ if (slots[slot])
+ fail("value returned more than once");
+ else
+ slots[slot] = true;
+ }
+
+ assertTrue(slots[0]);
+ assertTrue(slots[1]);
+ assertTrue(slots[2]);
+ assertTrue(slots[3]);
+ }
+
+ /**
+ * checks if the entry iterator works for HashMaps.
+ */
+ @SmallTest
+ public void testEntryIterator() throws Exception {
+ HashMap map = new HashMap();
+
+ boolean[] slots = new boolean[4];
+
+ addItems(map);
+
+ Iterator iter = map.entrySet().iterator();
+
+ while (iter.hasNext()) {
+ int slot = 0;
+ Object entry = iter.next();
+
+ if (entry.toString().equals("one=1"))
+ slot = 0;
+ else if (entry.toString().equals("two=2"))
+ slot = 1;
+ else if (entry.toString().equals("three=3"))
+ slot = 2;
+ else if (entry.toString().equals("four=4"))
+ slot = 3;
+ else
+ fail("Unkown entry in hashmap");
+
+ if (slots[slot])
+ fail("entry returned more than once");
+ else
+ slots[slot] = true;
+ }
+
+ assertTrue(slots[0]);
+ assertTrue(slots[1]);
+ assertTrue(slots[2]);
+ assertTrue(slots[3]);
+ }
+
+ /**
+ * checks if the HashMap equals method works.
+ */
+ @SmallTest
+ public void testEquals() throws Exception {
+ HashMap map1 = new HashMap();
+ HashMap map2 = new HashMap();
+ HashMap map3 = new HashMap();
+
+ map1.put("one", "1");
+ map1.put("two", "2");
+ map1.put("three", "3");
+
+ map2.put("one", new String("1"));
+ map2.put(new String("two"), "2");
+ map2.put(new String("three"), new String("3"));
+
+ assertTrue(map1.equals(map2));
+
+ map3.put("one", "1");
+ map3.put("two", "1");
+ map3.put("three", "1");
+
+ assertFalse(map1.equals(map3));
+ assertFalse(map2.equals(map3));
+ }
+}
+
diff --git a/tests/CoreTests/android/core/HttpConstants.java b/tests/CoreTests/android/core/HttpConstants.java
new file mode 100644
index 0000000..d655d52
--- /dev/null
+++ b/tests/CoreTests/android/core/HttpConstants.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+interface HttpConstants {
+ /** 2XX: generally "OK" */
+ public static final int HTTP_OK = 200;
+ public static final int HTTP_CREATED = 201;
+ public static final int HTTP_ACCEPTED = 202;
+ public static final int HTTP_NOT_AUTHORITATIVE = 203;
+ public static final int HTTP_NO_CONTENT = 204;
+ public static final int HTTP_RESET = 205;
+ public static final int HTTP_PARTIAL = 206;
+
+ /** 3XX: relocation/redirect */
+ public static final int HTTP_MULT_CHOICE = 300;
+ public static final int HTTP_MOVED_PERM = 301;
+ public static final int HTTP_MOVED_TEMP = 302;
+ public static final int HTTP_SEE_OTHER = 303;
+ public static final int HTTP_NOT_MODIFIED = 304;
+ public static final int HTTP_USE_PROXY = 305;
+
+ /** 4XX: client error */
+ public static final int HTTP_BAD_REQUEST = 400;
+ public static final int HTTP_UNAUTHORIZED = 401;
+ public static final int HTTP_PAYMENT_REQUIRED = 402;
+ public static final int HTTP_FORBIDDEN = 403;
+ public static final int HTTP_NOT_FOUND = 404;
+ public static final int HTTP_BAD_METHOD = 405;
+ public static final int HTTP_NOT_ACCEPTABLE = 406;
+ public static final int HTTP_PROXY_AUTH = 407;
+ public static final int HTTP_CLIENT_TIMEOUT = 408;
+ public static final int HTTP_CONFLICT = 409;
+ public static final int HTTP_GONE = 410;
+ public static final int HTTP_LENGTH_REQUIRED = 411;
+ public static final int HTTP_PRECON_FAILED = 412;
+ public static final int HTTP_ENTITY_TOO_LARGE = 413;
+ public static final int HTTP_REQ_TOO_LONG = 414;
+ public static final int HTTP_UNSUPPORTED_TYPE = 415;
+
+ /** 5XX: server error */
+ public static final int HTTP_SERVER_ERROR = 500;
+ public static final int HTTP_INTERNAL_ERROR = 501;
+ public static final int HTTP_BAD_GATEWAY = 502;
+ public static final int HTTP_UNAVAILABLE = 503;
+ public static final int HTTP_GATEWAY_TIMEOUT = 504;
+ public static final int HTTP_VERSION = 505;
+
+ /** Method IDs */
+ public static final int UNKNOWN_METHOD = 0;
+ public static final int GET_METHOD = 1;
+ public static final int HEAD_METHOD = 2;
+ public static final int POST_METHOD = 3;
+
+ public static final String[] requestHeaders = {
+ "cache-control",
+ "connection",
+ "date",
+ "pragma",
+ "trailer",
+ "transfer-encoding",
+ "upgrade",
+ "via",
+ "warning",
+ "accept",
+ "accept-charset",
+ "accept-encoding",
+ "accept-language",
+ "authorization",
+ "expect",
+ "from",
+ "host",
+ "if-match",
+ "if-modified-since",
+ "if-none-match",
+ "if-range",
+ "if-unmodified-since",
+ "max-forwards",
+ "proxy-authentication",
+ "range",
+ "referer",
+ "te",
+ "user-agent",
+ "keep-alive",
+ "allow",
+ "content-encoding",
+ "content-language",
+ "content-length",
+ "content-location",
+ "content-md5",
+ "content-range",
+ "content-type",
+ "expires",
+ "last-modified",
+ "location",
+ "server"
+
+ };
+
+ public static final int REQ_UNKNOWN = -1;
+ public static final int REQ_CACHE_CONTROL = 0;
+ public static final int REQ_CONNECTION = 1;
+ public static final int REQ_DATE = 2;
+ public static final int REQ_PRAGMA = 3;
+ public static final int REQ_TRAILER = 4;
+ public static final int REQ_TRANSFER_ENCODING = 5;
+ public static final int REQ_UPGRADE = 6;
+ public static final int REQ_VIA = 7;
+ public static final int REQ_WARNING = 8;
+ public static final int REQ_ACCEPT = 9;
+ public static final int REQ_ACCEPT_CHARSET = 10;
+ public static final int REQ_ACCEPT_ENCODING = 11;
+ public static final int REQ_ACCEPT_LANGUAGE = 12;
+ public static final int REQ_AUTHORIZATION = 13;
+ public static final int REQ_EXPECT = 14;
+ public static final int REQ_FROM = 15;
+ public static final int REQ_HOST = 16;
+ public static final int REQ_IF_MATCH = 17;
+ public static final int REQ_IF_MODIFIED_SINCE = 18;
+ public static final int REQ_IF_NONE_MATCH = 19;
+ public static final int REQ_IF_RANGE = 20;
+ public static final int REQ_IF_UNMODIFIED_SINCE = 21;
+ public static final int REQ_MAX_FORWARDS = 22;
+ public static final int REQ_PROXY_AUTHENTICATION = 23;
+ public static final int REQ_RANGE = 24;
+ public static final int REQ_REFERER = 25;
+ public static final int REQ_TE = 26;
+ public static final int REQ_USER_AGENT = 27;
+ public static final int REQ_KEEP_ALIVE = 28;
+ public static final int REQ_ALLOW = 29;
+ public static final int REQ_CONTENT_ENCODING = 30;
+ public static final int REQ_CONTENT_LANGUAGE = 31;
+ public static final int REQ_CONTENT_LENGTH = 32;
+ public static final int REQ_CONTENT_LOCATION = 33;
+ public static final int REQ_CONTENT_MD5 = 34;
+ public static final int REQ_CONTENT_RANGE = 35;
+ public static final int REQ_CONTENT_TYPE = 36;
+ public static final int REQ_EXPIRES = 37;
+ public static final int REQ_LAST_MODIFIED = 38;
+ public static final int REQ_LOCATION = 39;
+ public static final int REQ_SERVER = 40;
+
+}
diff --git a/tests/CoreTests/android/core/IOUtil.java b/tests/CoreTests/android/core/IOUtil.java
new file mode 100644
index 0000000..6f69418
--- /dev/null
+++ b/tests/CoreTests/android/core/IOUtil.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.InputStreamReader;
+
+public final class IOUtil {
+
+ private IOUtil() {
+ }
+
+ /**
+ * returns the content of an InputStream as a String.
+ *
+ * @param a the input stream.
+ * @return the string
+ * @throws java.io.IOException
+ */
+ public static String read(InputStream a) throws IOException {
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ r = a.read();
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+
+ /**
+ * reads characters from a reader and returns them as a string.
+ *
+ * @param a the reader.
+ * @return the string.
+ * @throws IOException
+ */
+ public static String read(Reader a) throws IOException {
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ r = a.read();
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+
+ /**
+ * returns the content of an InputStream as a String. It reads x characters.
+ *
+ * @param a the input stream.
+ * @param x number of characters to read.
+ * @return the string
+ * @throws IOException
+ */
+ public static String read(InputStream a, int x) throws IOException {
+ byte[] b = new byte[x];
+ int len = a.read(b, 0, x);
+ if (len < 0) {
+ return "";
+ }
+ return new String(b, 0, len);
+ }
+
+ /**
+ * reads a number of characters from a reader and returns them as a string.
+ *
+ * @param a the reader.
+ * @param x the number of characters to read.
+ * @return the string.
+ * @throws IOException
+ */
+ public static String read(Reader a, int x) throws IOException {
+ char[] b = new char[x];
+ int len = a.read(b, 0, x);
+ if (len < 0) {
+ return "";
+ }
+ return new String(b, 0, len);
+ }
+
+ /**
+ * returns the content of the input stream as a String. It only appends
+ * every second character.
+ *
+ * @param a the input stream.
+ * @return the string created from every second character of the input stream.
+ * @throws IOException
+ */
+ public static String skipRead(InputStream a) throws IOException {
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ a.skip(1);
+ r = a.read();
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+
+ /**
+ * reads every second characters from a reader and returns them as a string.
+ *
+ * @param a the reader.
+ * @return the string.
+ * @throws IOException
+ */
+ public static String skipRead(Reader a) throws IOException {
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ a.skip(1);
+ r = a.read();
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+
+ /**
+ * reads characters from a InputStream, skips back y characters and continues
+ * reading from that new position up to the end.
+ *
+ * @param a the InputStream.
+ * @param x the position of the mark. the marks position is x+y
+ * @param y the number of characters to jump back after the position x+y was reached.
+ * @return the string.
+ * @throws IOException
+ */
+ public static String markRead(InputStream a, int x, int y) throws IOException {
+ int m = 0;
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ m++;
+ r = a.read();
+ if (m == x)
+ a.mark((x + y));
+ if (m == (x + y))
+ a.reset();
+
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+
+ /**
+ * reads characters from a reader, skips back y characters and continues
+ * reading from that new position up to the end.
+ *
+ * @param a the reader.
+ * @param x the position of the mark. the marks position is x+y
+ * @param y the number of characters to jump back after the position x+y was reached.
+ * @return the string.
+ * @throws IOException
+ */
+ public static String markRead(Reader a, int x, int y) throws IOException {
+ int m = 0;
+ int r;
+ StringBuilder builder = new StringBuilder();
+ do {
+ m++;
+ r = a.read();
+ if (m == x)
+ a.mark((x + y));
+ if (m == (x + y))
+ a.reset();
+
+ if (r != -1)
+ builder.append((char) r);
+ } while (r != -1);
+ return builder.toString();
+ }
+}
diff --git a/tests/CoreTests/android/core/InetAddrTest.java b/tests/CoreTests/android/core/InetAddrTest.java
new file mode 100644
index 0000000..c7b89e1
--- /dev/null
+++ b/tests/CoreTests/android/core/InetAddrTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Random;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Tests InetAddr class by checking methods to resolve domains to IP addresses
+ * and by checking if the class returns correct addresses for local host address
+ * and host name.
+ */
+@Suppress
+public class InetAddrTest extends TestCase {
+ private static final String[] HOSTS = {
+ "localhost", "www.google.com", "www.slashdot.org", "www.wikipedia.org",
+ "www.paypal.com", "www.cnn.com", "www.yahoo.com", "www.amazon.com",
+ "www.ebay.com", "www.android.com"
+ };
+
+ public void testInetAddr() throws Exception {
+ byte[] raw;
+
+ InetAddress ia = InetAddress.getByName("localhost");
+
+ raw = ia.getAddress();
+
+ assertEquals(127, raw[0]);
+ assertEquals(0, raw[1]);
+ assertEquals(0, raw[2]);
+ assertEquals(1, raw[3]);
+
+ ia = InetAddress.getByName("127.0.0.1");
+
+ raw = ia.getAddress();
+
+ assertEquals(127, raw[0]);
+ assertEquals(0, raw[1]);
+ assertEquals(0, raw[2]);
+ assertEquals(1, raw[3]);
+
+ ia = InetAddress.getByName(null);
+
+ try {
+ InetAddress.getByName(".0.0.1");
+ fail("expected ex");
+ } catch (UnknownHostException ex) {
+ // expected
+ }
+
+ try {
+ InetAddress.getByName("thereisagoodchancethisdomaindoesnotexist.weirdtld");
+ fail("expected ex");
+ } catch (UnknownHostException ex) {
+ // expected
+ }
+
+ try {
+ InetAddress.getByName("127.0.0.");
+ fail("expected ex");
+ } catch (UnknownHostException ex) {
+ // expected
+ }
+
+ Random random = new Random();
+ int count = 0;
+ for (int i = 0; i < 100; i++) {
+ int index = random.nextInt(HOSTS.length);
+ try {
+ InetAddress.getByName(HOSTS[index]);
+ count++;
+ try {
+ Thread.sleep(50);
+ } catch (InterruptedException ex) {
+ }
+ } catch (UnknownHostException ex) {
+ }
+ }
+ assertEquals("Not all host lookups succeeded", 100, count);
+ }
+}
diff --git a/tests/CoreTests/android/core/InputStreamReaderTest.java b/tests/CoreTests/android/core/InputStreamReaderTest.java
new file mode 100644
index 0000000..1e8d87c
--- /dev/null
+++ b/tests/CoreTests/android/core/InputStreamReaderTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStreamReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Checks basic InputStreamReader functionality.
+ */
+public class InputStreamReaderTest extends TestCase {
+
+ /**
+ * Checks if ASCII encoding works with InputStreamReader
+ */
+ @SmallTest
+ public void testAscii() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX";
+ ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes("ISO8859_1"));
+ InputStreamReader a = new InputStreamReader(aa, "ISO8859_1");
+
+ try {
+ int x = a.read();
+ assertEquals('A', x);
+ char[] c = new char[26];
+ x = a.read(c, 0, 26);
+ assertTrue(a.getEncoding().equalsIgnoreCase("ISO8859_1"));
+ assertEquals(26, x);
+ assertEquals("bCdEfGhIjKlMnOpQrStUvWxYzX", String.valueOf(c));
+ } finally {
+ a.close();
+ }
+ }
+
+ /**
+ * Checks if Utf8 encoding works with InputStreamReader
+ */
+ @SmallTest
+ public void testUtf8() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYzX" +
+ "\u00a3\u00c5\u00c9"; // total of 30 characters
+ ByteArrayInputStream aa =
+ new ByteArrayInputStream(str.getBytes());
+
+ InputStreamReader a = new InputStreamReader(aa);
+
+ try {
+ assertEquals("UTF8", a.getEncoding());
+
+ int x = a.read();
+ assertEquals('A', x);
+
+ char[] c = new char[29];
+ x = a.read(c, 0, 3);
+ assertEquals(3, x);
+ assertEquals("bCd", new String(c, 0, 3));
+
+ x = a.read(c, 3, 26);
+ assertEquals(26, x);
+ assertEquals("EfGhIjKlMnOpQrStUvWxYzX\u00a3\u00c5\u00c9", new String(c, 3, 26));
+ } finally {
+ a.close();
+ }
+ }
+
+ /**
+ * Checks if several encodings works with InputStreamReader
+ */
+ @SmallTest
+ public void testStringy() throws Exception {
+ String src = "The quick brown fox\u00A0\u00FF" +
+ "\uFFFC\uD7C5\uDC03bloof";
+
+ String[] enc = new String[]{
+ "utf-8", "us-ascii", "iso-8859-1", "utf-16be", "utf-16le",
+ "utf-16",
+ };
+
+ for (int i = 0; i < enc.length; i++) {
+ byte[] ba = src.getBytes(enc[i]);
+
+ String s1 = new String(ba, enc[i]);
+
+ ByteArrayInputStream bais = new ByteArrayInputStream(ba);
+ InputStreamReader r = new InputStreamReader(bais, enc[i]);
+ try {
+ char[] ca = new char[600];
+ int n = r.read(ca, 0, 600);
+
+ String s2 = new String(ca, 0, n);
+ assertEquals(s1, s2);
+ } finally {
+ r.close();
+ }
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/JavaTests.java b/tests/CoreTests/android/core/JavaTests.java
new file mode 100644
index 0000000..bd8cbf0
--- /dev/null
+++ b/tests/CoreTests/android/core/JavaTests.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestSuite;
+
+public class JavaTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(JavaTests.class.getName());
+
+ //Disabling until bug http://b/issue?id=1200337 is resolved
+ //suite.addTestSuite(RequestAPITest.class);
+ suite.addTestSuite(MathTest.class);
+ suite.addTestSuite(StrictMathTest.class);
+ suite.addTestSuite(HashMapPerfTest.class);
+ suite.addTestSuite(TreeMapTest.class);
+ suite.addTestSuite(FloatDoubleTest.class);
+ suite.addTestSuite(Sha1Test.class);
+ suite.addTestSuite(NIOTest.class);
+ suite.addTestSuite(ReflectArrayTest.class);
+ //Commenting out until we find a better way to exclude from continuous testing.
+ //suite.addTestSuite(URLTest.class);
+ suite.addTestSuite(URITest.class);
+ suite.addTestSuite(RegexTest.class);
+ suite.addTestSuite(HashMapTest.class);
+ suite.addTestSuite(ArrayListTest.class);
+ suite.addTestSuite(BooleanTest.class);
+ suite.addTestSuite(StringTest.class);
+ suite.addTestSuite(BufferedReaderTest.class);
+ suite.addTestSuite(CharArrayReaderTest.class);
+ suite.addTestSuite(PushbackReaderTest.class);
+ suite.addTestSuite(StringReaderTest.class);
+ suite.addTestSuite(StreamTokenizerTest.class);
+ suite.addTestSuite(ByteArrayInputStreamTest.class);
+ suite.addTestSuite(DataInputStreamTest.class);
+ suite.addTestSuite(BufferedInputStreamTest.class);
+ suite.addTestSuite(PushbackInputStreamTest.class);
+ suite.addTestSuite(ByteArrayOutputStreamTest.class);
+ suite.addTestSuite(DataOutputStreamTest.class);
+ suite.addTestSuite(BufferedOutputStreamTest.class);
+ suite.addTestSuite(CharArrayWriterTest.class);
+ suite.addTestSuite(StringWriterTest.class);
+ suite.addTestSuite(PrintWriterTest.class);
+ suite.addTestSuite(BufferedWriterTest.class);
+ suite.addTestSuite(ClassTest.class);
+ //To be unccommented when Bug #799327 is fixed.
+ //suite.addTestSuite(ClassLoaderTest.class);
+ suite.addTestSuite(LineNumberReaderTest.class);
+ suite.addTestSuite(InputStreamReaderTest.class);
+ suite.addTestSuite(OutputStreamWriterTest.class);
+ suite.addTestSuite(EnumTest.class);
+ suite.addTestSuite(ParseIntTest.class);
+ suite.addTestSuite(PipedStreamTest.class);
+ suite.addTestSuite(LocaleTest.class);
+ //Commenting out until we find a better way to exclude from continuous testing.
+ //suite.addTestSuite(InetAddrTest.class);
+ suite.addTestSuite(SocketTest.class);
+ suite.addTestSuite(ChecksumTest.class);
+ suite.addTestSuite(DeflateTest.class);
+ suite.addTestSuite(ZipStreamTest.class);
+ suite.addTestSuite(GZIPStreamTest.class);
+ suite.addTestSuite(ZipFileTest.class);
+ suite.addTestSuite(FileTest.class);
+ suite.addTestSuite(SQLiteJDBCDriverTest.class);
+ suite.addTestSuite(AtParserTest.class);
+ suite.addTestSuite(DatagramTest.class);
+ suite.addTestSuite(CryptoTest.class);
+ suite.addTestSuite(MiscRegressionTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/CoreTests/android/core/LineNumberReaderTest.java b/tests/CoreTests/android/core/LineNumberReaderTest.java
new file mode 100644
index 0000000..6380ebe
--- /dev/null
+++ b/tests/CoreTests/android/core/LineNumberReaderTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.LineNumberReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Checks basic functionality for LineNumberReader.
+ */
+public class LineNumberReaderTest extends TestCase {
+
+ @MediumTest
+ public void testLineNumberReader() throws Exception {
+ String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+
+ StringReader aa = new StringReader(str);
+ StringReader ba = new StringReader(str);
+ StringReader ca = new StringReader(str);
+ StringReader da = new StringReader(str);
+ StringReader ea = new StringReader(str);
+
+ LineNumberReader a = new LineNumberReader(aa);
+ try {
+ assertEquals(0, a.getLineNumber());
+ assertEquals(str, IOUtil.read(a));
+ assertEquals(1, a.getLineNumber());
+ a.setLineNumber(5);
+ assertEquals(5, a.getLineNumber());
+ } finally {
+ a.close();
+ }
+
+ LineNumberReader b = new LineNumberReader(ba);
+ try {
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ LineNumberReader c = new LineNumberReader(ca);
+ try {
+ assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+
+ LineNumberReader d = new LineNumberReader(da);
+ try {
+ assertEquals("AbCdEfGdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+ } finally {
+ d.close();
+ }
+
+ LineNumberReader e = new LineNumberReader(ea);
+ try {
+ assertEquals("AbCdEfGhIjKlM", e.readLine());
+ } finally {
+ e.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/LocaleTest.java b/tests/CoreTests/android/core/LocaleTest.java
new file mode 100644
index 0000000..700cf1d
--- /dev/null
+++ b/tests/CoreTests/android/core/LocaleTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.nio.charset.Charset;
+import java.text.DateFormatSymbols;
+import java.util.Calendar;
+import java.util.Currency;
+import java.util.Locale;
+import java.util.Set;
+import java.util.TimeZone;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Test some locale-dependent stuff for Android. This test mainly ensures that
+ * our ICU configuration is correct and contains all the needed locales and
+ * resource bundles.
+ */
+public class LocaleTest extends TestCase {
+
+ // Test basic Locale infrastructure.
+ @SmallTest
+ public void testLocale() throws Exception {
+ Locale locale = new Locale("en");
+ assertEquals("en", locale.toString());
+
+ locale = new Locale("en", "US");
+ assertEquals("en_US", locale.toString());
+
+ locale = new Locale("en", "", "POSIX");
+ assertEquals("en__POSIX", locale.toString());
+
+ locale = new Locale("en", "US", "POSIX");
+ assertEquals("en_US_POSIX", locale.toString());
+ }
+
+ // Test some must-have locales.
+ @LargeTest
+ public void testResourceBundles() throws Exception {
+ Locale eng = new Locale("en", "US");
+ DateFormatSymbols engSymbols = new DateFormatSymbols(eng);
+
+ Locale deu = new Locale("de", "DE");
+ DateFormatSymbols deuSymbols = new DateFormatSymbols(deu);
+
+ TimeZone berlin = TimeZone.getTimeZone("Europe/Berlin");
+
+ assertEquals("January", engSymbols.getMonths()[0]);
+ assertEquals("Januar", deuSymbols.getMonths()[0]);
+
+ assertEquals("Sunday", engSymbols.getWeekdays()[Calendar.SUNDAY]);
+ assertEquals("Sonntag", deuSymbols.getWeekdays()[Calendar.SUNDAY]);
+
+ assertEquals("Central European Time",
+ berlin.getDisplayName(false, TimeZone.LONG, eng));
+ assertEquals("Central European Summer Time",
+ berlin.getDisplayName(true, TimeZone.LONG, eng));
+
+ assertEquals("Mitteleurop\u00E4ische Zeit",
+ berlin.getDisplayName(false, TimeZone.LONG, deu));
+ assertEquals("Mitteleurop\u00E4ische Sommerzeit",
+ berlin.getDisplayName(true, TimeZone.LONG, deu));
+
+ assertTrue(engSymbols.getZoneStrings().length > 100);
+ }
+
+ // Regression test for 1118570: Create test cases for tracking ICU config
+ // changes. This one makes sure we have all necessary locales installed.
+ @MediumTest
+ public void testICULocales() {
+ String[] locales = new String[] {
+ // List of locales currently required for Android.
+ "en_US", "es_US", "en_GB", "fr_FR", "de_DE", "de_AT", "cs_CZ", "nl_NL" };
+
+ String[] mondays = new String[] {
+ "Monday", "lunes", "Monday", "lundi", "Montag", "Montag", "pond\u011bl\u00ed", "maandag" };
+
+ String[] currencies = new String[] {
+ "USD", "USD", "GBP", "EUR", "EUR", "EUR", "CZK", "EUR"};
+
+ for (int i = 0; i < locales.length; i++) {
+ Locale l = new Locale(locales[i].substring(0, 2), locales[i].substring(3));
+
+ // Check language part of locale.
+ DateFormatSymbols d = new DateFormatSymbols(l);
+ assertEquals("Monday name for " + locales[i] + " must match",
+ mondays[i], d.getWeekdays()[2]);
+
+ // Check country part of locale.
+ Currency c = Currency.getInstance(l);
+ assertEquals("Currency code for " + locales[i] + " must match",
+ currencies[i], c.getCurrencyCode());
+ }
+ }
+
+ // Regression test for 1118570: Create test cases for tracking ICU config
+ // changes. This one makes sure we have the necessary converters installed
+ // and don't lose the changes to the converter alias table.
+ @MediumTest
+ public void testICUConverters() {
+ // List of encodings currently required for Android.
+ String[] encodings = new String[] {
+ // Encoding required by the language specification.
+ "US-ASCII",
+ "UTF-8",
+ "UTF-16",
+ "UTF-16BE",
+ "UTF-16LE",
+ "ISO-8859-1",
+
+ // Additional encodings included in standard ICU
+ "ISO-8859-2",
+ "ISO-8859-3",
+ "ISO-8859-4",
+ "ISO-8859-5",
+ "ISO-8859-6",
+ "ISO-8859-7",
+ "ISO-8859-8",
+ "ISO-8859-8-I",
+ "ISO-8859-9",
+ "ISO-8859-10",
+ "ISO-8859-11",
+ "ISO-8859-13",
+ "ISO-8859-14",
+ "ISO-8859-15",
+ "ISO-8859-16",
+ "ISO-2022-JP",
+ "Windows-950",
+ "Windows-1250",
+ "Windows-1251",
+ "Windows-1252",
+ "Windows-1253",
+ "Windows-1254",
+ "Windows-1255",
+ "Windows-1256",
+ "Windows-1257",
+ "Windows-1258",
+ "Big5",
+ "CP864",
+ "CP874",
+ "EUC-CN",
+ "EUC-JP",
+ "KOI8-R",
+ "Macintosh",
+ "GBK",
+ "GB2312",
+ "EUC-KR",
+
+ // Additional encoding not included in standard ICU.
+ "GSM0338" };
+
+ for (int i = 0; i < encodings.length; i++) {
+ assertTrue("Charset " + encodings[i] + " must be supported",
+ Charset.isSupported(encodings[i]));
+
+ Charset cs = Charset.forName(encodings[i]);
+ android.util.Log.d("LocaleTest", cs.name());
+
+ Set<String> aliases = cs.aliases();
+ for (String s: aliases) {
+ android.util.Log.d("LocaleTest", " - " + s);
+ }
+ }
+
+ // Test for valid encoding that is not included in Android. IBM-37 is
+ // a perfect candidate for this, as it is being used for mainframes and
+ // thus somewhat out of the scope of Android.
+ assertFalse("Charset IBM-37 must not be supported",
+ Charset.isSupported("IBM-37"));
+
+ // Test for a bogus encoding.
+ assertFalse("Charset KLINGON must not be supported",
+ Charset.isSupported("KLINGON"));
+
+ // Make sure our local change to the real translation table used for
+ // EUC-JP doesn't get lost.
+ Charset cs = Charset.forName("EUC-JP");
+ assertTrue("EUC-JP must use 'ibm-954_P101-2007'", cs.aliases().contains("ibm-954_P101-2007"));
+ }
+
+}
diff --git a/tests/CoreTests/android/core/LowLevelNetRunner.java b/tests/CoreTests/android/core/LowLevelNetRunner.java
new file mode 100644
index 0000000..812ceb5
--- /dev/null
+++ b/tests/CoreTests/android/core/LowLevelNetRunner.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+/**
+ * Provides synchronization handling for low level Request API tests
+ */
+public class LowLevelNetRunner extends Thread {
+
+ private int count = 0;
+
+ LowLevelNetRunner() {
+ }
+
+ public void incrementRunCount() {
+ count++;
+ }
+
+ /**
+ * Decrement the run count. If this returns to zero notify any
+ * test waiting.
+ */
+ public void decrementRunCount() {
+ count--;
+ if (count <= 0) {
+ synchronized (RequestAPITest.syncObj) {
+ RequestAPITest.syncObj.notifyAll();
+ }
+ }
+ }
+
+} /* LowLevelNetRunner*/
diff --git a/tests/CoreTests/android/core/MathTest.java b/tests/CoreTests/android/core/MathTest.java
new file mode 100644
index 0000000..50009db
--- /dev/null
+++ b/tests/CoreTests/android/core/MathTest.java
@@ -0,0 +1,831 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class MathTest extends TestCase {
+
+ private final double HYP = Math.sqrt(2.0);
+
+ private final double OPP = 1.0;
+
+ private final double ADJ = 1.0;
+
+ /* Required to make previous preprocessor flags work - do not remove */
+ int unused = 0;
+
+ public static void assertEquals(String message, double expected, double actual, double delta) {
+ if (delta == 0D) {
+ Assert.assertEquals(message, expected, actual, Math.ulp(expected));
+ } else {
+ Assert.assertEquals(message, expected, actual, delta);
+ }
+ }
+
+ public static void assertEquals(String message, float expected, float actual, float delta) {
+ if (delta == 0F) {
+ Assert.assertEquals(message, expected, actual, Math.ulp(expected));
+ } else {
+ Assert.assertEquals(message, expected, actual, delta);
+ }
+ }
+
+ /**
+ * @tests java.lang.Math#abs(double)
+ */
+ @SmallTest
+ public void testAbsD() {
+ // Test for method double java.lang.Math.abs(double)
+
+ assertTrue("Incorrect double abs value",
+ (Math.abs(-1908.8976) == 1908.8976));
+ assertTrue("Incorrect double abs value",
+ (Math.abs(1908.8976) == 1908.8976));
+ }
+
+ /**
+ * @tests java.lang.Math#abs(float)
+ */
+ @SmallTest
+ public void testAbsF() {
+ // Test for method float java.lang.Math.abs(float)
+ assertTrue("Incorrect float abs value",
+ (Math.abs(-1908.8976f) == 1908.8976f));
+ assertTrue("Incorrect float abs value",
+ (Math.abs(1908.8976f) == 1908.8976f));
+ }
+
+ /**
+ * @tests java.lang.Math#abs(int)
+ */
+ @SmallTest
+ public void testAbsI() {
+ // Test for method int java.lang.Math.abs(int)
+ assertTrue("Incorrect int abs value", (Math.abs(-1908897) == 1908897));
+ assertTrue("Incorrect int abs value", (Math.abs(1908897) == 1908897));
+ }
+
+ /**
+ * @tests java.lang.Math#abs(long)
+ */
+ @SmallTest
+ public void testAbsJ() {
+ // Test for method long java.lang.Math.abs(long)
+ assertTrue("Incorrect long abs value",
+ (Math.abs(-19088976000089L) == 19088976000089L));
+ assertTrue("Incorrect long abs value",
+ (Math.abs(19088976000089L) == 19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.Math#acos(double)
+ */
+ @SmallTest
+ public void testAcosD() {
+ // Test for method double java.lang.Math.acos(double)
+ double r = Math.cos(Math.acos(ADJ / HYP));
+ long lr = Double.doubleToLongBits(r);
+ long t = Double.doubleToLongBits(ADJ / HYP);
+ assertTrue("Returned incorrect arc cosine", lr == t || (lr + 1) == t
+ || (lr - 1) == t);
+ }
+
+ /**
+ * @tests java.lang.Math#asin(double)
+ */
+ @SmallTest
+ public void testAsinD() {
+ // Test for method double java.lang.Math.asin(double)
+ double r = Math.sin(Math.asin(OPP / HYP));
+ long lr = Double.doubleToLongBits(r);
+ long t = Double.doubleToLongBits(OPP / HYP);
+ assertTrue("Returned incorrect arc sine", lr == t || (lr + 1) == t
+ || (lr - 1) == t);
+ }
+
+ /**
+ * @tests java.lang.Math#atan(double)
+ */
+ @SmallTest
+ public void testAtanD() {
+ // Test for method double java.lang.Math.atan(double)
+ double answer = Math.tan(Math.atan(1.0));
+ assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+ && answer >= 9.9999999999999983E-1);
+ }
+
+ /**
+ * @tests java.lang.Math#atan2(double, double)
+ */
+ @SmallTest
+ public void testAtan2DD() {
+ // Test for method double java.lang.Math.atan2(double, double)
+ double answer = Math.atan(Math.tan(1.0));
+ assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+ && answer >= 9.9999999999999983E-1);
+ }
+
+ /**
+ * @tests java.lang.Math#cbrt(double)
+ */
+ @SmallTest
+ public void testCbrtD() {
+ //Test for special situations
+ assertTrue("Should return Double.NaN", Double.isNaN(Math
+ .cbrt(Double.NaN)));
+ assertEquals("Should return Double.POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math
+ .cbrt(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return Double.NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, Math
+ .cbrt(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .cbrt(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double.doubleToLongBits(Math
+ .cbrt(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double.doubleToLongBits(Math
+ .cbrt(-0.0)));
+
+ assertEquals("Should return 3.0", 3.0, Math.cbrt(27.0), 0D);
+ assertEquals("Should return 23.111993172558684", 23.111993172558684,
+ Math.cbrt(12345.6), 0D);
+ assertEquals("Should return 5.643803094122362E102",
+ 5.643803094122362E102, Math.cbrt(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 0.01", 0.01, Math.cbrt(0.000001), 0D);
+
+ assertEquals("Should return -3.0", -3.0, Math.cbrt(-27.0), 0D);
+ assertEquals("Should return -23.111993172558684", -23.111993172558684,
+ Math.cbrt(-12345.6), 0D);
+ assertEquals("Should return 1.7031839360032603E-108",
+ 1.7031839360032603E-108, Math.cbrt(Double.MIN_VALUE), 0D);
+ assertEquals("Should return -0.01", -0.01, Math.cbrt(-0.000001), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#ceil(double)
+ */
+ @SmallTest
+ public void testCeilD() {
+ // Test for method double java.lang.Math.ceil(double)
+ assertEquals("Incorrect ceiling for double",
+ 79, Math.ceil(78.89), 0);
+ assertEquals("Incorrect ceiling for double",
+ -78, Math.ceil(-78.89), 0);
+ }
+
+ /**
+ * @tests java.lang.Math#cos(double)
+ */
+ @SmallTest
+ public void testCosD() {
+ // Test for method double java.lang.Math.cos(double)
+ assertEquals("Incorrect answer", 1.0, Math.cos(0), 0D);
+ assertEquals("Incorrect answer", 0.5403023058681398, Math.cos(1), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#cosh(double)
+ */
+ @SmallTest
+ public void testCoshD() {
+ // Test for special situations
+ assertTrue(Double.isNaN(Math.cosh(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.cosh(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.cosh(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals("Should return 1.0", 1.0, Math.cosh(+0.0), 0D);
+ assertEquals("Should return 1.0", 1.0, Math.cosh(-0.0), 0D);
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.cosh(1234.56), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.cosh(-1234.56), 0D);
+ assertEquals("Should return 1.0000000000005", 1.0000000000005, Math
+ .cosh(0.000001), 0D);
+ assertEquals("Should return 1.0000000000005", 1.0000000000005, Math
+ .cosh(-0.000001), 0D);
+ assertEquals("Should return 5.212214351945598", 5.212214351945598, Math
+ .cosh(2.33482), 0D);
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.cosh(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 1.0", 1.0, Math.cosh(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#exp(double)
+ */
+ @SmallTest
+ public void testExpD() {
+ // Test for method double java.lang.Math.exp(double)
+ assertTrue("Incorrect answer returned for simple power", Math.abs(Math
+ .exp(4D)
+ - Math.E * Math.E * Math.E * Math.E) < 0.1D);
+ assertTrue("Incorrect answer returned for larger power", Math.log(Math
+ .abs(Math.exp(5.5D)) - 5.5D) < 10.0D);
+ }
+
+ /**
+ * @tests java.lang.Math#expm1(double)
+ */
+ @SmallTest
+ public void testExpm1D() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(Math.expm1(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.expm1(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return -1.0", -1.0, Math
+ .expm1(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .expm1(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(Math.expm1(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(Math.expm1(-0.0)));
+
+ assertEquals("Should return -9.999950000166666E-6",
+ -9.999950000166666E-6, Math.expm1(-0.00001), 0D);
+ assertEquals("Should return 1.0145103074469635E60",
+ 1.0145103074469635E60, Math.expm1(138.16951162), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math
+ .expm1(123456789123456789123456789.4521584223), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.expm1(Double.MAX_VALUE), 0D);
+ assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, Math
+ .expm1(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#floor(double)
+ */
+ @SmallTest
+ public void testFloorD() {
+ // Test for method double java.lang.Math.floor(double)
+ assertEquals("Incorrect floor for double",
+ 78, Math.floor(78.89), 0);
+ assertEquals("Incorrect floor for double",
+ -79, Math.floor(-78.89), 0);
+ }
+
+ /**
+ * @tests java.lang.Math#hypot(double, double)
+ */
+ @SmallTest
+ public void testHypotDD() {
+ // Test for special cases
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY,
+ 1.0), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY,
+ 123.324), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(-758.2587,
+ Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(5687.21,
+ Double.NEGATIVE_INFINITY), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(Double.POSITIVE_INFINITY,
+ Double.NEGATIVE_INFINITY), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.hypot(Double.NEGATIVE_INFINITY,
+ Double.POSITIVE_INFINITY), 0D);
+ assertTrue("Should be NaN", Double.isNaN(Math.hypot(Double.NaN,
+ 2342301.89843)));
+ assertTrue("Should be NaN", Double.isNaN(Math.hypot(-345.2680,
+ Double.NaN)));
+
+ assertEquals("Should return 2396424.905416697", 2396424.905416697, Math
+ .hypot(12322.12, -2396393.2258), 0D);
+ assertEquals("Should return 138.16958070558556", 138.16958070558556,
+ Math.hypot(-138.16951162, 0.13817035864), 0D);
+ assertEquals("Should return 1.7976931348623157E308",
+ 1.7976931348623157E308, Math.hypot(Double.MAX_VALUE, 211370.35), 0D);
+ assertEquals("Should return 5413.7185", 5413.7185, Math.hypot(
+ -5413.7185, Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#IEEEremainder(double, double)
+ */
+ @SmallTest
+ public void testIEEEremainderDD() {
+ // Test for method double java.lang.Math.IEEEremainder(double, double)
+ assertEquals("Incorrect remainder returned",
+ 0.0, Math.IEEEremainder(1.0, 1.0), 0D);
+ assertTrue("Incorrect remainder returned", Math.IEEEremainder(1.32,
+ 89.765) >= 1.4705063220631647E-2
+ || Math.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+ }
+
+ /**
+ * @tests java.lang.Math#log(double)
+ */
+ @SmallTest
+ public void testLogD() {
+ // Test for method double java.lang.Math.log(double)
+ for (double d = 10; d >= -10; d -= 0.5) {
+ double answer = Math.log(Math.exp(d));
+ assertTrue("Answer does not equal expected answer for d = " + d
+ + " answer = " + answer, Math.abs(answer - d) <= Math
+ .abs(d * 0.00000001));
+ }
+ }
+
+ /**
+ * @tests java.lang.Math#log10(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testLog10D() {
+ // Test for special cases
+ assertTrue(Double.isNaN(Math.log10(Double.NaN)));
+ assertTrue(Double.isNaN(Math.log10(-2541.05745687234187532)));
+ assertTrue(Double.isNaN(Math.log10(-0.1)));
+ assertEquals(Double.POSITIVE_INFINITY, Math.log10(Double.POSITIVE_INFINITY));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.log10(0.0));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.log10(+0.0));
+ assertEquals(Double.NEGATIVE_INFINITY, Math.log10(-0.0));
+
+ assertEquals(3.0, Math.log10(1000.0));
+ assertEquals(14.0, Math.log10(Math.pow(10, 14)));
+ assertEquals(3.7389561269540406, Math.log10(5482.2158));
+ assertEquals(14.661551142893833, Math.log10(458723662312872.125782332587));
+ assertEquals(-0.9083828622192334, Math.log10(0.12348583358871));
+ assertEquals(308.25471555991675, Math.log10(Double.MAX_VALUE));
+ assertEquals(-323.3062153431158, Math.log10(Double.MIN_VALUE));
+ }
+
+ /**
+ * @tests java.lang.Math#log1p(double)
+ */
+ @SmallTest
+ public void testLog1pD() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(Math.log1p(Double.NaN)));
+ assertTrue("Should return NaN", Double.isNaN(Math.log1p(-32.0482175)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.log1p(Double.POSITIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .log1p(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(Math.log1p(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(Math.log1p(-0.0)));
+
+ assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
+ Math.log1p(-0.254856327), 0D);
+ assertEquals("Should return 7.368050685564151", 7.368050685564151, Math
+ .log1p(1583.542), 0D);
+ assertEquals("Should return 0.4633708685409921", 0.4633708685409921,
+ Math.log1p(0.5894227), 0D);
+ assertEquals("Should return 709.782712893384", 709.782712893384, Math
+ .log1p(Double.MAX_VALUE), 0D);
+ assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE, Math
+ .log1p(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#max(double, double)
+ */
+ @SmallTest
+ public void testMaxDD() {
+ // Test for method double java.lang.Math.max(double, double)
+ assertEquals("Incorrect double max value", 1908897.6000089, Math.max(-1908897.6000089,
+ 1908897.6000089), 0D);
+ assertEquals("Incorrect double max value",
+ 1908897.6000089, Math.max(2.0, 1908897.6000089), 0D);
+ assertEquals("Incorrect double max value", -2.0, Math.max(-2.0,
+ -1908897.6000089), 0D);
+
+ }
+
+ /**
+ * @tests java.lang.Math#max(float, float)
+ */
+ @SmallTest
+ public void testMaxFF() {
+ // Test for method float java.lang.Math.max(float, float)
+ assertTrue("Incorrect float max value", Math.max(-1908897.600f,
+ 1908897.600f) == 1908897.600f);
+ assertTrue("Incorrect float max value",
+ Math.max(2.0f, 1908897.600f) == 1908897.600f);
+ assertTrue("Incorrect float max value",
+ Math.max(-2.0f, -1908897.600f) == -2.0f);
+ }
+
+ /**
+ * @tests java.lang.Math#max(int, int)
+ */
+ @SmallTest
+ public void testMaxII() {
+ // Test for method int java.lang.Math.max(int, int)
+ assertEquals("Incorrect int max value",
+ 19088976, Math.max(-19088976, 19088976));
+ assertEquals("Incorrect int max value",
+ 19088976, Math.max(20, 19088976));
+ assertEquals("Incorrect int max value", -20, Math.max(-20, -19088976));
+ }
+
+ /**
+ * @tests java.lang.Math#max(long, long)
+ */
+ @SmallTest
+ public void testMaxJJ() {
+ // Test for method long java.lang.Math.max(long, long)
+ assertEquals("Incorrect long max value", 19088976000089L, Math.max(-19088976000089L,
+ 19088976000089L));
+ assertEquals("Incorrect long max value",
+ 19088976000089L, Math.max(20, 19088976000089L));
+ assertEquals("Incorrect long max value",
+ -20, Math.max(-20, -19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.Math#min(double, double)
+ */
+ @SmallTest
+ public void testMinDD() {
+ // Test for method double java.lang.Math.min(double, double)
+ assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-1908897.6000089,
+ 1908897.6000089), 0D);
+ assertEquals("Incorrect double min value",
+ 2.0, Math.min(2.0, 1908897.6000089), 0D);
+ assertEquals("Incorrect double min value", -1908897.6000089, Math.min(-2.0,
+ -1908897.6000089), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#min(float, float)
+ */
+ @SmallTest
+ public void testMinFF() {
+ // Test for method float java.lang.Math.min(float, float)
+ assertTrue("Incorrect float min value", Math.min(-1908897.600f,
+ 1908897.600f) == -1908897.600f);
+ assertTrue("Incorrect float min value",
+ Math.min(2.0f, 1908897.600f) == 2.0f);
+ assertTrue("Incorrect float min value",
+ Math.min(-2.0f, -1908897.600f) == -1908897.600f);
+ }
+
+ /**
+ * @tests java.lang.Math#min(int, int)
+ */
+ @SmallTest
+ public void testMinII() {
+ // Test for method int java.lang.Math.min(int, int)
+ assertEquals("Incorrect int min value",
+ -19088976, Math.min(-19088976, 19088976));
+ assertEquals("Incorrect int min value", 20, Math.min(20, 19088976));
+ assertEquals("Incorrect int min value",
+ -19088976, Math.min(-20, -19088976));
+
+ }
+
+ /**
+ * @tests java.lang.Math#min(long, long)
+ */
+ @SmallTest
+ public void testMinJJ() {
+ // Test for method long java.lang.Math.min(long, long)
+ assertEquals("Incorrect long min value", -19088976000089L, Math.min(-19088976000089L,
+ 19088976000089L));
+ assertEquals("Incorrect long min value",
+ 20, Math.min(20, 19088976000089L));
+ assertEquals("Incorrect long min value",
+ -19088976000089L, Math.min(-20, -19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.Math#pow(double, double)
+ */
+ @SmallTest
+ public void testPowDD() {
+ // Test for method double java.lang.Math.pow(double, double)
+ assertTrue("pow returned incorrect value",
+ (long) Math.pow(2, 8) == 256l);
+ assertTrue("pow returned incorrect value",
+ Math.pow(2, -8) == 0.00390625d);
+ assertEquals("Incorrect root returned1",
+ 2, Math.sqrt(Math.pow(Math.sqrt(2), 4)), 0);
+ }
+
+ /**
+ * @tests java.lang.Math#rint(double)
+ */
+ @SmallTest
+ public void testRintD() {
+ // Test for method double java.lang.Math.rint(double)
+ assertEquals("Failed to round properly - up to odd",
+ 3.0, Math.rint(2.9), 0D);
+ assertTrue("Failed to round properly - NaN", Double.isNaN(Math
+ .rint(Double.NaN)));
+ assertEquals("Failed to round properly down to even",
+ 2.0, Math.rint(2.1), 0D);
+ assertTrue("Failed to round properly " + 2.5 + " to even", Math
+ .rint(2.5) == 2.0);
+ }
+
+ /**
+ * @tests java.lang.Math#round(double)
+ */
+ @SmallTest
+ public void testRoundD() {
+ // Test for method long java.lang.Math.round(double)
+ assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89d));
+ }
+
+ /**
+ * @tests java.lang.Math#round(float)
+ */
+ @SmallTest
+ public void testRoundF() {
+ // Test for method int java.lang.Math.round(float)
+ assertEquals("Incorrect rounding of a float", -91, Math.round(-90.89f));
+ }
+
+ /**
+ * @tests java.lang.Math#signum(double)
+ */
+ @SmallTest
+ public void testSignumD() {
+ assertTrue(Double.isNaN(Math.signum(Double.NaN)));
+ assertTrue(Double.isNaN(Math.signum(Double.NaN)));
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .signum(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(Math.signum(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(Math.signum(-0.0)));
+
+ assertEquals(1.0, Math.signum(253681.2187962), 0D);
+ assertEquals(-1.0, Math.signum(-125874693.56), 0D);
+ assertEquals(1.0, Math.signum(1.2587E-308), 0D);
+ assertEquals(-1.0, Math.signum(-1.2587E-308), 0D);
+
+ assertEquals(1.0, Math.signum(Double.MAX_VALUE), 0D);
+ assertEquals(1.0, Math.signum(Double.MIN_VALUE), 0D);
+ assertEquals(-1.0, Math.signum(-Double.MAX_VALUE), 0D);
+ assertEquals(-1.0, Math.signum(-Double.MIN_VALUE), 0D);
+ assertEquals(1.0, Math.signum(Double.POSITIVE_INFINITY), 0D);
+ assertEquals(-1.0, Math.signum(Double.NEGATIVE_INFINITY), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#signum(float)
+ */
+ @SmallTest
+ public void testSignumF() {
+ assertTrue(Float.isNaN(Math.signum(Float.NaN)));
+ assertEquals(Float.floatToIntBits(0.0f), Float
+ .floatToIntBits(Math.signum(0.0f)));
+ assertEquals(Float.floatToIntBits(+0.0f), Float
+ .floatToIntBits(Math.signum(+0.0f)));
+ assertEquals(Float.floatToIntBits(-0.0f), Float
+ .floatToIntBits(Math.signum(-0.0f)));
+
+ assertEquals(1.0f, Math.signum(253681.2187962f), 0f);
+ assertEquals(-1.0f, Math.signum(-125874693.56f), 0f);
+ assertEquals(1.0f, Math.signum(1.2587E-11f), 0f);
+ assertEquals(-1.0f, Math.signum(-1.2587E-11f), 0f);
+
+ assertEquals(1.0f, Math.signum(Float.MAX_VALUE), 0f);
+ assertEquals(1.0f, Math.signum(Float.MIN_VALUE), 0f);
+ assertEquals(-1.0f, Math.signum(-Float.MAX_VALUE), 0f);
+ assertEquals(-1.0f, Math.signum(-Float.MIN_VALUE), 0f);
+ assertEquals(1.0f, Math.signum(Float.POSITIVE_INFINITY), 0f);
+ assertEquals(-1.0f, Math.signum(Float.NEGATIVE_INFINITY), 0f);
+ }
+
+ /**
+ * @tests java.lang.Math#sin(double)
+ */
+ @SmallTest
+ public void testSinD() {
+ // Test for method double java.lang.Math.sin(double)
+ assertEquals("Incorrect answer", 0.0, Math.sin(0), 0D);
+ assertEquals("Incorrect answer", 0.8414709848078965, Math.sin(1), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#sinh(double)
+ */
+ @SmallTest
+ public void testSinhD() {
+ // Test for special situations
+ assertTrue("Should return NaN", Double.isNaN(Math.sinh(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.sinh(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, Math.sinh(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .sinh(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(Math.sinh(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(Math.sinh(-0.0)));
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.sinh(1234.56), 0D);
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, Math.sinh(-1234.56), 0D);
+ assertEquals("Should return 1.0000000000001666E-6",
+ 1.0000000000001666E-6, Math.sinh(0.000001), 0D);
+ assertEquals("Should return -1.0000000000001666E-6",
+ -1.0000000000001666E-6, Math.sinh(-0.000001), 0D);
+ assertEquals("Should return 5.115386441963859", 5.115386441963859, Math
+ .sinh(2.33482), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, Math.sinh(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 4.9E-324", 4.9E-324, Math
+ .sinh(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#sqrt(double)
+ */
+ @SmallTest
+ public void testSqrtD() {
+ // Test for method double java.lang.Math.sqrt(double)
+ assertEquals("Incorrect root returned2", 7, Math.sqrt(49), 0);
+ }
+
+ /**
+ * @tests java.lang.Math#tan(double)
+ */
+ @SmallTest
+ public void testTanD() {
+ // Test for method double java.lang.Math.tan(double)
+ assertEquals("Incorrect answer", 0.0, Math.tan(0), 0D);
+ assertEquals("Incorrect answer", 1.5574077246549023, Math.tan(1), 0D);
+
+ }
+
+ /**
+ * @tests java.lang.Math#tanh(double)
+ */
+ @SmallTest
+ public void testTanhD() {
+ // Test for special situations
+ assertTrue("Should return NaN", Double.isNaN(Math.tanh(Double.NaN)));
+ assertEquals("Should return +1.0", +1.0, Math
+ .tanh(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return -1.0", -1.0, Math
+ .tanh(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double.doubleToLongBits(Math
+ .tanh(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(Math.tanh(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(Math.tanh(-0.0)));
+
+ assertEquals("Should return 1.0", 1.0, Math.tanh(1234.56), 0D);
+ assertEquals("Should return -1.0", -1.0, Math.tanh(-1234.56), 0D);
+ assertEquals("Should return 9.999999999996666E-7",
+ 9.999999999996666E-7, Math.tanh(0.000001), 0D);
+ assertEquals("Should return 0.981422884124941", 0.981422884124941, Math
+ .tanh(2.33482), 0D);
+ assertEquals("Should return 1.0", 1.0, Math.tanh(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 4.9E-324", 4.9E-324, Math
+ .tanh(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#random()
+ */
+ @MediumTest
+ public void testRandom() {
+ // There isn't a place for these tests so just stick them here
+ assertEquals("Wrong value E",
+ 4613303445314885481L, Double.doubleToLongBits(Math.E));
+ assertEquals("Wrong value PI",
+ 4614256656552045848L, Double.doubleToLongBits(Math.PI));
+
+ for (int i = 500; i >= 0; i--) {
+ double d = Math.random();
+ assertTrue("Generated number is out of range: " + d, d >= 0.0
+ && d < 1.0);
+ }
+ }
+
+ /**
+ * @tests java.lang.Math#toRadians(double)
+ */
+ @MediumTest
+ public void testToRadiansD() {
+ for (double d = 500; d >= 0; d -= 1.0) {
+ double converted = Math.toDegrees(Math.toRadians(d));
+ assertTrue("Converted number not equal to original. d = " + d,
+ converted >= d * 0.99999999 && converted <= d * 1.00000001);
+ }
+ }
+
+ /**
+ * @tests java.lang.Math#toDegrees(double)
+ */
+ @MediumTest
+ public void testToDegreesD() {
+ for (double d = 500; d >= 0; d -= 1.0) {
+ double converted = Math.toRadians(Math.toDegrees(d));
+ assertTrue("Converted number not equal to original. d = " + d,
+ converted >= d * 0.99999999 && converted <= d * 1.00000001);
+ }
+ }
+
+ /**
+ * @tests java.lang.Math#ulp(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testUlpD() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(Math.ulp(Double.NaN)));
+ assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+ .ulp(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY, Math
+ .ulp(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+ .ulp(0.0), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+ .ulp(+0.0), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+ .ulp(-0.0), 0D);
+ assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+ .ulp(Double.MAX_VALUE), 0D);
+ assertEquals("Returned incorrect value", Math.pow(2, 971), Math
+ .ulp(-Double.MAX_VALUE), 0D);
+
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+ .ulp(Double.MIN_VALUE), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, Math
+ .ulp(-Double.MIN_VALUE), 0D);
+
+ assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+ .ulp(1.0), 0D);
+ assertEquals("Returned incorrect value", 2.220446049250313E-16, Math
+ .ulp(-1.0), 0D);
+ assertEquals("Returned incorrect value", 2.2737367544323206E-13, Math
+ .ulp(1153.0), 0D);
+ }
+
+ /**
+ * @tests java.lang.Math#ulp(float)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testUlpf() {
+ // Test for special cases
+ assertTrue("Should return NaN", Float.isNaN(Math.ulp(Float.NaN)));
+ assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+ .ulp(Float.POSITIVE_INFINITY), 0f);
+ assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY, Math
+ .ulp(Float.NEGATIVE_INFINITY), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+ .ulp(0.0f), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+ .ulp(+0.0f), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, Math
+ .ulp(-0.0f), 0f);
+ assertEquals("Returned incorrect value", 2.028241E31f, Math
+ .ulp(Float.MAX_VALUE), 0f);
+ assertEquals("Returned incorrect value", 2.028241E31f, Math
+ .ulp(-Float.MAX_VALUE), 0f);
+
+ assertEquals("Returned incorrect value", 1.4E-45f, Math
+ .ulp(Float.MIN_VALUE), 0f);
+ assertEquals("Returned incorrect value", 1.4E-45f, Math
+ .ulp(-Float.MIN_VALUE), 0f);
+
+ assertEquals("Returned incorrect value", 1.1920929E-7f, Math.ulp(1.0f),
+ 0f);
+ assertEquals("Returned incorrect value", 1.1920929E-7f,
+ Math.ulp(-1.0f), 0f);
+ assertEquals("Returned incorrect value", 1.2207031E-4f, Math
+ .ulp(1153.0f), 0f);
+ assertEquals("Returned incorrect value", 5.6E-45f, Math
+ .ulp(9.403954E-38f), 0f);
+ }
+}
diff --git a/tests/CoreTests/android/core/MiscRegressionTest.java b/tests/CoreTests/android/core/MiscRegressionTest.java
new file mode 100644
index 0000000..8fe064c
--- /dev/null
+++ b/tests/CoreTests/android/core/MiscRegressionTest.java
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.ObjectInputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.security.KeyStore;
+import java.security.cert.Certificate;
+import java.util.Arrays;
+import java.util.ConcurrentModificationException;
+import java.util.Enumeration;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Random;
+import java.util.jar.JarEntry;
+import java.util.jar.JarFile;
+import java.util.logging.Logger;
+import java.util.zip.Deflater;
+import java.util.zip.Inflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class MiscRegressionTest extends TestCase {
+
+ // Regression test for #857840: want JKS key store
+ @SmallTest
+ public void testDefaultKeystore() {
+ String type = KeyStore.getDefaultType();
+ Assert.assertEquals("Default keystore type must be Bouncy Castle", "BKS", type);
+
+ try {
+ KeyStore store = KeyStore.getInstance(KeyStore.getDefaultType());
+ Assert.assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ try {
+ KeyStore store = KeyStore.getInstance("BKS");
+ Assert.assertNotNull("Keystore must not be null", store);
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // Regression test for #1061945: negative Shorts do not
+ // serialize/deserialize correctly
+ @SmallTest
+ public void testShortSerialization() throws Exception {
+ // create an instance of ObjectInputStream
+ String x = new String("serialize_foobar");
+ java.io.ByteArrayOutputStream baos = new java.io.ByteArrayOutputStream();
+ (new java.io.ObjectOutputStream(baos)).writeObject(x);
+ ObjectInputStream ois = new java.io.ObjectInputStream(
+ new java.io.ByteArrayInputStream(baos.toByteArray()));
+
+ // get the setField(...,, short val) method in question
+ Class<ObjectInputStream> oClass = ObjectInputStream.class;
+ Method m = oClass.getDeclaredMethod("setField", new Class[] { Object.class, Class.class, String.class, short.class});
+ // compose args
+ short start = 123;
+ short origval = -1; // 0xffff
+ Short obj = new Short(start);
+ Class<Short> declaringClass = Short.class;
+ String fieldDescName = "value";
+
+ // test the initial value
+ assertEquals(obj.shortValue(), start);
+ // invoke native method to set the field "value" of type short to the newval
+ m.setAccessible(true); // since the method is private
+ m.invoke(ois, new Object[]{ obj, declaringClass, fieldDescName, new Short(origval)} );
+ // test the set value
+ short res = obj.shortValue();
+ assertEquals("Read and written values must be equal", origval, res);
+ }
+
+ // Regression test for #951285: Suitable LogHandler should be chosen
+ // depending on the environment.
+ @MediumTest
+ public void testAndroidLogHandler() throws Exception {
+ Logger.global.severe("This has logging Level.SEVERE, should become ERROR");
+ Logger.global.warning("This has logging Level.WARNING, should become WARN");
+ Logger.global.info("This has logging Level.INFO, should become INFO");
+ Logger.global.config("This has logging Level.CONFIG, should become DEBUG");
+ Logger.global.fine("This has logging Level.FINE, should become VERBOSE");
+ Logger.global.finer("This has logging Level.FINER, should become VERBOSE");
+ Logger.global.finest("This has logging Level.FINEST, should become VERBOSE");
+ }
+
+ // Regression test for #1045939: Different output for Method.toString()
+ @SmallTest
+ public void testMethodToString() {
+ try {
+ Method m1 = Object.class.getMethod("notify", new Class[] { });
+ Method m2 = Object.class.getMethod("toString", new Class[] { });
+ Method m3 = Object.class.getMethod("wait", new Class[] { long.class, int.class });
+ Method m4 = Object.class.getMethod("equals", new Class[] { Object.class });
+ Method m5 = String.class.getMethod("valueOf", new Class[] { char[].class });
+ Method m6 = Runtime.class.getMethod("exec", new Class[] { String[].class });
+
+ assertEquals("Method.toString() must match expectations",
+ "public final native void java.lang.Object.notify()",
+ m1.toString());
+
+ assertEquals("Method.toString() must match expectations",
+ "public java.lang.String java.lang.Object.toString()",
+ m2.toString());
+
+ assertEquals("Method.toString() must match expectations",
+ "public final native void java.lang.Object.wait(long,int) throws java.lang.InterruptedException",
+ m3.toString());
+
+ assertEquals("Method.toString() must match expectations",
+ "public boolean java.lang.Object.equals(java.lang.Object)",
+ m4.toString());
+
+ assertEquals("Method.toString() must match expectations",
+ "public static java.lang.String java.lang.String.valueOf(char[])",
+ m5.toString());
+
+ assertEquals("Method.toString() must match expectations",
+ "public java.lang.Process java.lang.Runtime.exec(java.lang.String[]) throws java.io.IOException",
+ m6.toString());
+
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ }
+
+ // Regression test for #1062200: Enum fails to deserialize. Actual problem
+ // was that Class.isEnum() erroneously returned true for indirect
+ // descendants of Enum.
+ enum TrafficLights {
+ RED,
+ YELLOW {},
+ GREEN {
+ @SuppressWarnings("unused")
+ int i;
+ @SuppressWarnings("unused")
+ void foobar() {}
+ };
+ }
+
+ @SmallTest
+ public void testClassIsEnum() {
+ Class<?> trafficClass = TrafficLights.class;
+
+ Class<?> redClass = TrafficLights.RED.getClass();
+ Class<?> yellowClass = TrafficLights.YELLOW.getClass();
+ Class<?> greenClass = TrafficLights.GREEN.getClass();
+
+ Assert.assertSame("Classes must be equal", trafficClass, redClass);
+ Assert.assertNotSame("Classes must be different", trafficClass, yellowClass);
+ Assert.assertNotSame("Classes must be different", trafficClass, greenClass);
+ Assert.assertNotSame("Classes must be different", yellowClass, greenClass);
+
+ Assert.assertTrue("Must be an enum", trafficClass.isEnum());
+ Assert.assertTrue("Must be an enum", redClass.isEnum());
+ Assert.assertFalse("Must not be an enum", yellowClass.isEnum());
+ Assert.assertFalse("Must not be an enum", greenClass.isEnum());
+
+ Assert.assertNotNull("Must have enum constants", trafficClass.getEnumConstants());
+ Assert.assertNull("Must not have enum constants", yellowClass.getEnumConstants());
+ Assert.assertNull("Must not have enum constants", greenClass.getEnumConstants());
+ }
+
+ // Regression test for #1046174: JarEntry.getCertificates() is really slow.
+ public void checkJarCertificates(File file) {
+ try {
+ JarFile jarFile = new JarFile(file);
+ JarEntry je = jarFile.getJarEntry("AndroidManifest.xml");
+ byte[] readBuffer = new byte[1024];
+
+ long t0 = System.currentTimeMillis();
+
+ // We must read the stream for the JarEntry to retrieve
+ // its certificates.
+ InputStream is = jarFile.getInputStream(je);
+ while (is.read(readBuffer, 0, readBuffer.length) != -1) {
+ // not using
+ }
+ is.close();
+ Certificate[] certs = je != null ? je.getCertificates() : null;
+
+ long t1 = System.currentTimeMillis();
+ android.util.Log.d("TestHarness", "loadCertificates() took " + (t1 - t0) + " ms");
+ if (certs == null) {
+ android.util.Log.d("TestHarness", "We have no certificates");
+ } else {
+ android.util.Log.d("TestHarness", "We have " + certs.length + " certificates");
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ @LargeTest
+ public void testJarCertificates() {
+ File[] files = new File("/system/app").listFiles();
+ for (int i = 0; i < files.length; i++) {
+ checkJarCertificates(files[i]);
+ }
+ }
+
+ // Regression test for #1120750: Reflection for static long fields is broken
+ private static final long MY_LONG = 5073258162644648461L;
+
+ @SmallTest
+ public void testLongFieldReflection() {
+ try {
+ Field field = getClass().getDeclaredField("MY_LONG");
+ assertEquals(5073258162644648461L, field.getLong(null));
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // Regression test for Harmony LinkedHashMap bug. Copied from core, just
+ // to make sure it doesn't get lost.
+ @SmallTest
+ public void testLinkedHashMap() {
+ // we want to test the LinkedHashMap in access ordering mode.
+ LinkedHashMap map = new LinkedHashMap<String, String>(10, 0.75f, true);
+
+ map.put("key1", "value1");
+ map.put("key2", "value2");
+ map.put("key3", "value3");
+
+ Iterator iterator = map.keySet().iterator();
+ String id = (String) iterator.next();
+ map.get(id);
+ try {
+ iterator.next();
+ // A LinkedHashMap is supposed to throw this Exception when a
+ // iterator.next() Operation takes place after a get
+ // Operation. This is because the get Operation is considered
+ // a structural modification if the LinkedHashMap is in
+ // access order mode.
+ fail("expected ConcurrentModificationException was not thrown.");
+ } catch(ConcurrentModificationException e) {
+ // expected
+ }
+
+ LinkedHashMap mapClone = (LinkedHashMap) map.clone();
+
+ iterator = map.keySet().iterator();
+ id = (String) iterator.next();
+ mapClone.get(id);
+ try {
+ iterator.next();
+ } catch(ConcurrentModificationException e) {
+ fail("expected ConcurrentModificationException was not thrown.");
+ }
+ }
+
+ // Regression test for #1212257: Boot-time package scan is slow. Not
+ // expected to fail. Please see log if you are interested in the results.
+ @LargeTest
+ public void testZipStressManifest() {
+ android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
+
+ long time0 = System.currentTimeMillis();
+
+ try {
+ File[] files = new File("/system/app").listFiles();
+
+ byte[] buffer = new byte[512];
+
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ android.util.Log.d("MiscRegressionTest",
+ "ZIP stress test processing " + files[i] + "...");
+
+ ZipFile zip = new ZipFile(files[i]);
+
+ ZipEntry entry = zip.getEntry("AndroidManifest.xml");
+ InputStream stream = zip.getInputStream(entry);
+
+ int j = stream.read(buffer);
+ while (j != -1) {
+ j = stream.read(buffer);
+ }
+
+ stream.close();
+ }
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ long time1 = System.currentTimeMillis();
+
+ android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
+ "time was " + (time1- time0) + "ms");
+ }
+
+ @LargeTest
+ public void testZipStressAllFiles() {
+ android.util.Log.d("MiscRegressionTest", "ZIP stress test started");
+
+ long time0 = System.currentTimeMillis();
+
+ try {
+ File[] files = new File("/system/app").listFiles();
+
+ byte[] buffer = new byte[512];
+
+ if (files != null) {
+ for (int i = 0; i < files.length; i++) {
+ android.util.Log.d("MiscRegressionTest",
+ "ZIP stress test processing " + files[i] + "...");
+
+ ZipFile zip = new ZipFile(files[i]);
+
+ Enumeration<? extends ZipEntry> entries = zip.entries();
+ while (entries.hasMoreElements()) {
+ InputStream stream = zip.getInputStream(entries.nextElement());
+
+ int j = stream.read(buffer);
+ while (j != -1) {
+ j = stream.read(buffer);
+ }
+
+ stream.close();
+ }
+ }
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ long time1 = System.currentTimeMillis();
+
+ android.util.Log.d("MiscRegressionTest", "ZIP stress test finished, " +
+ "time was " + (time1- time0) + "ms");
+ }
+
+ @SmallTest
+ public void testOsEncodingProperty() {
+ long time0 = System.currentTimeMillis();
+ String[] files = new File("/system/app").list();
+ long time1 = System.currentTimeMillis();
+ android.util.Log.d("MiscRegressionTest", "File.list() test finished, " +
+ "time was " + (time1- time0) + "ms");
+ }
+
+ // -------------------------------------------------------------------------
+ // Regression test for #1185084: Native memory allocated by
+ // java.util.zip.Deflater in system_server. The fix reduced some internal
+ // ZLIB buffers in size, so this test is trying to execute a lot of
+ // deflating to ensure that things are still working properly.
+ private void assertEquals(byte[] a, byte[] b) {
+ assertEquals("Arrays must have same length", a.length, b.length);
+
+ for (int i = 0; i < a.length; i++) {
+ assertEquals("Array elements #" + i + " must be equal", a[i], b[i]);
+ }
+ }
+
+ @LargeTest
+ public void testZipDeflateInflateStress() {
+
+ final int DATA_SIZE = 16384;
+
+ Random random = new Random(42); // Seed makes test reproducible
+
+ try {
+ // Outer loop selects "mode" of test.
+ for (int j = 1; j <=2 ; j++) {
+
+ byte[] input = new byte[DATA_SIZE];
+
+ if (j == 1) {
+ // Totally random content
+ random.nextBytes(input);
+ } else {
+ // Random contents with longer repetitions
+ int pos = 0;
+ while (pos < input.length) {
+ byte what = (byte)random.nextInt(256);
+ int howMany = random.nextInt(32);
+ if (pos + howMany >= input.length) {
+ howMany = input.length - pos;
+ }
+ Arrays.fill(input, pos, pos + howMany, what);
+ pos += howMany;
+ }
+ }
+
+ // Inner loop tries all 9 compression levels.
+ for (int i = 1; i <= 9; i++) {
+ android.util.Log.d("MiscRegressionTest", "ZipDeflateInflateStress test (" + j + "," + i + ")...");
+
+ byte[] zipped = new byte[2 * DATA_SIZE]; // Just to make sure...
+
+ Deflater deflater = new Deflater(i);
+ deflater.setInput(input);
+ deflater.finish();
+
+ deflater.deflate(zipped);
+
+ byte[] output = new byte[DATA_SIZE];
+
+ Inflater inflater = new Inflater();
+ inflater.setInput(zipped);
+ inflater.finished();
+
+ inflater.inflate(output);
+
+ assertEquals(input, output);
+ }
+ }
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ // Regression test for #1252043: Thread.getStackTrace() is broken
+ class MyThread extends Thread {
+ public MyThread(String name) {
+ super(name);
+ }
+
+ @Override
+ public void run() {
+ doSomething();
+ }
+
+ public void doSomething() {
+ for (int i = 0; i < 20;) {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException ex) {
+ }
+ }
+ }
+ }
+
+ class MyOtherThread extends Thread {
+ public int visibleTraces;
+
+ public MyOtherThread(ThreadGroup group, String name) {
+ super(group, name);
+ }
+
+ @Override
+ public void run() {
+ visibleTraces = Thread.getAllStackTraces().size();
+ }
+ }
+
+ @LargeTest
+ public void testThreadGetStackTrace() {
+ MyThread t1 = new MyThread("t1");
+ t1.start();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ }
+
+ StackTraceElement[] traces = t1.getStackTrace();
+ StackTraceElement trace = traces[traces.length - 2];
+
+ // Expect to find MyThread.doSomething in the trace
+ assertTrue("Must find MyThread.doSomething in trace",
+ trace.getClassName().endsWith("$MyThread") &&
+ trace.getMethodName().equals("doSomething"));
+
+ ThreadGroup g1 = new ThreadGroup("1");
+ MyOtherThread t2 = new MyOtherThread(g1, "t2");
+ t2.start();
+ try {
+ t2.join();
+ } catch (InterruptedException ex) {
+ }
+
+ // Expect to see the traces of all threads (not just t2)
+ assertTrue("Must have traces for all threads", t2.visibleTraces > 1);
+ }
+}
diff --git a/tests/CoreTests/android/core/NIOTest.java b/tests/CoreTests/android/core/NIOTest.java
new file mode 100644
index 0000000..fd279ca
--- /dev/null
+++ b/tests/CoreTests/android/core/NIOTest.java
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.nio.Buffer;
+import java.nio.BufferOverflowException;
+import java.nio.BufferUnderflowException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for some buffers from the java.nio package.
+ */
+public class NIOTest extends TestCase {
+
+ void checkBuffer(Buffer b) {
+ assertTrue(0 <= b.position());
+ assertTrue(b.position() <= b.limit());
+ assertTrue(b.limit() <= b.capacity());
+ }
+
+ @SmallTest
+ public void testNIO() throws Exception {
+ ByteBuffer b;
+
+ // Test byte array-based buffer
+ b = ByteBuffer.allocate(12);
+ byteBufferTest(b);
+
+ // Test native heap-allocated buffer
+ b = ByteBuffer.allocateDirect(12);
+ byteBufferTest(b);
+
+ // Test short array-based buffer
+ short[] shortArray = new short[8];
+ ShortBuffer sb = ShortBuffer.wrap(shortArray);
+ shortBufferTest(sb);
+
+ // Test int array-based buffer
+ int[] intArray = new int[8];
+ IntBuffer ib = IntBuffer.wrap(intArray);
+ intBufferTest(ib);
+
+ // Test float array-based buffer
+ float[] floatArray = new float[8];
+ FloatBuffer fb = FloatBuffer.wrap(floatArray);
+ floatBufferTest(fb);
+ }
+
+ private void byteBufferTest(ByteBuffer b) {
+ checkBuffer(b);
+
+ // Bounds checks
+ try {
+ b.put(-1, (byte) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ try {
+ b.put(b.limit(), (byte) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: offset < 0
+ try {
+ byte[] data = new byte[8];
+ b.position(0);
+ b.put(data, -1, 2);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: length > array.length - offset
+ try {
+ byte[] data = new byte[8];
+ b.position(0);
+ b.put(data, 1, 8);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // BufferOverflowException: length > remaining()
+ try {
+ byte[] data = new byte[8];
+ b.position(b.limit() - 2);
+ b.put(data, 0, 3);
+ fail("expected exception not thrown");
+ } catch (BufferOverflowException e) {
+ // expected
+ }
+
+ // Fill buffer with bytes A0 A1 A2 A3 ...
+ b.position(0);
+ for (int i = 0; i < b.capacity(); i++) {
+ b.put((byte) (0xA0 + i));
+ }
+ try {
+ b.put((byte) 0xFF);
+ fail("expected exception not thrown");
+ } catch (BufferOverflowException e) {
+ // expected
+ }
+
+ b.position(0);
+ assertEquals((byte) 0xA7, b.get(7));
+ try {
+ b.get(12);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ b.get(-10);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ b.position(0);
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ assertEquals((byte) 0xA0, b.get());
+ assertEquals((byte) 0xA1, b.get());
+ assertEquals((byte) 0xA2, b.get());
+ assertEquals((byte) 0xA3, b.get());
+ assertEquals((byte) 0xA4, b.get());
+ assertEquals((byte) 0xA5, b.get());
+ assertEquals((byte) 0xA6, b.get());
+ assertEquals((byte) 0xA7, b.get());
+ assertEquals((byte) 0xA8, b.get());
+ assertEquals((byte) 0xA9, b.get());
+ assertEquals((byte) 0xAA, b.get());
+ assertEquals((byte) 0xAB, b.get());
+ try {
+ b.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ b.position(0);
+ b.order(ByteOrder.BIG_ENDIAN);
+ assertEquals((byte) 0xA0, b.get());
+ assertEquals((byte) 0xA1, b.get());
+ assertEquals((byte) 0xA2, b.get());
+ assertEquals((byte) 0xA3, b.get());
+ assertEquals((byte) 0xA4, b.get());
+ assertEquals((byte) 0xA5, b.get());
+ assertEquals((byte) 0xA6, b.get());
+ assertEquals((byte) 0xA7, b.get());
+ assertEquals((byte) 0xA8, b.get());
+ assertEquals((byte) 0xA9, b.get());
+ assertEquals((byte) 0xAA, b.get());
+ assertEquals((byte) 0xAB, b.get());
+ try {
+ b.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ b.position(6);
+ b.limit(10);
+ assertEquals((byte) 0xA6, b.get());
+
+ // Check sliced buffer
+ b.position(6);
+
+ ByteBuffer bb = b.slice();
+ checkBuffer(bb);
+
+ assertEquals(0, bb.position());
+ assertEquals(4, bb.limit());
+ assertEquals(4, bb.capacity());
+
+ assertEquals((byte) 0xA6, bb.get());
+ assertEquals((byte) 0xA7, bb.get());
+ assertEquals((byte) 0xA8, bb.get());
+ assertEquals((byte) 0xA9, bb.get());
+ try {
+ bb.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ // Reset position and limit
+ b.position(0);
+ b.limit(b.capacity());
+
+ // Check 'getShort'
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ b.position(0);
+ assertEquals((short) 0xA1A0, b.getShort());
+ assertEquals((short) 0xA3A2, b.getShort());
+ assertEquals((short) 0xA5A4, b.getShort());
+ assertEquals((short) 0xA7A6, b.getShort());
+ assertEquals((short) 0xA9A8, b.getShort());
+ assertEquals((short) 0xABAA, b.getShort());
+ try {
+ bb.getShort();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ b.order(ByteOrder.BIG_ENDIAN);
+ b.position(0);
+ assertEquals((short) 0xA0A1, b.getShort());
+ assertEquals((short) 0xA2A3, b.getShort());
+ assertEquals((short) 0xA4A5, b.getShort());
+ assertEquals((short) 0xA6A7, b.getShort());
+ assertEquals((short) 0xA8A9, b.getShort());
+ assertEquals((short) 0xAAAB, b.getShort());
+ try {
+ bb.getShort();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ // Check 'getInt'
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ b.position(0);
+ assertEquals(0xA3A2A1A0, b.getInt());
+ assertEquals(0xA7A6A5A4, b.getInt());
+ assertEquals(0xABAAA9A8, b.getInt());
+ try {
+ bb.getInt();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ b.order(ByteOrder.BIG_ENDIAN);
+ b.position(0);
+ assertEquals(0xA0A1A2A3, b.getInt());
+ assertEquals(0xA4A5A6A7, b.getInt());
+ assertEquals(0xA8A9AAAB, b.getInt());
+ try {
+ bb.getInt();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ // Check 'getFloat'
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ b.position(0);
+ assertEquals(0xA3A2A1A0, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xA7A6A5A4, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xABAAA9A8, Float.floatToIntBits(b.getFloat()));
+ try {
+ b.getFloat();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ b.order(ByteOrder.BIG_ENDIAN);
+ b.position(0);
+ assertEquals(0xA0A1A2A3, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xA4A5A6A7, Float.floatToIntBits(b.getFloat()));
+ assertEquals(0xA8A9AAAB, Float.floatToIntBits(b.getFloat()));
+ try {
+ b.getFloat();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ // Check 'getDouble(int position)'
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ assertEquals(0xA7A6A5A4A3A2A1A0L, Double.doubleToLongBits(b.getDouble(0)));
+ assertEquals(0xA8A7A6A5A4A3A2A1L, Double.doubleToLongBits(b.getDouble(1)));
+ try {
+ b.getDouble(-1);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ b.getDouble(5);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ b.order(ByteOrder.BIG_ENDIAN);
+ assertEquals(0xA0A1A2A3A4A5A6A7L, Double.doubleToLongBits(b.getDouble(0)));
+ assertEquals(0xA1A2A3A4A5A6A7A8L, Double.doubleToLongBits(b.getDouble(1)));
+ try {
+ b.getDouble(-1);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+ try {
+ b.getDouble(5);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // Slice and check 'getInt'
+ b.position(1);
+ b.limit(5);
+ b.order(ByteOrder.LITTLE_ENDIAN);
+ bb = b.slice();
+ assertEquals(4, bb.capacity());
+ assertEquals(0xA4A3A2A1, bb.getInt(0));
+
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ ShortBuffer sb = bb.asShortBuffer();
+
+ checkBuffer(sb);
+ assertEquals(2, sb.capacity());
+ assertEquals((short) 0xA2A1, sb.get());
+ assertEquals((short) 0xA4A3, sb.get());
+
+ bb.order(ByteOrder.BIG_ENDIAN);
+ sb = bb.asShortBuffer();
+
+ checkBuffer(sb);
+ assertEquals(2, sb.capacity());
+ assertEquals((short) 0xA1A2, sb.get());
+ assertEquals((short) 0xA3A4, sb.get());
+
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ IntBuffer ib = bb.asIntBuffer();
+
+ checkBuffer(ib);
+ assertEquals(1, ib.capacity());
+ assertEquals(0xA4A3A2A1, ib.get());
+
+ bb.order(ByteOrder.BIG_ENDIAN);
+ ib = bb.asIntBuffer();
+
+ checkBuffer(ib);
+ assertEquals(1, ib.capacity());
+ assertEquals(0xA1A2A3A4, ib.get());
+
+ bb.order(ByteOrder.LITTLE_ENDIAN);
+ FloatBuffer fb = bb.asFloatBuffer();
+
+ checkBuffer(fb);
+ assertEquals(1, fb.capacity());
+ assertEquals(0xA4A3A2A1, Float.floatToIntBits(fb.get()));
+
+ bb.order(ByteOrder.BIG_ENDIAN);
+ fb = bb.asFloatBuffer();
+
+ checkBuffer(fb);
+ assertEquals(1, fb.capacity());
+ assertEquals(0xA1A2A3A4, Float.floatToIntBits(fb.get()));
+ }
+
+ private void shortBufferTest(ShortBuffer sb) {
+ checkBuffer(sb);
+
+ try {
+ sb.put(-1, (short) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ try {
+ sb.put(sb.limit(), (short) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: offset < 0
+ try {
+ short[] data = new short[8];
+ sb.position(0);
+ sb.put(data, -1, 2);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: length > array.length - offset
+ try {
+ short[] data = new short[8];
+ sb.position(0);
+ sb.put(data, 1, 8);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // BufferOverflowException: length > remaining()
+ try {
+ short[] data = new short[8];
+ sb.position(sb.limit() - 2);
+ sb.put(data, 0, 3);
+ fail("expected exception not thrown");
+ } catch (BufferOverflowException e) {
+ // expected
+ }
+
+ short[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+ sb.position(0);
+ sb.put(data);
+
+ try {
+ sb.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ sb.position(0);
+ assertEquals((short) 0, sb.get());
+ assertEquals((short) 10, sb.get());
+ assertEquals((short) 20, sb.get());
+ assertEquals((short) 30, sb.get());
+ assertEquals((short) 40, sb.get());
+ assertEquals((short) 50, sb.get());
+ assertEquals((short) 60, sb.get());
+ assertEquals((short) 70, sb.get());
+ try {
+ sb.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+ sb.position(1);
+ sb.put((short) 11);
+ assertEquals((short) 11, sb.get(1));
+
+ short[] ss1 = {33, 44, 55, 66};
+ sb.position(3);
+ sb.put(ss1);
+ sb.position(0);
+ assertEquals((short) 0, sb.get());
+ assertEquals((short) 11, sb.get());
+ assertEquals((short) 20, sb.get());
+ assertEquals((short) 33, sb.get());
+ assertEquals((short) 44, sb.get());
+ assertEquals((short) 55, sb.get());
+ assertEquals((short) 66, sb.get());
+ assertEquals((short) 70, sb.get());
+
+ short[] ss2 = {10, 22, 30};
+ sb.position(2);
+ sb.put(ss2, 1, 1);
+ sb.position(0);
+ assertEquals((short) 0, sb.get());
+ assertEquals((short) 11, sb.get());
+ assertEquals((short) 22, sb.get());
+ assertEquals((short) 33, sb.get());
+ assertEquals((short) 44, sb.get());
+ assertEquals((short) 55, sb.get());
+ assertEquals((short) 66, sb.get());
+ assertEquals((short) 70, sb.get());
+ }
+
+ private void intBufferTest(IntBuffer ib) {
+ checkBuffer(ib);
+
+ try {
+ ib.put(-1, (int) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ try {
+ ib.put(ib.limit(), (int) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: offset < 0
+ try {
+ int[] data = new int[8];
+ ib.position(0);
+ ib.put(data, -1, 2);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: length > array.length - offset
+ try {
+ int[] data = new int[8];
+ ib.position(0);
+ ib.put(data, 1, 8);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // BufferOverflowException: length > remaining()
+ try {
+ int[] data = new int[8];
+ ib.position(ib.limit() - 2);
+ ib.put(data, 0, 3);
+ fail("expected exception not thrown");
+ } catch (BufferOverflowException e) {
+ // expected
+ }
+
+ int[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+ ib.position(0);
+ ib.put(data);
+
+ try {
+ ib.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ ib.position(0);
+ assertEquals((int) 0, ib.get());
+ assertEquals((int) 10, ib.get());
+ assertEquals((int) 20, ib.get());
+ assertEquals((int) 30, ib.get());
+ assertEquals((int) 40, ib.get());
+ assertEquals((int) 50, ib.get());
+ assertEquals((int) 60, ib.get());
+ assertEquals((int) 70, ib.get());
+ try {
+ ib.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+ ib.position(1);
+ ib.put((int) 11);
+ assertEquals((int) 11, ib.get(1));
+
+ int[] ss1 = {33, 44, 55, 66};
+ ib.position(3);
+ ib.put(ss1);
+ ib.position(0);
+ assertEquals((int) 0, ib.get());
+ assertEquals((int) 11, ib.get());
+ assertEquals((int) 20, ib.get());
+ assertEquals((int) 33, ib.get());
+ assertEquals((int) 44, ib.get());
+ assertEquals((int) 55, ib.get());
+ assertEquals((int) 66, ib.get());
+ assertEquals((int) 70, ib.get());
+
+ int[] ss2 = {10, 22, 30};
+ ib.position(2);
+ ib.put(ss2, 1, 1);
+ ib.position(0);
+ assertEquals((int) 0, ib.get());
+ assertEquals((int) 11, ib.get());
+ assertEquals((int) 22, ib.get());
+ assertEquals((int) 33, ib.get());
+ assertEquals((int) 44, ib.get());
+ assertEquals((int) 55, ib.get());
+ assertEquals((int) 66, ib.get());
+ assertEquals((int) 70, ib.get());
+ }
+
+ void floatBufferTest(FloatBuffer fb) {
+ checkBuffer(fb);
+
+ try {
+ fb.put(-1, (float) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ try {
+ fb.put(fb.limit(), (float) 0);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: offset < 0
+ try {
+ float[] data = new float[8];
+ fb.position(0);
+ fb.put(data, -1, 2);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // IndexOutOfBoundsException: length > array.length - offset
+ try {
+ float[] data = new float[8];
+ fb.position(0);
+ fb.put(data, 1, 8);
+ fail("expected exception not thrown");
+ } catch (IndexOutOfBoundsException e) {
+ // expected
+ }
+
+ // BufferOverflowException: length > remaining()
+ try {
+ float[] data = new float[8];
+ fb.position(fb.limit() - 2);
+ fb.put(data, 0, 3);
+ fail("expected exception not thrown");
+ } catch (BufferOverflowException e) {
+ // expected
+ }
+
+ float[] data = {0, 10, 20, 30, 40, 50, 60, 70};
+ fb.position(0);
+ fb.put(data);
+
+ try {
+ fb.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+
+ fb.position(0);
+ assertEquals((float) 0, fb.get());
+ assertEquals((float) 10, fb.get());
+ assertEquals((float) 20, fb.get());
+ assertEquals((float) 30, fb.get());
+ assertEquals((float) 40, fb.get());
+ assertEquals((float) 50, fb.get());
+ assertEquals((float) 60, fb.get());
+ assertEquals((float) 70, fb.get());
+ try {
+ fb.get();
+ fail("expected exception not thrown");
+ } catch (BufferUnderflowException e) {
+ // expected
+ }
+ fb.position(1);
+ fb.put((float) 11);
+ assertEquals((float) 11, fb.get(1));
+
+ float[] ss1 = {33, 44, 55, 66};
+ fb.position(3);
+ fb.put(ss1);
+ fb.position(0);
+ assertEquals((float) 0, fb.get());
+ assertEquals((float) 11, fb.get());
+ assertEquals((float) 20, fb.get());
+ assertEquals((float) 33, fb.get());
+ assertEquals((float) 44, fb.get());
+ assertEquals((float) 55, fb.get());
+ assertEquals((float) 66, fb.get());
+ assertEquals((float) 70, fb.get());
+
+ float[] ss2 = {10, 22, 30};
+ fb.position(2);
+ fb.put(ss2, 1, 1);
+ fb.position(0);
+ assertEquals((float) 0, fb.get());
+ assertEquals((float) 11, fb.get());
+ assertEquals((float) 22, fb.get());
+ assertEquals((float) 33, fb.get());
+ assertEquals((float) 44, fb.get());
+ assertEquals((float) 55, fb.get());
+ assertEquals((float) 66, fb.get());
+ assertEquals((float) 70, fb.get());
+ }
+}
diff --git a/tests/CoreTests/android/core/OutputStreamWriterTest.java b/tests/CoreTests/android/core/OutputStreamWriterTest.java
new file mode 100644
index 0000000..1c0901e
--- /dev/null
+++ b/tests/CoreTests/android/core/OutputStreamWriterTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests basic functionality of an OutputStreamWriter.
+ */
+public class OutputStreamWriterTest extends TestCase {
+
+ @SmallTest
+ public void testOutputStreamWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ ByteArrayOutputStream aa = new ByteArrayOutputStream();
+ OutputStreamWriter a = new OutputStreamWriter(aa, "ISO8859_1");
+ try {
+ a.write(str, 0, 4);
+ a.write('A');
+ // We have to flush the OutputStreamWriter to guarantee
+ // that the results will appear in the underlying OutputStream
+ a.flush();
+ assertEquals("ISO8859_1", a.getEncoding());
+ assertEquals(5, aa.size());
+ assertEquals("AbCdA", aa.toString());
+ } finally {
+ a.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/ParseIntTest.java b/tests/CoreTests/android/core/ParseIntTest.java
new file mode 100644
index 0000000..0e3b0c6
--- /dev/null
+++ b/tests/CoreTests/android/core/ParseIntTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for functionality of class Integer to parse integers.
+ */
+public class ParseIntTest extends TestCase {
+
+ @SmallTest
+ public void testParseInt() throws Exception {
+ assertEquals(0, Integer.parseInt("0", 10));
+ assertEquals(473, Integer.parseInt("473", 10));
+ assertEquals(0, Integer.parseInt("-0", 10));
+ assertEquals(-255, Integer.parseInt("-FF", 16));
+ assertEquals(102, Integer.parseInt("1100110", 2));
+ assertEquals(2147483647, Integer.parseInt("2147483647", 10));
+ assertEquals(-2147483648, Integer.parseInt("-2147483648", 10));
+
+ try {
+ Integer.parseInt("2147483648", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("-2147483649", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ // One digit too many
+ try {
+ Integer.parseInt("21474836470", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("-21474836480", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("21474836471", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("-21474836481", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("214748364710", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("-214748364811", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("99", 8);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ try {
+ Integer.parseInt("Kona", 10);
+ fail();
+ } catch (NumberFormatException e) {
+ // ok
+ }
+
+ assertEquals(411787, Integer.parseInt("Kona", 27));
+ }
+}
diff --git a/tests/CoreTests/android/core/PipedStreamTest.java b/tests/CoreTests/android/core/PipedStreamTest.java
new file mode 100644
index 0000000..564b337
--- /dev/null
+++ b/tests/CoreTests/android/core/PipedStreamTest.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.PipedInputStream;
+import java.io.PipedOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+class Fibonacci {
+ int n1 = -1;
+ int n2;
+
+ public int next() {
+ if (n1 < 0) {
+ n1 = 0;
+ return 0;
+ } else if (n1 == 0) {
+ n2 = 0;
+ n1 = 1;
+ return 1;
+ } else {
+ int ret = n1 + n2;
+ n2 = n1;
+ n1 = ret;
+ return ret;
+ }
+ }
+}
+
+
+public class PipedStreamTest extends TestCase {
+
+ private abstract static class TestThread extends Thread {
+ public abstract void runTest() throws Exception;
+
+ public final void run() {
+ try {
+ runTest();
+ } catch (Throwable e) {
+ android.util.Log.e("PST", "Got exception " + e, e);
+ android.util.Log.e("PST", android.util.Log.getStackTraceString(e));
+ exception = e;
+ }
+ }
+
+ Throwable exception;
+ int countRead = 0;
+ }
+
+ @MediumTest
+ public void testA() throws Exception {
+
+ final PipedInputStream in = new PipedInputStream();
+ final PipedOutputStream out = new PipedOutputStream(in);
+
+ assertEquals(0, in.available());
+
+ TestThread reader, writer;
+
+ reader = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ int readInt;
+ byte readByte;
+
+ for (; ;) {
+ readInt = in.read();
+
+ if (readInt == -1) {
+ return;
+ }
+
+ readByte = (byte) readInt;
+ assertEquals(readByte, (byte) fib.next());
+ countRead++;
+ }
+ }
+ };
+
+ reader.start();
+
+ writer = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ for (int i = 0; i < 2000; i++) {
+ int toWrite = fib.next();
+ out.write(toWrite);
+ }
+ out.close();
+ }
+ };
+
+ writer.start();
+
+
+ for (; ;) {
+ try {
+ reader.join(60 * 1000);
+ writer.join(1 * 1000);
+ break;
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ assertEquals(2000, reader.countRead);
+
+ if (writer.exception != null) {
+ throw new Exception(writer.exception);
+ }
+ if (reader.exception != null) {
+ throw new Exception(reader.exception);
+ }
+ }
+
+ @MediumTest
+ public void testB() throws Exception {
+ final PipedInputStream in = new PipedInputStream();
+ final PipedOutputStream out = new PipedOutputStream(in);
+
+ assertEquals(0, in.available());
+
+ TestThread reader, writer;
+
+ reader = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ byte readBytes[] = new byte[5];
+ int ret;
+
+ for (; ;) {
+ int nread = 0;
+ while (nread < 5) {
+ ret = in.read(readBytes, nread, readBytes.length - nread);
+
+ if (ret == -1) {
+ return;
+ }
+ nread += ret;
+ }
+
+ assertEquals(5, nread);
+
+ int readInt = (((int) readBytes[0] & 0xff) << 24)
+ | (((int) readBytes[1] & 0xff) << 16)
+ | (((int) readBytes[2] & 0xff) << 8)
+ | (((int) readBytes[3] & 0xff) << 0);
+
+
+ assertEquals(readInt, fib.next());
+ assertEquals(0, readBytes[4]);
+ countRead++;
+ }
+ }
+ };
+
+ reader.start();
+
+ writer = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ byte writeBytes[] = new byte[5];
+ for (int i = 0; i < 2000; i++) {
+ int toWrite = fib.next();
+ writeBytes[0] = (byte) (toWrite >> 24);
+ writeBytes[1] = (byte) (toWrite >> 16);
+ writeBytes[2] = (byte) (toWrite >> 8);
+ writeBytes[3] = (byte) (toWrite >> 0);
+ writeBytes[4] = 0;
+ out.write(writeBytes, 0, writeBytes.length);
+ }
+ out.close();
+ }
+ };
+
+ writer.start();
+
+
+ for (; ;) {
+ try {
+ reader.join(60 * 1000);
+ writer.join(1 * 1000);
+ break;
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ assertEquals(2000, reader.countRead);
+
+ if (writer.exception != null) {
+ throw new Exception(writer.exception);
+ }
+ if (reader.exception != null) {
+ throw new Exception(reader.exception);
+ }
+ }
+
+ @SmallTest
+ public void testC() throws Exception {
+ final PipedInputStream in = new PipedInputStream();
+ final PipedOutputStream out = new PipedOutputStream(in);
+
+ assertEquals(0, in.available());
+
+ TestThread reader, writer;
+
+ reader = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ byte readBytes[] = new byte[1024 * 2];
+ int ret;
+
+ for (; ;) {
+ int nread = 0;
+ while (nread < readBytes.length) {
+ ret = in.read(readBytes, nread, readBytes.length - nread);
+
+ if (ret == -1) {
+ return;
+ }
+ nread += ret;
+ }
+
+ assertEquals(nread, readBytes.length);
+
+ for (int i = 0; i < (readBytes.length - 4); i += 4) {
+ int readInt = (((int) readBytes[i + 0] & 0xff) << 24)
+ | (((int) readBytes[i + 1] & 0xff) << 16)
+ | (((int) readBytes[i + 2] & 0xff) << 8)
+ | (((int) readBytes[i + 3] & 0xff) << 0);
+
+ assertEquals(readInt, fib.next());
+ }
+ }
+ }
+ };
+
+ reader.start();
+
+ writer = new TestThread() {
+ Fibonacci fib = new Fibonacci();
+
+ @Override
+ public void runTest() throws Exception {
+ byte writeBytes[] = new byte[1024 * 2];
+ for (int i = 0; i < (writeBytes.length - 4); i += 4) {
+ int toWrite = fib.next();
+ writeBytes[i + 0] = (byte) (toWrite >> 24);
+ writeBytes[i + 1] = (byte) (toWrite >> 16);
+ writeBytes[i + 2] = (byte) (toWrite >> 8);
+ writeBytes[i + 3] = (byte) (toWrite >> 0);
+ }
+ out.write(writeBytes, 0, writeBytes.length);
+ out.close();
+ }
+ };
+
+ writer.start();
+
+
+ for (; ;) {
+ try {
+ reader.join(60 * 1000);
+ writer.join(1 * 100);
+ break;
+ } catch (InterruptedException ex) {
+ }
+ }
+
+ if (writer.exception != null) {
+ throw new Exception(writer.exception);
+ }
+ if (reader.exception != null) {
+ throw new Exception(reader.exception);
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/PrintWriterTest.java b/tests/CoreTests/android/core/PrintWriterTest.java
new file mode 100644
index 0000000..09ee389
--- /dev/null
+++ b/tests/CoreTests/android/core/PrintWriterTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PrintWriterTest extends TestCase {
+
+ @SmallTest
+ public void testPrintWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ StringWriter aa = new StringWriter();
+ PrintWriter a = new PrintWriter(aa);
+
+ try {
+ a.write(str, 0, 26);
+ a.write('X');
+
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", aa.toString());
+
+ a.write("alphabravodelta", 5, 5);
+ a.append('X');
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", aa.toString());
+ a.append("omega");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", aa.toString());
+ a.print("ZZZ");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomegaZZZ", aa.toString());
+ } finally {
+ a.close();
+ }
+
+ StringWriter ba = new StringWriter();
+ PrintWriter b = new PrintWriter(ba);
+ try {
+ b.print(true);
+ b.print((char) 'A');
+ b.print("BCD".toCharArray());
+ b.print((double) 1.2);
+ b.print((float) 3);
+ b.print((int) 4);
+ b.print((long) 5);
+ assertEquals("trueABCD1.23.045", ba.toString());
+ b.println();
+ b.println(true);
+ b.println((char) 'A');
+ b.println("BCD".toCharArray());
+ b.println((double) 1.2);
+ b.println((float) 3);
+ b.println((int) 4);
+ b.println((long) 5);
+ b.print("THE END");
+ assertEquals("trueABCD1.23.045\ntrue\nA\nBCD\n1.2\n3.0\n4\n5\nTHE END", ba.toString());
+ } finally {
+ b.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/PushbackInputStreamTest.java b/tests/CoreTests/android/core/PushbackInputStreamTest.java
new file mode 100644
index 0000000..44cfd8a
--- /dev/null
+++ b/tests/CoreTests/android/core/PushbackInputStreamTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.PushbackInputStream;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PushbackInputStreamTest extends TestCase {
+
+ @SmallTest
+ public void testPushbackInputStream() throws Exception {
+ String str = "AbCdEfGhIjKlM\nOpQrStUvWxYz";
+ ByteArrayInputStream aa = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ba = new ByteArrayInputStream(str.getBytes());
+ ByteArrayInputStream ca = new ByteArrayInputStream(str.getBytes());
+
+ PushbackInputStream a = new PushbackInputStream(aa, 7);
+ try {
+ a.unread("push".getBytes());
+ assertEquals("pushAbCdEfGhIjKlM\nOpQrStUvWxYz", IOUtil.read(a));
+ } finally {
+ a.close();
+ }
+
+ PushbackInputStream b = new PushbackInputStream(ba, 9);
+ try {
+ b.unread('X');
+ assertEquals("XAbCdEfGhI", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ PushbackInputStream c = new PushbackInputStream(ca);
+ try {
+ assertEquals("bdfhjl\nprtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/PushbackReaderTest.java b/tests/CoreTests/android/core/PushbackReaderTest.java
new file mode 100644
index 0000000..ef62c28
--- /dev/null
+++ b/tests/CoreTests/android/core/PushbackReaderTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.PushbackReader;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class PushbackReaderTest extends TestCase {
+
+ @SmallTest
+ public void testPushbackReader() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ StringReader aa = new StringReader(str);
+ StringReader ba = new StringReader(str);
+ StringReader ca = new StringReader(str);
+
+ PushbackReader a = new PushbackReader(aa, 5);
+ try {
+ a.unread("PUSH".toCharArray());
+ assertEquals("PUSHAbCdEfGhIjKlMnOpQrStUvWxYz", IOUtil.read(a));
+ } finally {
+ a.close();
+ }
+
+ PushbackReader b = new PushbackReader(ba, 15);
+ try {
+ b.unread('X');
+ assertEquals("XAbCdEfGhI", IOUtil.read(b, 10));
+ } finally {
+ b.close();
+ }
+
+ PushbackReader c = new PushbackReader(ca);
+ try {
+ assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+ } finally {
+ c.close();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/ReflectArrayTest.java b/tests/CoreTests/android/core/ReflectArrayTest.java
new file mode 100644
index 0000000..20ee8a4
--- /dev/null
+++ b/tests/CoreTests/android/core/ReflectArrayTest.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Array;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Test java.lang.reflect.Array methods.
+ */
+public class ReflectArrayTest extends TestCase {
+
+ @SmallTest
+ public void testSingleInt() throws Exception {
+ Object intArray = Array.newInstance(Integer.TYPE, 2);
+
+ int[] array = (int[]) intArray;
+ array[0] = 5;
+ Array.setInt(intArray, 1, 6);
+
+ assertEquals(5, Array.getInt(intArray, 0));
+ assertEquals(6, array[1]);
+
+ try {
+ array[2] = 27;
+ fail("store should have failed");
+ } catch (ArrayIndexOutOfBoundsException abe) {
+ // expected
+ }
+
+ assertEquals(2, array.length);
+ assertEquals(Array.getLength(intArray), array.length);
+
+ try {
+ int[][] wrongArray = (int[][]) intArray;
+ fail("cast should have failed");
+ } catch (ClassCastException cce) {
+ // expected
+ }
+
+ intArray = Array.newInstance(Integer.TYPE, 0);
+ assertEquals(0, Array.getLength(intArray));
+ }
+
+ @SmallTest
+ public void testSingle() throws Exception {
+ Object strArray = Array.newInstance(String.class, 2);
+
+ String[] array = (String[]) strArray;
+ array[0] = "entry zero";
+ Array.set(strArray, 1, "entry one");
+
+ //System.out.println("array: " + array);
+
+ assertEquals("entry zero", Array.get(strArray, 0));
+ assertEquals("entry one", array[1]);
+
+ assertEquals(2, array.length);
+ assertEquals(Array.getLength(strArray), array.length);
+ }
+
+ @SmallTest
+ public void testMultiInt() throws Exception {
+ int[] dimensions = {3, 2, 1};
+ Object intIntIntArray = Array.newInstance(Integer.TYPE, dimensions);
+ int[][][] array3 = (int[][][]) intIntIntArray;
+
+ array3[0][0][0] = 123;
+ array3[2][1][0] = 456;
+
+ try {
+ array3[2][1][1] = 768;
+ fail("store should have failed");
+ } catch (ArrayIndexOutOfBoundsException abe) {
+ // expected
+ }
+
+ //System.out.println("array3: " + array3);
+ }
+
+ @SmallTest
+ public void testMulti() throws Exception {
+ int[] dimensions = {1, 2, 3};
+ Object strStrStrArray = Array.newInstance(String.class, dimensions);
+ String[][][] array3 = (String[][][]) strStrStrArray;
+
+ array3[0][0][0] = "zero zero zero";
+ array3[0][1][2] = "zero one two";
+
+ try {
+ array3[1][0][0] = "bad store";
+ fail("store should have failed");
+ } catch (ArrayIndexOutOfBoundsException abe) {
+ // expected
+ }
+
+ try {
+ String[][] array2 = (String[][]) strStrStrArray;
+ fail("expecting bad cast");
+ } catch (ClassCastException cce) {
+ // expected
+ }
+ //System.out.println("array3: " + array3);
+
+
+ int[] dimensions2 = {1, 2};
+ strStrStrArray = Array.newInstance(String[].class, dimensions2);
+ array3 = (String[][][]) strStrStrArray;
+ array3[0][1] = new String[3];
+ array3[0][1][2] = "zero one two";
+ try {
+ array3[1][0][0] = "bad store";
+ fail("store should have failed");
+ } catch (ArrayIndexOutOfBoundsException abe) {
+ // expected
+ }
+ //System.out.println("array3: " + array3);
+ }
+}
+
diff --git a/tests/CoreTests/android/core/RegexTest.java b/tests/CoreTests/android/core/RegexTest.java
new file mode 100644
index 0000000..a7f79e8
--- /dev/null
+++ b/tests/CoreTests/android/core/RegexTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.util.Regex;
+
+import junit.framework.TestCase;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Tests basic functionality of Pattern and Matcher classes.
+ */
+public class RegexTest extends TestCase {
+
+ @SmallTest
+ public void testMatches() throws Exception {
+ /* Tests class Matcher */
+
+ Pattern p = Pattern.compile("bcd");
+ Matcher m = p.matcher("bcd");
+ assertTrue("Should match.", m.matches());
+
+ /* Pattern in the middle */
+ p = Pattern.compile("bcd");
+ m = p.matcher("abcdefg");
+ assertFalse("Should not match.", m.matches());
+
+ /* Pattern at the head */
+ m = p.matcher("bcdefg");
+ assertFalse("Should not match.", m.matches());
+
+ /* Pattern at the tail */
+ m = p.matcher("abcd");
+ assertFalse("Should not match.", m.matches());
+
+ /* Make sure matches() doesn't change after calls to find() */
+ p = Pattern.compile(".*");
+ m = p.matcher("abc");
+ assertTrue(m.matches());
+ assertTrue(m.find());
+ assertTrue(m.matches());
+
+ p = Pattern.compile(".");
+ m = p.matcher("abc");
+ assertFalse(m.matches());
+ assertTrue(m.find());
+ assertFalse(m.matches());
+
+ /* Make sure matches() agrees after a reset() */
+ m.reset("z");
+ assertTrue(m.matches());
+
+ m.reset("xyz");
+ assertFalse(m.matches());
+
+ /* Tests class Pattern */
+
+ assertFalse("Erroneously matched partial string. " +
+ "See http://b/issue?id=754601", Pattern.matches("er", "xer"));
+ assertFalse("Erroneously matched partial string. " +
+ "See http://b/issue?id=754601", Pattern.matches("xe", "xer"));
+ assertTrue("Generic regex should match.",
+ Pattern.matches(".*", "bcd"));
+ assertTrue("Grouped regex should match.",
+ Pattern.matches("(b(c(d)))", "bcd"));
+ assertTrue("Grouped regex should match.",
+ Pattern.matches("(b)(c)(d)", "bcd"));
+ }
+
+ @SmallTest
+ public void testGroupCount() throws Exception {
+ Pattern p = Pattern.compile(
+ "\\b(?:\\+?1)?"
+ + "(?:[ -\\.])?"
+ + "\\(?(\\d{3})?\\)?"
+ + "(?:[ -\\.\\/])?"
+ + "(\\d{3})"
+ + "(?:[ -\\.])?"
+ + "(\\d{4})\\b"
+ );
+
+ Matcher m = p.matcher("1 (919) 555-1212");
+
+ assertEquals("groupCount is incorrect, see http://b/issue?id=759412",
+ 3, m.groupCount());
+ }
+
+ @SmallTest
+ public void testGroups() throws Exception {
+ Pattern p = Pattern.compile("(b)([c|d])(z*)");
+ Matcher m = p.matcher("abcdefg");
+
+ /* Must call find() first, otherwise group*() are undefined. */
+ assertTrue(m.find());
+
+ assertEquals(3, m.groupCount());
+
+ assertEquals("bc", m.group(0));
+ assertEquals("b", m.group(1));
+ assertEquals("c", m.group(2));
+ assertEquals("", m.group(3));
+ }
+
+ @SmallTest
+ public void testFind() throws Exception {
+ Pattern p = Pattern.compile(".");
+ Matcher m = p.matcher("abc");
+
+ assertTrue(m.find());
+ assertEquals("a", m.group(0));
+
+ assertTrue(m.find());
+ assertEquals("b", m.group(0));
+
+ assertTrue(m.find());
+ assertEquals("c", m.group(0));
+
+ assertFalse(m.find());
+ }
+
+ @SmallTest
+ public void testReplaceAll() throws Exception {
+ // Begins with non-matching text, ends with matching text
+ Pattern p = Pattern.compile("a*b");
+ Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+ String r = m.replaceAll("-");
+ assertEquals("foo-foo-foo-foo-", r);
+
+ // Begins with matching text, ends with non-matching text
+ p = Pattern.compile("a*b");
+ m = p.matcher("aabfooaabfooabfoobfoo");
+
+ r = m.replaceAll("-");
+ assertEquals("-foo-foo-foo-foo", r);
+ }
+
+ @SmallTest
+ public void testReplaceFirst() throws Exception {
+ // Begins with non-matching text, ends with matching text
+ Pattern p = Pattern.compile("a*b");
+ Matcher m = p.matcher("fooaabfooaabfooabfoob");
+
+ String r = m.replaceFirst("-");
+ assertEquals("foo-fooaabfooabfoob", r);
+
+ // Begins with matching text, ends with non-matching text
+ p = Pattern.compile("a*b");
+ m = p.matcher("aabfooaabfooabfoobfoo");
+
+ r = m.replaceFirst("-");
+ assertEquals("-fooaabfooabfoobfoo", r);
+ }
+
+ @SmallTest
+ public void testSplit() throws Exception {
+ Pattern p = Pattern.compile(":");
+ String[] strings;
+
+ strings = p.split("boo:and:foo");
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ strings = p.split("boo:and:foo", 2);
+ assertEquals(2, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and:foo", strings[1]);
+
+ strings = p.split("boo:and:foo", 5);
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ strings = p.split("boo:and:foo", -2);
+ assertEquals(3, strings.length);
+ assertEquals("boo", strings[0]);
+ assertEquals("and", strings[1]);
+ assertEquals("foo", strings[2]);
+
+ p = Pattern.compile("o");
+
+ strings = p.split("boo:and:foo");
+ assertEquals(3, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+
+ strings = p.split("boo:and:foo", 5);
+ assertEquals(5, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ assertEquals("", strings[3]);
+ assertEquals("", strings[4]);
+
+ strings = p.split("boo:and:foo", -2);
+ assertEquals(5, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ assertEquals("", strings[3]);
+ assertEquals("", strings[4]);
+
+ strings = p.split("boo:and:foo", 0);
+ assertEquals(3, strings.length);
+ assertEquals("b", strings[0]);
+ assertEquals("", strings[1]);
+ assertEquals(":and:f", strings[2]);
+ }
+
+ // -------------------------------------------------------------------
+ // Regression test for #1172774: Bug in Regex.java
+ // Regression test for #1216887: Regular expression match is very slow
+ public static final Pattern TOP_LEVEL_DOMAIN_PATTERN = Pattern.compile(
+ "((aero|arpa|asia|a[cdefgilmnoqrstuwxz])"
+ + "|(biz|b[abdefghijmnorstvwyz])"
+ + "|(cat|com|coop|c[acdfghiklmnoruvxyz])"
+ + "|d[ejkmoz]"
+ + "|(edu|e[cegrstu])"
+ + "|f[ijkmor]"
+ + "|(gov|g[abdefghilmnpqrstuwy])"
+ + "|h[kmnrtu]"
+ + "|(info|int|i[delmnoqrst])"
+ + "|(jobs|j[emop])"
+ + "|k[eghimnrwyz]"
+ + "|l[abcikrstuvy]"
+ + "|(mil|mobi|museum|m[acdghklmnopqrstuvwxyz])"
+ + "|(name|net|n[acefgilopruz])"
+ + "|(org|om)"
+ + "|(pro|p[aefghklmnrstwy])"
+ + "|qa"
+ + "|r[eouw]"
+ + "|s[abcdeghijklmnortuvyz]"
+ + "|(tel|travel|t[cdfghjklmnoprtvwz])"
+ + "|u[agkmsyz]"
+ + "|v[aceginu]"
+ + "|w[fs]"
+ + "|y[etu]"
+ + "|z[amw])");
+
+ public static final Pattern EMAIL_ADDRESS_PATTERN = Pattern.compile(
+ "[\\+a-zA-Z0-9\\.\\_\\%\\-]+\\@"
+ + "(("
+ + "[a-zA-Z0-9]\\.|"
+ + "([a-zA-Z0-9][a-zA-Z0-9\\-]*[a-zA-Z0-9]\\.)+)"
+ + TOP_LEVEL_DOMAIN_PATTERN
+ + ")");
+
+ @SmallTest
+ public void testMonsterRegexCorrectness() {
+ assertTrue(EMAIL_ADDRESS_PATTERN.matcher("a+b@gmail.com").matches());
+ }
+
+ @SmallTest
+ public void testMonsterRegexPerformance() {
+ android.util.Log.e("RegexTest", "RegEx performance test started.");
+ long t0 = System.currentTimeMillis();
+ Matcher m = EMAIL_ADDRESS_PATTERN.matcher("donot repeate@RC8jjjjjjjjjjjjjjj");
+ assertFalse(m.find());
+ long t1 = System.currentTimeMillis();
+ android.util.Log.e("RegexTest", "RegEx performance test finished, " +
+ "took " + (t1 - t0) + " ms.");
+ }
+
+ //
+ // -------------------------------------------------------------------
+
+}
diff --git a/tests/CoreTests/android/core/RequestAPITest.java b/tests/CoreTests/android/core/RequestAPITest.java
new file mode 100644
index 0000000..d89f5ae
--- /dev/null
+++ b/tests/CoreTests/android/core/RequestAPITest.java
@@ -0,0 +1,483 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.net.http.RequestHandle;
+import android.net.http.RequestQueue;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.util.Log;
+import android.webkit.CookieSyncManager;
+import com.google.android.collect.Maps;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Container class for all RequestAPI tests
+ */
+//http://b/issue?id=1200337
+@Suppress
+public class RequestAPITest extends AndroidTestCase implements HttpConstants {
+ private static final String LOGTAG = "http";
+
+ /*
+ Other tests to write
+ GET, HEAD, POST with differing parameters to RequestQueue
+ More reuse and pipelining tests - testing for server closing unexpectedly
+ */
+
+ // Sync object for synchronizing end of each test that does communications
+ public static Object syncObj = new Object();
+
+ private RequestQueue mRequestQueue;
+ private TestWebServer mTestWebServer;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ Log.d(LOGTAG, "Base setup context = " + mContext);
+ mRequestQueue = new RequestQueue(mContext);
+ CookieSyncManager.createInstance(mContext);
+
+ mTestWebServer = new TestWebServer();
+ mTestWebServer.initServer(8080, true);
+ }
+
+ protected void tearDown() throws Exception {
+ Log.d(LOGTAG, "Base tearDown");
+ mTestWebServer.close();
+ Log.d(LOGTAG, "Base teardown done");
+
+ super.tearDown();
+ }
+
+ public void verifyFailure(Map<String, String> headers) {
+ try {
+ RequestHandle handle =
+ mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", headers, null,
+ null, 0, false);
+
+ handle.waitUntilComplete();
+ fail("expected exception not thrown");
+ } catch (RuntimeException e) {
+ // expected
+ }
+ }
+
+ public void testRequestAddNullHeader() throws Exception {
+ /**
+ * Test Request.addHeader throws a NullPointerException if a null
+ * header is attempted to be set
+ */
+ Log.d(LOGTAG, "testRequestAddNullHeader start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put(null, null);
+ verifyFailure(headers);
+ Log.d(LOGTAG, "testRequestAddNullHeader - returning");
+ }
+
+ public void testRequestAddNullValue() throws Exception {
+ /**
+ * Test Request.addHeader throws a RuntimeException if a null
+ * value is attempted to be set
+ */
+ Log.d(LOGTAG, "testRequestAddNullValue start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put("TestHeader", null);
+ verifyFailure(headers);
+ Log.d(LOGTAG, "testRequestAddNullValue - returning");
+ }
+
+ public void testRequestAddEmptyValue() throws Exception {
+ /**
+ * Test Request.addEmptyValue throws a RuntimeException if an empty
+ * header is attempted to be set
+ */
+ Log.d(LOGTAG, "testRequestAddEmptyValue start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put("TestHeader", "");
+ verifyFailure(headers);
+ Log.d(LOGTAG, "testRequestAddEmptyValue - returning");
+ }
+
+ public void verifySuccess(Map<String, String> headers) {
+ mTestWebServer.setKeepAlive(false);
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", headers, null,
+ null, 0, false);
+ handle.waitUntilComplete();
+ }
+
+ public void testRequestAddHeader() throws Exception {
+ /**
+ * Test Request.addHeader with a valid header and value can be set without
+ * generating and exception
+ */
+ Log.d(LOGTAG, "testRequestAddHeader start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put("TestHeader", "RequestAddHeader");
+ verifySuccess(headers);
+ Log.d(LOGTAG, "testRequestAddHeader - returning");
+ }
+
+ public void testRequestAddMultiHeader() throws Exception {
+ /**
+ * Test multiple calls to Request.addHeader with valid headers and values
+ * can be set without generating and exception
+ */
+ Log.d(LOGTAG, "testRequestAddMultiHeader start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put("TestHeader", "RequestAddMultiHeader");
+ headers.put("TestHeader2", "RequestAddMultiHeader");
+ headers.put("TestHeader3", "RequestAddMultiHeader");
+ verifySuccess(headers);
+ Log.d(LOGTAG, "testRequestAddMultiHeader - returning");
+ }
+
+ public void testRequestAddSameHeader() throws Exception {
+ /**
+ * Test multiple calls to Request.addHeader with valid identical headers
+ * and values can be set without generating and exception
+ */
+ Log.d(LOGTAG, "testRequestAddSameHeader start ");
+ Map<String, String> headers = Maps.newHashMap();
+ headers.put("TestHeader", "RequestAddSameHeader");
+ headers.put("TestHeader", "RequestAddSameHeader");
+ headers.put("TestHeader", "RequestAddSameHeader");
+ verifySuccess(headers);
+ Log.d(LOGTAG, "testRequestAddSameHeader - returning");
+ }
+
+ public void testRequestAddNullHeaders() throws Exception {
+ /**
+ * Test Request.addHeaders with a null header map. This should not generate
+ * any exceptions but accept that there are no headers to add.
+ */
+ Log.d(LOGTAG, "testRequestAddNullHeaders start ");
+ verifySuccess(null);
+ Log.d(LOGTAG, "testRequestAddNullHeaders - returning");
+ }
+
+ public void testGet() throws Exception {
+ /**
+ * Test sending a GET request. Test will pass if the events received
+ * correspond with the expected response. This should respond with the
+ * test data requested.
+ */
+ TestEventHandler testEventHandler = new TestEventHandler();
+
+ mTestWebServer.setKeepAlive(false);
+
+ Log.d(LOGTAG, "testGet start ");
+
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONNECTION], "Close");
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52");
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html");
+ testEventHandler.expectData(52);
+
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler,
+ null, 0, false);
+
+ Log.d(LOGTAG, "testGet - sent request. Waiting");
+ handle.waitUntilComplete();
+ Log.d(LOGTAG, "testGet - sent request. Notified");
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ }
+
+ public void testReuse() throws Exception {
+ /**
+ * Test sending two GET requests. Test will pass if the events
+ * received correspond with the expected response.
+ */
+ final String TEST_NAME = "testReuse";
+ Log.d(LOGTAG, TEST_NAME + " start ");
+
+ TestEventHandler testEventHandler = new TestEventHandler();
+
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+
+ TestEventHandler testEventHandler2 = new TestEventHandler();
+ testEventHandler2.expectStatus(200);
+ testEventHandler2.expectHeaders();
+
+ mTestWebServer.setAcceptLimit(2);
+
+ RequestHandle handle0 = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler,
+ null, 0, false);
+ handle0.waitUntilComplete();
+ RequestHandle handle1 = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler2,
+ null, 0, false);
+ handle1.waitUntilComplete();
+
+ /* It's not correct to use same listener for multiple
+ requests. Otherwise there would be no distiction between
+ events delivered for either request. */
+
+ if (!testEventHandler.expectPassed() && !testEventHandler2.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ Log.d(LOGTAG, testEventHandler2.getFailureMessage());
+ fail();
+ }
+ Log.d(LOGTAG, TEST_NAME + " - sent request. Notified");
+ }
+
+ public void testHead() throws Exception {
+ /**
+ * Test sending a HEAD request. Test will pass if the events
+ * delivered match the expected response.
+ */
+ TestEventHandler testEventHandler = new TestEventHandler();
+
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectNoData();
+
+ mTestWebServer.setKeepAlive(false);
+ mTestWebServer.setAcceptLimit(1);
+
+
+ Log.d(LOGTAG, "testHead start - rq = " + mRequestQueue);
+
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "HEAD", null, testEventHandler,
+ null, 0, false);
+
+ Log.d(LOGTAG, "testHead - sent request waiting");
+ handle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ }
+
+ public void testChunked() throws Exception {
+ TestEventHandler testEventHandler = new TestEventHandler();
+
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+
+ mTestWebServer.setKeepAlive(false);
+ mTestWebServer.setChunked(true);
+ mTestWebServer.setAcceptLimit(1);
+
+
+ Log.d(LOGTAG, "testChunked start - rq = " + mRequestQueue);
+
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler,
+ null, 0, false);
+
+ Log.d(LOGTAG, "testChunked - sent request waiting");
+ handle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ }
+
+ public void verifyRedirect(int statusCode, String testName) throws Exception {
+ final String REDIRECT_TO = "http://localhost:8081/test1";
+
+ mTestWebServer.setKeepAlive(false);
+ TestWebServer redirectWebServer = new TestWebServer();
+ redirectWebServer.initServer(8081, true);
+ redirectWebServer.setKeepAlive(false);
+
+ try {
+ TestEventHandler testEventHandler = new TestEventHandler();
+ // Load up expected response
+ testEventHandler.expectStatus(statusCode);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_LOCATION], REDIRECT_TO);
+
+ mTestWebServer.setAcceptLimit(1);
+ mTestWebServer.setRedirect(REDIRECT_TO, statusCode);
+ redirectWebServer.setAcceptLimit(1);
+
+ Log.d(LOGTAG, testName + " start - rq = " + mRequestQueue);
+
+ RequestHandle requestHandle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ Log.d(LOGTAG, testName + " - sent request waiting");
+
+ requestHandle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+
+ requestHandle.setupRedirect(REDIRECT_TO, statusCode, new HashMap<String, String>());
+
+ testEventHandler.expectStatus(HttpConstants.HTTP_OK);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_LENGTH], "52");
+ testEventHandler.expectHeaderAdd(requestHeaders[REQ_CONTENT_TYPE], "text/html");
+ // Server name should be TestWebServer+port
+ // we ignore the server tag, so don't test it
+ // testEventHandler.expectHeaderAdd(requestHeaders[REQ_SERVER], "TestWebServer8081");
+ testEventHandler.expectData(52);
+ testEventHandler.expectEndData();
+
+ requestHandle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ } finally {
+ Log.d(LOGTAG, testName + " - returning");
+ redirectWebServer.close();
+ }
+ }
+
+ public void testRedirect301() throws Exception {
+ verifyRedirect(HttpConstants.HTTP_MOVED_PERM, "testRedirect301");
+ }
+
+ public void testRedirect302() throws Exception {
+ verifyRedirect(HttpConstants.HTTP_MOVED_TEMP, "testRedirect302");
+ }
+
+ public void testRedirect303() throws Exception {
+ verifyRedirect(HttpConstants.HTTP_SEE_OTHER, "testRedirect303");
+ }
+
+ public void testRedirect307() throws Exception {
+ verifyRedirect(307, "testRedirect307");
+ }
+
+ public void testGetAndHead() throws Exception {
+ /**
+ * Test sending a GET and a HEAD request. Test will pass if the
+ * event received correspond with the expected response. The two
+ * requests should respond the same test data.
+ */
+ mTestWebServer.setKeepAlive(true);
+ mTestWebServer.setAcceptLimit(2);
+
+ TestEventHandler testEventHandler = new TestEventHandler();
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+
+ TestEventHandler leh2 = new TestEventHandler();
+ leh2.expectStatus(200);
+ leh2.expectHeaders();
+
+ RequestHandle handle0 = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "GET", null, testEventHandler, null, 0, false);
+ handle0.waitUntilComplete();
+ RequestHandle handle1 = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "HEAD", null, testEventHandler, null, 0, false);
+
+ Log.d(LOGTAG, "testGetAndHead - sent request. Waiting");
+ handle1.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed() && !leh2.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ Log.d(LOGTAG, leh2.getFailureMessage());
+ fail();
+ }
+ }
+
+ public void testPost() throws Exception {
+ /**
+ * Test sending a POST request with no body data. Test will pass if the event
+ * received correspond with the expected response. This should respond with
+ * the test data requested.
+ */
+ TestEventHandler testEventHandler = new TestEventHandler();
+
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectData(52);
+
+ mTestWebServer.setKeepAlive(false);
+ mTestWebServer.setAcceptLimit(1);
+
+ Log.d(LOGTAG, "testPost start - rq = " + mRequestQueue);
+
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "POST", null, testEventHandler, null, 0, false);
+
+ Log.d(LOGTAG, "testPost - sent request waiting");
+ handle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ }
+
+
+ public void testPostWithData() throws Exception {
+ /**
+ * Test sending a POST request with body data. Test will pass if the event
+ * received correspond with the expected response. This should respond with
+ * the test data requested.
+ */
+
+ TestEventHandler testEventHandler = new TestEventHandler();
+ // Load up expected response
+ testEventHandler.expectStatus(200);
+ testEventHandler.expectHeaders();
+ testEventHandler.expectData(52);
+
+ mTestWebServer.setKeepAlive(false);
+ mTestWebServer.setAcceptLimit(1);
+
+ Log.d(LOGTAG, "testPostWithData start - rq = " + mRequestQueue);
+
+ String mBody = TestWebData.postContent;
+ int bodyLength = mBody.length();
+ if (bodyLength > 0) {
+ Log.v(LOGTAG, "testPostWithData: body " + mBody);
+ }
+ InputStream bodyProvider = new ByteArrayInputStream(mBody.getBytes());
+
+ RequestHandle handle = mRequestQueue.queueRequest(
+ "http://localhost:8080/test1", "POST", null, testEventHandler, bodyProvider, bodyLength, false);
+
+ Log.d(LOGTAG, "testPostWithData - sent request waiting");
+ handle.waitUntilComplete();
+
+ if (!testEventHandler.expectPassed()) {
+ Log.d(LOGTAG, testEventHandler.getFailureMessage());
+ fail("expectPassed was false " + testEventHandler.getFailureMessage());
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java
new file mode 100644
index 0000000..eec82aa
--- /dev/null
+++ b/tests/CoreTests/android/core/SQLiteJDBCDriverTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import java.io.File;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Minimal test for JDBC driver
+ */
+public class SQLiteJDBCDriverTest extends AbstractJDBCDriverTest {
+
+ private File dbFile;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ dbFile = File.createTempFile("sqliteTestDB", null);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if(dbFile != null) {
+ dbFile.delete();
+ }
+ super.tearDown();
+ }
+
+ @Override
+ protected String getConnectionURL() {
+ return "jdbc:sqlite:/" + dbFile;
+ }
+
+ @Override
+ protected File getDbFile() {
+ return dbFile;
+ }
+
+ @Override
+ protected String getJDBCDriverClassName() {
+ return "SQLite.JDBCDriver";
+ }
+
+ // Regression test for (Noser) #255: PreparedStatement.executeUpdate results
+ // in VM crashing with SIGABRT.
+ @MediumTest
+ public void test_connection3() throws Exception {
+ PreparedStatement prst = null;
+ Statement st = null;
+ Connection conn = null;
+ try {
+ Class.forName("SQLite.JDBCDriver").newInstance();
+ if (dbFile.exists()) {
+ dbFile.delete();
+ }
+ conn = DriverManager.getConnection("jdbc:sqlite:/"
+ + dbFile.getPath());
+ assertNotNull(conn);
+
+ // create table
+ st = conn.createStatement();
+ String sql = "CREATE TABLE zoo (ZID INTEGER NOT NULL, family VARCHAR (20) NOT NULL, name VARCHAR (20) NOT NULL, PRIMARY KEY(ZID) )";
+ st.executeUpdate(sql);
+
+ String update = "update zoo set family = ? where name = ?;";
+ prst = conn.prepareStatement(update);
+ prst.setString(1, "cat");
+ prst.setString(2, "Yasha");
+ // st = conn.createStatement();
+ // st.execute("select * from zoo where family = 'cat'");
+ // ResultSet rs = st.getResultSet();
+ // assertEquals(0, getCount(rs));
+ prst.executeUpdate();
+ // st.execute("select * from zoo where family = 'cat'");
+ // ResultSet rs1 = st.getResultSet();
+ // assertEquals(1, getCount(rs1));
+ try {
+ prst = conn.prepareStatement("");
+ prst.execute();
+ fail("SQLException is not thrown");
+ } catch (SQLException e) {
+ // expected
+ }
+
+ try {
+ conn.prepareStatement(null);
+ fail("NPE is not thrown");
+ } catch (Exception e) {
+ // expected
+ }
+ try {
+ st = conn.createStatement();
+ st.execute("drop table if exists zoo");
+
+ } catch (SQLException e) {
+ fail("Couldn't drop table: " + e.getMessage());
+ } finally {
+ try {
+ st.close();
+ conn.close();
+ } catch (SQLException ee) {
+ }
+ }
+ } finally {
+ try {
+ if (prst != null) {
+ prst.close();
+ }
+ if (st != null) {
+ st.close();
+ }
+ } catch (SQLException ee) {
+ }
+ }
+
+ }
+
+}
diff --git a/tests/CoreTests/android/core/SSLPerformanceTest.java b/tests/CoreTests/android/core/SSLPerformanceTest.java
new file mode 100644
index 0000000..e2bd9c5
--- /dev/null
+++ b/tests/CoreTests/android/core/SSLPerformanceTest.java
@@ -0,0 +1,432 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.test.AndroidTestCase;
+import android.os.Debug;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.impl.conn.SingleClientConnManager;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.ClientProtocolException;
+import org.apache.http.HttpResponse;
+
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSessionContext;
+import java.io.File;
+import java.io.IOException;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
+import java.security.cert.Certificate;
+import java.security.Principal;
+import java.security.KeyManagementException;
+import java.util.Arrays;
+
+public class SSLPerformanceTest extends AndroidTestCase {
+
+ static final byte[] SESSION_DATA = new byte[6000];
+ static {
+ for (int i = 0; i < SESSION_DATA.length; i++) {
+ SESSION_DATA[i] = (byte) i;
+ }
+ }
+
+ static final File dataDir = new File("/data/data/android.core/");
+ static final File filesDir = new File(dataDir, "files");
+ static final File dbDir = new File(dataDir, "databases");
+
+ static final String CACHE_DIR
+ = SSLPerformanceTest.class.getName() + "/cache";
+
+ static final int ITERATIONS = 10;
+
+ public void testCreateNewEmptyDatabase() {
+ deleteDatabase();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testCreateNewEmptyDirectory() throws IOException {
+ deleteDirectory();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testOpenDatabaseWith10Sessions() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ putSessionsIn(cache);
+ closeDatabase();
+
+ System.err.println("Size of ssl_sessions.db w/ 10 sessions: "
+ + new File(dbDir, "ssl_sessions.db").length());
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testOpenDirectoryWith10Sessions() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ putSessionsIn(cache);
+ closeDirectoryCache();
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ stopwatch.stop();
+ }
+
+ public void testGetSessionFromDatabase() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+ closeDatabase();
+
+ cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ byte[] sessionData = cache.getSessionData("foo", 443);
+
+ stopwatch.stop();
+
+ assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+ }
+
+ public void testGetSessionFromDirectory() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+ closeDirectoryCache();
+
+ cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ byte[] sessionData = cache.getSessionData("foo", 443);
+
+ stopwatch.stop();
+
+ assertTrue(Arrays.equals(SESSION_DATA, sessionData));
+ }
+
+ public void testPutSessionIntoDatabase() {
+ deleteDatabase();
+
+ DatabaseSessionCache cache = new DatabaseSessionCache(getContext());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+ stopwatch.stop();
+ }
+
+ public void testPutSessionIntoDirectory() throws IOException {
+ deleteDirectory();
+
+ SSLClientSessionCache cache = FileClientSessionCache.usingDirectory(
+ getCacheDirectory());
+ cache.getSessionData("crazybob.org", 443);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ cache.putSessionData(new FakeSession("foo"), SESSION_DATA);
+
+ stopwatch.stop();
+ }
+
+ public void testEngineInit() throws IOException, KeyManagementException {
+ Stopwatch stopwatch = new Stopwatch();
+
+ new SSLContextImpl().engineInit(null, null, null);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithoutCache() throws IOException,
+ KeyManagementException {
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithFileCache() throws IOException,
+ KeyManagementException {
+ deleteDirectory();
+
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null,
+ FileClientSessionCache.usingDirectory(getCacheDirectory()),
+ null);
+
+ // Make sure www.google.com is in the cache.
+ getVerisignDotCom(sslContext);
+
+ // Re-initialize so we hit the file cache.
+ sslContext.engineInit(null, null, null,
+ FileClientSessionCache.usingDirectory(getCacheDirectory()),
+ null);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ public void testWebRequestWithInMemoryCache() throws IOException,
+ KeyManagementException {
+ deleteDirectory();
+
+ SSLContextImpl sslContext = new SSLContextImpl();
+ sslContext.engineInit(null, null, null);
+
+ // Make sure www.google.com is in the cache.
+ getVerisignDotCom(sslContext);
+
+ Stopwatch stopwatch = new Stopwatch();
+
+ getVerisignDotCom(sslContext);
+
+ stopwatch.stop();
+ }
+
+ private void getVerisignDotCom(SSLContextImpl sslContext)
+ throws IOException {
+ SchemeRegistry schemeRegistry = new SchemeRegistry();
+ schemeRegistry.register(new Scheme("https",
+ new SSLSocketFactory(sslContext.engineGetSocketFactory()),
+ 443));
+
+ ClientConnectionManager manager =
+ new SingleClientConnManager(null, schemeRegistry);
+
+ new DefaultHttpClient(manager, null).execute(
+ new HttpGet("https://www.verisign.com"),
+ new ResponseHandler<Object>() {
+ public Object handleResponse(HttpResponse response)
+ throws ClientProtocolException, IOException {
+ return null;
+ }
+ });
+ }
+
+ private void putSessionsIn(SSLClientSessionCache cache) {
+ for (int i = 0; i < 10; i++) {
+ cache.putSessionData(new FakeSession("host" + i), SESSION_DATA);
+ }
+ }
+
+ private void deleteDatabase() {
+ closeDatabase();
+ if (!new File(dbDir, "ssl_sessions.db").delete()) {
+ System.err.println("Failed to delete database.");
+ }
+ }
+
+ private void closeDatabase() {
+ if (DatabaseSessionCache.sDefaultDatabaseHelper != null) {
+ DatabaseSessionCache.sDefaultDatabaseHelper.close();
+ }
+ DatabaseSessionCache.sDefaultDatabaseHelper = null;
+ DatabaseSessionCache.sHookInitializationDone = false;
+ DatabaseSessionCache.mNeedsCacheLoad = true;
+ }
+
+ private void deleteDirectory() {
+ closeDirectoryCache();
+
+ File dir = getCacheDirectory();
+ if (!dir.exists()) {
+ return;
+ }
+ for (File file : dir.listFiles()) {
+ file.delete();
+ }
+ if (!dir.delete()) {
+ System.err.println("Failed to delete directory.");
+ }
+ }
+
+ private void closeDirectoryCache() {
+ try {
+ Method reset = FileClientSessionCache.class
+ .getDeclaredMethod("reset");
+ reset.setAccessible(true);
+ reset.invoke(null);
+ } catch (NoSuchMethodException e) {
+ throw new RuntimeException(e);
+ } catch (IllegalAccessException e) {
+ throw new RuntimeException(e);
+ } catch (InvocationTargetException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private File getCacheDirectory() {
+ return new File(getContext().getFilesDir(), CACHE_DIR);
+ }
+
+ class Stopwatch {
+ {
+ Debug.startAllocCounting();
+ }
+ long start = System.nanoTime();
+
+ void stop() {
+ long elapsed = (System.nanoTime() - start) / 1000;
+ Debug.stopAllocCounting();
+ System.err.println(getName() + ": " + elapsed + "us, "
+ + Debug.getThreadAllocCount() + " allocations, "
+ + Debug.getThreadAllocSize() + " bytes");
+ }
+ }
+}
+
+class FakeSession implements SSLSession {
+ final String host;
+
+ FakeSession(String host) {
+ this.host = host;
+ }
+
+ public int getApplicationBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getCipherSuite() {
+ throw new UnsupportedOperationException();
+ }
+
+ public long getCreationTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte[] getId() {
+ return host.getBytes();
+ }
+
+ public long getLastAccessedTime() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Certificate[] getLocalCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Principal getLocalPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getPacketBufferSize() {
+ throw new UnsupportedOperationException();
+ }
+
+ public javax.security.cert.X509Certificate[] getPeerCertificateChain() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Certificate[] getPeerCertificates() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPeerHost() {
+ return host;
+ }
+
+ public int getPeerPort() {
+ return 443;
+ }
+
+ public Principal getPeerPrincipal() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getProtocol() {
+ throw new UnsupportedOperationException();
+ }
+
+ public SSLSessionContext getSessionContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object getValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String[] getValueNames() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void invalidate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isValid() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void putValue(String name, Object value) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void removeValue(String name) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tests/CoreTests/android/core/SSLSocketTest.java b/tests/CoreTests/android/core/SSLSocketTest.java
new file mode 100644
index 0000000..088fa8c
--- /dev/null
+++ b/tests/CoreTests/android/core/SSLSocketTest.java
@@ -0,0 +1,1089 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.harmony.xnet.provider.jsse.SSLContextImpl;
+import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache;
+import org.apache.harmony.xnet.provider.jsse.FileClientSessionCache;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.security.KeyStore;
+import java.security.KeyManagementException;
+import java.security.cert.X509Certificate;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+
+import javax.net.ssl.KeyManager;
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLServerSocket;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * SSL integration tests that hit real servers.
+ */
+public class SSLSocketTest extends TestCase {
+
+ private static SSLSocketFactory clientFactory =
+ (SSLSocketFactory) SSLSocketFactory.getDefault();
+
+ /**
+ * Does a number of HTTPS requests on some host and consumes the response.
+ * We don't use the HttpsUrlConnection class, but do this on our own
+ * with the SSLSocket class. This gives us a chance to test the basic
+ * behavior of SSL.
+ *
+ * @param host The host name the request is being sent to.
+ * @param port The port the request is being sent to.
+ * @param path The path being requested (e.g. "/index.html").
+ * @param outerLoop The number of times we reconnect and do the request.
+ * @param innerLoop The number of times we do the request for each
+ * connection (using HTTP keep-alive).
+ * @param delay The delay after each request (in seconds).
+ * @throws IOException When a problem occurs.
+ */
+ private void fetch(SSLSocketFactory socketFactory, String host, int port,
+ boolean secure, String path, int outerLoop, int innerLoop,
+ int delay, int timeout) throws IOException {
+ InetSocketAddress address = new InetSocketAddress(host, port);
+
+ for (int i = 0; i < outerLoop; i++) {
+ // Connect to the remote host
+ Socket socket = secure ? socketFactory.createSocket()
+ : new Socket();
+ if (timeout >= 0) {
+ socket.setKeepAlive(true);
+ socket.setSoTimeout(timeout * 1000);
+ }
+ socket.connect(address);
+
+ // Get the streams
+ OutputStream output = socket.getOutputStream();
+ PrintWriter writer = new PrintWriter(output);
+
+ try {
+ DataInputStream input = new DataInputStream(socket.getInputStream());
+ try {
+ for (int j = 0; j < innerLoop; j++) {
+ android.util.Log.d("SSLSocketTest",
+ "GET https://" + host + path + " HTTP/1.1");
+
+ // Send a request
+ writer.println("GET https://" + host + path + " HTTP/1.1\r");
+ writer.println("Host: " + host + "\r");
+ writer.println("Connection: " +
+ (j == innerLoop - 1 ? "Close" : "Keep-Alive")
+ + "\r");
+ writer.println("\r");
+ writer.flush();
+
+ int length = -1;
+ boolean chunked = false;
+
+ String line = input.readLine();
+
+ if (line == null) {
+ throw new IOException("No response from server");
+ // android.util.Log.d("SSLSocketTest", "No response from server");
+ }
+
+ // Consume the headers, check content length and encoding type
+ while (line != null && line.length() != 0) {
+// System.out.println(line);
+ int dot = line.indexOf(':');
+ if (dot != -1) {
+ String key = line.substring(0, dot).trim();
+ String value = line.substring(dot + 1).trim();
+
+ if ("Content-Length".equalsIgnoreCase(key)) {
+ length = Integer.valueOf(value);
+ } else if ("Transfer-Encoding".equalsIgnoreCase(key)) {
+ chunked = "Chunked".equalsIgnoreCase(value);
+ }
+
+ }
+ line = input.readLine();
+ }
+
+ assertTrue("Need either content length or chunked encoding", length != -1
+ || chunked);
+
+ // Consume the content itself
+ if (chunked) {
+ length = Integer.parseInt(input.readLine(), 16);
+ while (length != 0) {
+ byte[] buffer = new byte[length];
+ input.readFully(buffer);
+ input.readLine();
+ length = Integer.parseInt(input.readLine(), 16);
+ }
+ input.readLine();
+ } else {
+ byte[] buffer = new byte[length];
+ input.readFully(buffer);
+ }
+
+ // Sleep for the given number of seconds
+ try {
+ Thread.sleep(delay * 1000);
+ } catch (InterruptedException ex) {
+ // Shut up!
+ }
+ }
+ } finally {
+ input.close();
+ }
+ } finally {
+ writer.close();
+ }
+ // Close the connection
+ socket.close();
+ }
+ }
+
+ /**
+ * Invokes fetch() with the default socket factory.
+ */
+ private void fetch(String host, int port, boolean secure, String path,
+ int outerLoop, int innerLoop,
+ int delay, int timeout) throws IOException {
+ fetch(clientFactory, host, port, secure, path, outerLoop, innerLoop,
+ delay, timeout);
+ }
+
+ /**
+ * Does a single request for each of the hosts. Consumes the response.
+ *
+ * @throws IOException If a problem occurs.
+ */
+ public void testSimple() throws IOException {
+ fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 1, 0, 60);
+ fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
+ fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
+ fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * closed in between.
+ *
+ * @throws IOException If a problem occurs.
+ */
+ public void testRepeatedClose() throws IOException {
+ fetch("www.fortify.net", 443, true, "/sslcheck.html", 10, 1, 0, 60);
+ fetch("mail.google.com", 443, true, "/mail/", 10, 1, 0, 60);
+ fetch("www.paypal.com", 443, true, "/", 10, 1, 0, 60);
+ fetch("www.yellownet.ch", 443, true, "/", 10, 1, 0, 60);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * kept alive in between.
+ *
+ * @throws IOException If a problem occurs.
+ */
+ public void testRepeatedKeepAlive() throws IOException {
+ fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 0, 60);
+ fetch("mail.google.com", 443, true, "/mail/", 1, 10, 0, 60);
+
+ // These two don't accept keep-alive
+ // fetch("www.paypal.com", 443, "/", 1, 10);
+ // fetch("www.yellownet.ch", 443, "/", 1, 10);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * closed in between. Waits a couple of seconds after each request, but
+ * stays within a reasonable timeout. Expectation is that the connection
+ * stays open.
+ *
+ * @throws IOException If a problem occurs.
+ */
+ public void testShortTimeout() throws IOException {
+ fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 10, 5, 60);
+ fetch("mail.google.com", 443, true, "/mail/", 1, 10, 5, 60);
+
+ // These two don't accept keep-alive
+ // fetch("www.paypal.com", 443, "/", 1, 10);
+ // fetch("www.yellownet.ch", 443, "/", 1, 10);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * kept alive in between. Waits a longer time after each request.
+ * Expectation is that the host closes the connection.
+ */
+ public void testLongTimeout() {
+ // Seems to have a veeeery long timeout.
+ // fetch("www.fortify.net", 443, "/sslcheck.html", 1, 2, 60);
+
+ // Google has a 60s timeout, so 90s of waiting should trigger it.
+ try {
+ fetch("mail.google.com", 443, true, "/mail/", 1, 2, 90, 180);
+ fail("Oops - timeout expected.");
+ } catch (IOException ex) {
+ // Expected.
+ }
+
+ // These two don't accept keep-alive
+ // fetch("www.paypal.com", 443, "/", 1, 10);
+ // fetch("www.yellownet.ch", 443, "/", 1, 10);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * closed in between. Waits a longer time after each request. Expectation is
+ * that the host closes the connection.
+ */
+ // These two need manual interaction to reproduce...
+ public void xxtestBrokenConnection() {
+ try {
+ fetch("www.fortify.net", 443, true, "/sslcheck.html", 1, 2, 60, 60);
+ fail("Oops - timeout expected.");
+ } catch (IOException ex) {
+ android.util.Log.d("SSLSocketTest", "Exception", ex);
+ // Expected.
+ }
+
+ // These two don't accept keep-alive
+ // fetch("www.paypal.com", 443, "/", 1, 10);
+ // fetch("www.yellownet.ch", 443, "/", 1, 10);
+ }
+
+ /**
+ * Does repeated requests for each of the hosts, with the connection being
+ * closed in between. Waits a longer time after each request. Expectation is
+ * that the host closes the connection.
+ */
+ // These two need manual interaction to reproduce...
+ public void xxtestBrokenConnection2() {
+ try {
+ fetch("www.heise.de", 80, false, "/index.html", 1, 2, 60, 60);
+ fail("Oops - timeout expected.");
+ } catch (IOException ex) {
+ android.util.Log.d("SSLSocketTest", "Exception", ex);
+ // Expected.
+ }
+
+ // These two don't accept keep-alive
+ // fetch("www.paypal.com", 443, "/", 1, 10);
+ // fetch("www.yellownet.ch", 443, "/", 1, 10);
+ }
+
+ /**
+ * Regression test for 865926: SSLContext.init() should
+ * use default values for null arguments.
+ */
+ public void testContextInitNullArgs() throws Exception {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ ctx.init(null, null, null);
+ }
+
+ /**
+ * Regression test for 963650: javax.net.ssl.KeyManager has no implemented
+ * (documented?) algorithms.
+ */
+ public void testDefaultAlgorithms() throws Exception {
+ SSLContext ctx = SSLContext.getInstance("TLS");
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
+ KeyStore ks = KeyStore.getInstance("BKS");
+
+ assertEquals("X509", kmf.getAlgorithm());
+ assertEquals("X509", KeyManagerFactory.getDefaultAlgorithm());
+
+ assertEquals("BKS", ks.getType());
+ assertEquals("BKS", KeyStore.getDefaultType());
+ }
+
+ /**
+ * Regression test for problem where close() resulted in a hand if
+ * a different thread was sitting in a blocking read or write.
+ */
+ public void testMultithreadedClose() throws Exception {
+ InetSocketAddress address = new InetSocketAddress("www.fortify.net", 443);
+ final Socket socket = clientFactory.createSocket();
+ socket.connect(address);
+
+ Thread reader = new Thread() {
+ @Override
+ public void run() {
+ try {
+ byte[] buffer = new byte[512];
+ InputStream stream = socket.getInputStream();
+ socket.getInputStream().read(buffer);
+ } catch (Exception ex) {
+ android.util.Log.d("SSLSocketTest",
+ "testMultithreadedClose() reader got " + ex.toString());
+ }
+ }
+ };
+
+ Thread closer = new Thread() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(5000);
+ socket.close();
+ } catch (Exception ex) {
+ android.util.Log.d("SSLSocketTest",
+ "testMultithreadedClose() closer got " + ex.toString());
+ }
+ }
+ };
+
+ android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting reader...");
+ reader.start();
+ android.util.Log.d("SSLSocketTest", "testMultithreadedClose() starting closer...");
+ closer.start();
+
+ long t1 = System.currentTimeMillis();
+ android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining reader...");
+ reader.join(30000);
+ android.util.Log.d("SSLSocketTest", "testMultithreadedClose() joining closer...");
+ closer.join(30000);
+ long t2 = System.currentTimeMillis();
+
+ assertTrue("Concurrent close() hangs", t2 - t1 < 30000);
+ }
+
+ private int multithreadedFetchRuns;
+
+ private int multithreadedFetchWins;
+
+ private Random multithreadedFetchRandom = new Random();
+
+ /**
+ * Regression test for problem where multiple threads with multiple SSL
+ * connection would cause problems due to either missing native locking
+ * or the slowness of the SSL connections.
+ */
+ public void testMultithreadedFetch() {
+ Thread[] threads = new Thread[10];
+
+ for (int i = 0; i < threads.length; i++) {
+ threads[i] = new Thread() {
+ @Override
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ try {
+ multithreadedFetchRuns++;
+ switch (multithreadedFetchRandom.nextInt(4)) {
+ case 0: {
+ fetch("www.fortify.net", 443,
+ true, "/sslcheck.html", 1, 1, 0, 60);
+ break;
+ }
+
+ case 1: {
+ fetch("mail.google.com", 443, true, "/mail/", 1, 1, 0, 60);
+ break;
+ }
+
+ case 2: {
+ fetch("www.paypal.com", 443, true, "/", 1, 1, 0, 60);
+ break;
+ }
+
+ case 3: {
+ fetch("www.yellownet.ch", 443, true, "/", 1, 1, 0, 60);
+ break;
+ }
+ }
+ multithreadedFetchWins++;
+ } catch (Exception ex) {
+ android.util.Log.d("SSLSocketTest",
+ "testMultithreadedFetch() got Exception", ex);
+ }
+ }
+ }
+ };
+ threads[i].start();
+
+ android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() started thread #" + i);
+ }
+
+ for (int i = 0; i < threads.length; i++) {
+ try {
+ threads[i].join();
+ android.util.Log.d("SSLSocketTest", "testMultithreadedFetch() joined thread #" + i);
+ } catch (InterruptedException ex) {
+ // Not interested.
+ }
+ }
+
+ assertTrue("At least 95% of multithreaded SSL connections must succeed",
+ multithreadedFetchWins >= (multithreadedFetchRuns * 95) / 100);
+ }
+
+ // -------------------------------------------------------------------------
+ // Regression test for #1204316: Missing client cert unit test. Passes on
+ // both Android and the RI. To use on the RI, install Apache Commons and
+ // replace the references to the base64-encoded keys by the JKS versions.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Defines the keystore contents for the server, JKS version. Holds just a
+ * single self-generated key. The subject name is "Test Server".
+ */
+ private static final String SERVER_KEYS_JKS =
+ "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFfBeAAAArowggK2MA4GCisGAQQBKgIRAQEFAASC" +
+ "AqI2kp5XjnF8YZkhcF92YsJNQkvsmH7zqMM87j23zSoV4DwyE3XeC/gZWq1ToScIhoqZkzlbWcu4" +
+ "T/Zfc/DrfGk/rKbBL1uWKGZ8fMtlZk8KoAhxZk1JSyJvdkyKxqmzUbxk1OFMlN2VJNu97FPVH+du" +
+ "dvjTvmpdoM81INWBW/1fZJeQeDvn4mMbbe0IxgpiLnI9WSevlaDP/sm1X3iO9yEyzHLL+M5Erspo" +
+ "Cwa558fOu5DdsICMXhvDQxjWFKFhPHnKtGe+VvwkG9/bAaDgx3kfhk0w5zvdnkKb+8Ed9ylNRzdk" +
+ "ocAa/mxlMTOsTvDKXjjsBupNPIIj7OP4GNnZaxkJjSs98pEO67op1GX2qhy6FSOPNuq8k/65HzUc" +
+ "PYn6voEeh6vm02U/sjEnzRevQ2+2wXoAdp0EwtQ/DlMe+NvcwPGWKuMgX4A4L93DZGb04N2VmAU3" +
+ "YLOtZwTO0LbuWrcCM/q99G/7LcczkxIVrO2I/rh8RXVczlf9QzcrFObFv4ATuspWJ8xG7DhsMbnk" +
+ "rT94Pq6TogYeoz8o8ZMykesAqN6mt/9+ToIemmXv+e+KU1hI5oLwWMnUG6dXM6hIvrULY6o+QCPH" +
+ "172YQJMa+68HAeS+itBTAF4Clm/bLn6reHCGGU6vNdwU0lYldpiOj9cB3t+u2UuLo6tiFWjLf5Zs" +
+ "EQJETd4g/EK9nHxJn0GAKrWnTw7pEHQJ08elzUuy04C/jEEG+4QXU1InzS4o/kR0Sqz2WTGDoSoq" +
+ "ewuPRU5bzQs/b9daq3mXrnPtRBL6HfSDAdpTK76iHqLCGdqx3avHjVSBm4zFvEuYBCev+3iKOBmg" +
+ "yh7eQRTjz4UOWfy85omMBr7lK8PtfVBDzOXpasxS0uBgdUyBDX4tO6k9jZ8a1kmQRQAAAAEABVgu" +
+ "NTA5AAACSDCCAkQwggGtAgRIR8SKMA0GCSqGSIb3DQEBBAUAMGkxCzAJBgNVBAYTAlVTMRMwEQYD" +
+ "VQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMH" +
+ "QW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBTZXJ2ZXIwHhcNMDgwNjA1MTA0ODQyWhcNMDgwOTAzMTA0" +
+ "ODQyWjBpMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8w" +
+ "DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMIGf" +
+ "MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCwoC6chqCI84rj1PrXuJgbiit4EV909zR6N0jNlYfg" +
+ "itwB39bP39wH03rFm8T59b3mbSptnGmCIpLZn25KPPFsYD3JJ+wFlmiUdEP9H05flfwtFQJnw9uT" +
+ "3rRIdYVMPcQ3RoZzwAMliGr882I2thIDbA6xjGU/1nRIdvk0LtxH3QIDAQABMA0GCSqGSIb3DQEB" +
+ "BAUAA4GBAJn+6YgUlY18Ie+0+Vt8oEi81DNi/bfPrAUAh63fhhBikx/3R9dl3wh09Z6p7cIdNxjW" +
+ "n2ll+cRW9eqF7z75F0Omm0C7/KAEPjukVbszmzeU5VqzkpSt0j84YWi+TfcHRrfvhLbrlmGITVpY" +
+ "ol5pHLDyqGmDs53pgwipWqsn/nEXEBgj3EoqPeqHbDf7YaP8h/5BSt0=";
+
+ /**
+ * Defines the keystore contents for the server, BKS version. Holds just a
+ * single self-generated key. The subject name is "Test Server".
+ */
+ private static final String SERVER_KEYS_BKS =
+ "AAAAAQAAABQDkebzoP1XwqyWKRCJEpn/t8dqIQAABDkEAAVteWtleQAAARpYl20nAAAAAQAFWC41" +
+ "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU1jANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
+ "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
+ "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgU2VydmVyMB4XDTA4MDYwNTExNTgxNFoXDTA4MDkw" +
+ "MzExNTgxNFowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
+ "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IFNlcnZl" +
+ "cjCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA0LIdKaIr9/vsTq8BZlA3R+NFWRaH4lGsTAQy" +
+ "DPMF9ZqEDOaL6DJuu0colSBBBQ85hQTPa9m9nyJoN3pEi1hgamqOvQIWcXBk+SOpUGRZZFXwniJV" +
+ "zDKU5nE9MYgn2B9AoiH3CSuMz6HRqgVaqtppIe1jhukMc/kHVJvlKRNy9XMCAwEAATANBgkqhkiG" +
+ "9w0BAQUFAAOBgQC7yBmJ9O/eWDGtSH9BH0R3dh2NdST3W9hNZ8hIa8U8klhNHbUCSSktZmZkvbPU" +
+ "hse5LI3dh6RyNDuqDrbYwcqzKbFJaq/jX9kCoeb3vgbQElMRX8D2ID1vRjxwlALFISrtaN4VpWzV" +
+ "yeoHPW4xldeZmoVtjn8zXNzQhLuBqX2MmAAAAqwAAAAUvkUScfw9yCSmALruURNmtBai7kQAAAZx" +
+ "4Jmijxs/l8EBaleaUru6EOPioWkUAEVWCxjM/TxbGHOi2VMsQWqRr/DZ3wsDmtQgw3QTrUK666sR" +
+ "MBnbqdnyCyvM1J2V1xxLXPUeRBmR2CXorYGF9Dye7NkgVdfA+9g9L/0Au6Ugn+2Cj5leoIgkgApN" +
+ "vuEcZegFlNOUPVEs3SlBgUF1BY6OBM0UBHTPwGGxFBBcetcuMRbUnu65vyDG0pslT59qpaR0TMVs" +
+ "P+tcheEzhyjbfM32/vwhnL9dBEgM8qMt0sqF6itNOQU/F4WGkK2Cm2v4CYEyKYw325fEhzTXosck" +
+ "MhbqmcyLab8EPceWF3dweoUT76+jEZx8lV2dapR+CmczQI43tV9btsd1xiBbBHAKvymm9Ep9bPzM" +
+ "J0MQi+OtURL9Lxke/70/MRueqbPeUlOaGvANTmXQD2OnW7PISwJ9lpeLfTG0LcqkoqkbtLKQLYHI" +
+ "rQfV5j0j+wmvmpMxzjN3uvNajLa4zQ8l0Eok9SFaRr2RL0gN8Q2JegfOL4pUiHPsh64WWya2NB7f" +
+ "V+1s65eA5ospXYsShRjo046QhGTmymwXXzdzuxu8IlnTEont6P4+J+GsWk6cldGbl20hctuUKzyx" +
+ "OptjEPOKejV60iDCYGmHbCWAzQ8h5MILV82IclzNViZmzAapeeCnexhpXhWTs+xDEYSKEiG/camt" +
+ "bhmZc3BcyVJrW23PktSfpBQ6D8ZxoMfF0L7V2GQMaUg+3r7ucrx82kpqotjv0xHghNIm95aBr1Qw" +
+ "1gaEjsC/0wGmmBDg1dTDH+F1p9TInzr3EFuYD0YiQ7YlAHq3cPuyGoLXJ5dXYuSBfhDXJSeddUkl" +
+ "k1ufZyOOcskeInQge7jzaRfmKg3U94r+spMEvb0AzDQVOKvjjo1ivxMSgFRZaDb/4qw=";
+
+ /**
+ * Defines the keystore contents for the client, JKS version. Holds just a
+ * single self-generated key. The subject name is "Test Client".
+ */
+ private static final String CLIENT_KEYS_JKS =
+ "/u3+7QAAAAIAAAABAAAAAQAFbXlrZXkAAAEaWFhyMAAAArkwggK1MA4GCisGAQQBKgIRAQEFAASC" +
+ "AqGVSfXolBStZy4nnRNn4fAr+S7kfU2BS23wwW8uB2Ru3GvtLzlK9q08Gvq/LNqBafjyFTVL5FV5" +
+ "SED/8YomO5a98GpskSeRvytCiTBLJdgGhws5TOGekgIAcBROPGIyOtJPQ0HfOQs+BqgzGDHzHQhw" +
+ "u/8Tm6yQwiP+W/1I9B1QnaEztZA3mhTyMMJsmsFTYroGgAog885D5Cmzd8sYGfxec3R6I+xcmBAY" +
+ "eibR5kGpWwt1R+qMvRrtBqh5r6WSKhCBNax+SJVbtUNRiKyjKccdJg6fGqIWWeivwYTy0OhjA6b4" +
+ "NiZ/ZZs5pxFGWUj/Rlp0RYy8fCF6aw5/5s4Bf4MI6dPSqMG8Hf7sJR91GbcELyzPdM0h5lNavgit" +
+ "QPEzKeuDrGxhY1frJThBsNsS0gxeu+OgfJPEb/H4lpYX5IvuIGbWKcxoO9zq4/fimIZkdA8A+3eY" +
+ "mfDaowvy65NBVQPJSxaOyFhLHfeLqOeCsVENAea02vA7andZHTZehvcrqyKtm+z8ncHGRC2H9H8O" +
+ "jKwKHfxxrYY/jMAKLl00+PBb3kspO+BHI2EcQnQuMw/zr83OR9Meq4TJ0TMuNkApZELAeFckIBbS" +
+ "rBr8NNjAIfjuCTuKHhsTFWiHfk9ZIzigxXagfeDRiyVc6khOuF/bGorj23N2o7Rf3uLoU6PyXWi4" +
+ "uhctR1aL6NzxDoK2PbYCeA9hxbDv8emaVPIzlVwpPK3Ruvv9mkjcOhZ74J8bPK2fQmbplbOljcZi" +
+ "tZijOfzcO/11JrwhuJZRA6wanTqHoujgChV9EukVrmbWGGAcewFnAsSbFXIik7/+QznXaDIt5NgL" +
+ "H/Bcz4Z/fdV7Ae1eUaxKXdPbI//4J+8liVT/d8awjW2tldIaDlmGMR3aoc830+3mAAAAAQAFWC41" +
+ "MDkAAAJIMIICRDCCAa0CBEhHxLgwDQYJKoZIhvcNAQEEBQAwaTELMAkGA1UEBhMCVVMxEzARBgNV" +
+ "BAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01UVjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdB" +
+ "bmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVudDAeFw0wODA2MDUxMDQ5MjhaFw0wODA5MDMxMDQ5" +
+ "MjhaMGkxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQwwCgYDVQQHEwNNVFYxDzAN" +
+ "BgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEUMBIGA1UEAxMLVGVzdCBDbGllbnQwgZ8w" +
+ "DQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAIK3Q+KiFbmCGg422TAo4gggdhMH6FJhiuz8DxRyeMKR" +
+ "UAfP4MK0wtc8N42waZ6OKvxpBFUy0BRfBsX0GD4Ku99yu9/tavSigTraeJtwV3WWRRjIqk7L3wX5" +
+ "cmgS2KSD43Y0rNUKrko26lnt9N4qiYRBSj+tcAN3Lx9+ptqk1LApAgMBAAEwDQYJKoZIhvcNAQEE" +
+ "BQADgYEANb7Q1GVSuy1RPJ0FmiXoMYCCtvlRLkmJphwxovK0cAQK12Vll+yAzBhHiQHy/RA11mng" +
+ "wYudC7u3P8X/tBT8GR1Yk7QW3KgFyPafp3lQBBCraSsfrjKj+dCLig1uBLUr4f68W8VFWZWWTHqp" +
+ "NMGpCX6qmjbkJQLVK/Yfo1ePaUexPSOX0G9m8+DoV3iyNw6at01NRw==";
+
+ /**
+ * Defines the keystore contents for the client, BKS version. Holds just a
+ * single self-generated key. The subject name is "Test Client".
+ */
+ private static final String CLIENT_KEYS_BKS =
+ "AAAAAQAAABT4Rka6fxbFps98Y5k2VilmbibNkQAABfQEAAVteWtleQAAARpYl+POAAAAAQAFWC41" +
+ "MDkAAAJNMIICSTCCAbKgAwIBAgIESEfU9TANBgkqhkiG9w0BAQUFADBpMQswCQYDVQQGEwJVUzET" +
+ "MBEGA1UECBMKQ2FsaWZvcm5pYTEMMAoGA1UEBxMDTVRWMQ8wDQYDVQQKEwZHb29nbGUxEDAOBgNV" +
+ "BAsTB0FuZHJvaWQxFDASBgNVBAMTC1Rlc3QgQ2xpZW50MB4XDTA4MDYwNTExNTg0NVoXDTA4MDkw" +
+ "MzExNTg0NVowaTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExDDAKBgNVBAcTA01U" +
+ "VjEPMA0GA1UEChMGR29vZ2xlMRAwDgYDVQQLEwdBbmRyb2lkMRQwEgYDVQQDEwtUZXN0IENsaWVu" +
+ "dDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEApUvmWsQDHPpbDKK13Yez2/q54tTOmRml/qva" +
+ "2K6dZjkjSTW0iRuk7ztaVEvdJpfVIDv1oBsCI51ttyLHROy1epjF+GoL74mJb7fkcd0VOoSOTjtD" +
+ "+3GgZkHPAm5YmUYxiJXqxKKJJqMCTIW46eJaA2nAep9QIwZ14/NFAs4ObV8CAwEAATANBgkqhkiG" +
+ "9w0BAQUFAAOBgQCJrCr3hZQFDlLIfsSKI1/w+BLvyf4fubOid0pBxfklR8KBNPTiqjSmu7pd/C/F" +
+ "1FR8CdZUDoPflZHCOU+fj5r5KUC1HyigY/tEUvlforBpfB0uCF+tXW4DbUfOWhfMtLV4nCOJOOZg" +
+ "awfZLJWBJouLKOp427vDftxTSB+Ks8YjlgAAAqwAAAAU+NH6TtrzjyDdCXm5B6Vo7xX5G4YAAAZx" +
+ "EAUkcZtmykn7YdaYxC1jRFJ+GEJpC8nZVg83QClVuCSIS8a5f8Hl44Bk4oepOZsPzhtz3RdVzDVi" +
+ "RFfoyZFsrk9F5bDTVJ6sQbb/1nfJkLhZFXokka0vND5AXMSoD5Bj1Fqem3cK7fSUyqKvFoRKC3XD" +
+ "FQvhqoam29F1rbl8FaYdPvhhZo8TfZQYUyUKwW+RbR44M5iHPx+ykieMe/C/4bcM3z8cwIbYI1aO" +
+ "gjQKS2MK9bs17xaDzeAh4sBKrskFGrDe+2dgvrSKdoakJhLTNTBSG6m+rzqMSCeQpafLKMSjTSSz" +
+ "+KoQ9bLyax8cbvViGGju0SlVhquloZmKOfHr8TukIoV64h3uCGFOVFtQjCYDOq6NbfRvMh14UVF5" +
+ "zgDIGczoD9dMoULWxBmniGSntoNgZM+QP6Id7DBasZGKfrHIAw3lHBqcvB5smemSu7F4itRoa3D8" +
+ "N7hhUEKAc+xA+8NKmXfiCBoHfPHTwDvt4IR7gWjeP3Xv5vitcKQ/MAfO5RwfzkYCXQ3FfjfzmsE1" +
+ "1IfLRDiBj+lhQSulhRVStKI88Che3M4JUNGKllrc0nt1pWa1vgzmUhhC4LSdm6trTHgyJnB6OcS9" +
+ "t2furYjK88j1AuB4921oxMxRm8c4Crq8Pyuf+n3YKi8Pl2BzBtw++0gj0ODlgwut8SrVj66/nvIB" +
+ "jN3kLVahR8nZrEFF6vTTmyXi761pzq9yOVqI57wJGx8o3Ygox1p+pWUPl1hQR7rrhUbgK/Q5wno9" +
+ "uJk07h3IZnNxE+/IKgeMTP/H4+jmyT4mhsexJ2BFHeiKF1KT/FMcJdSi+ZK5yoNVcYuY8aZbx0Ef" +
+ "lHorCXAmLFB0W6Cz4KPP01nD9YBB4olxiK1t7m0AU9zscdivNiuUaB5OIEr+JuZ6dNw=";
+ /**
+ * Defines the password for the keystore.
+ */
+ private static final String PASSWORD = "android";
+
+ /**
+ * Implements basically a dummy TrustManager. It stores the certificate
+ * chain it sees, so it can later be queried.
+ */
+ class TestTrustManager implements X509TrustManager {
+
+ private X509Certificate[] chain;
+
+ private String authType;
+
+ public void checkClientTrusted(X509Certificate[] chain, String authType) {
+ this.chain = chain;
+ this.authType = authType;
+ }
+
+ public void checkServerTrusted(X509Certificate[] chain, String authType) {
+ this.chain = chain;
+ this.authType = authType;
+ }
+
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+
+ public X509Certificate[] getChain() {
+ return chain;
+ }
+
+ public String getAuthType() {
+ return authType;
+ }
+
+ }
+
+ /**
+ * Implements a test SSL socket server. It wait for a connection on a given
+ * port, requests client authentication (if specified), and read 256 bytes
+ * from the socket.
+ */
+ class TestServer implements Runnable {
+
+ public static final int CLIENT_AUTH_NONE = 0;
+
+ public static final int CLIENT_AUTH_WANTED = 1;
+
+ public static final int CLIENT_AUTH_NEEDED = 2;
+
+ private TestTrustManager trustManager;
+
+ private Exception exception;
+
+ private int port;
+
+ private int clientAuth;
+
+ private boolean provideKeys;
+
+ public TestServer(int port, boolean provideKeys, int clientAuth) {
+ this.port = port;
+ this.clientAuth = clientAuth;
+ this.provideKeys = provideKeys;
+
+ trustManager = new TestTrustManager();
+ }
+
+ public void run() {
+ try {
+ KeyManager[] keyManagers = provideKeys
+ ? getKeyManagers(SERVER_KEYS_BKS) : null;
+ TrustManager[] trustManagers = new TrustManager[] {
+ trustManager };
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagers, trustManagers, null);
+
+ SSLServerSocket serverSocket
+ = (SSLServerSocket) sslContext.getServerSocketFactory()
+ .createServerSocket();
+
+ if (clientAuth == CLIENT_AUTH_WANTED) {
+ serverSocket.setWantClientAuth(true);
+ } else if (clientAuth == CLIENT_AUTH_NEEDED) {
+ serverSocket.setNeedClientAuth(true);
+ } else {
+ serverSocket.setWantClientAuth(false);
+ }
+
+ serverSocket.bind(new InetSocketAddress(port));
+
+ SSLSocket clientSocket = (SSLSocket) serverSocket.accept();
+
+ InputStream stream = clientSocket.getInputStream();
+
+ for (int i = 0; i < 256; i++) {
+ int j = stream.read();
+ if (i != j) {
+ throw new RuntimeException("Error reading socket,"
+ + " expected " + i + ", got " + j);
+ }
+ }
+
+ stream.close();
+ clientSocket.close();
+ serverSocket.close();
+
+ } catch (Exception ex) {
+ exception = ex;
+ }
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+
+ public X509Certificate[] getChain() {
+ return trustManager.getChain();
+ }
+
+ }
+
+ /**
+ * Implements a test SSL socket client. It open a connection to localhost on
+ * a given port and writes 256 bytes to the socket.
+ */
+ class TestClient implements Runnable {
+
+ private TestTrustManager trustManager;
+
+ private Exception exception;
+
+ private int port;
+
+ private boolean provideKeys;
+
+ public TestClient(int port, boolean provideKeys) {
+ this.port = port;
+ this.provideKeys = provideKeys;
+
+ trustManager = new TestTrustManager();
+ }
+
+ public void run() {
+ try {
+ KeyManager[] keyManagers = provideKeys
+ ? getKeyManagers(CLIENT_KEYS_BKS) : null;
+ TrustManager[] trustManagers = new TrustManager[] {
+ trustManager };
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(keyManagers, trustManagers, null);
+
+ SSLSocket socket = (SSLSocket) sslContext.getSocketFactory()
+ .createSocket();
+
+ socket.connect(new InetSocketAddress(port));
+ socket.startHandshake();
+
+ OutputStream stream = socket.getOutputStream();
+
+ for (int i = 0; i < 256; i++) {
+ stream.write(i);
+ }
+
+ stream.flush();
+ stream.close();
+ socket.close();
+
+ } catch (Exception ex) {
+ exception = ex;
+ }
+ }
+
+ public Exception getException() {
+ return exception;
+ }
+
+ public X509Certificate[] getChain() {
+ return trustManager.getChain();
+ }
+
+ }
+
+ /**
+ * Loads a keystore from a base64-encoded String. Returns the KeyManager[]
+ * for the result.
+ */
+ private KeyManager[] getKeyManagers(String keys) throws Exception {
+ byte[] bytes = new Base64().decode(keys.getBytes());
+ InputStream inputStream = new ByteArrayInputStream(bytes);
+
+ KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
+ keyStore.load(inputStream, PASSWORD.toCharArray());
+ inputStream.close();
+
+ String algorithm = KeyManagerFactory.getDefaultAlgorithm();
+ KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(algorithm);
+ keyManagerFactory.init(keyStore, PASSWORD.toCharArray());
+
+ return keyManagerFactory.getKeyManagers();
+ }
+
+ /**
+ * Implements the actual test case. Launches a server and a client, requires
+ * client authentication and checks the certificates afterwards (not in the
+ * usual sense, we just make sure that we got the expected certificates,
+ * because our self-signed test certificates are not valid.)
+ */
+ public void testClientAuth() {
+ try {
+ TestServer server = new TestServer(8088, true, TestServer.CLIENT_AUTH_WANTED);
+ TestClient client = new TestClient(8088, true);
+
+ Thread serverThread = new Thread(server);
+ Thread clientThread = new Thread(client);
+
+ serverThread.start();
+ clientThread.start();
+
+ serverThread.join();
+ clientThread.join();
+
+ // The server must have completed without an exception.
+ if (server.getException() != null) {
+ throw new RuntimeException(server.getException());
+ }
+
+ // The client must have completed without an exception.
+ if (client.getException() != null) {
+ throw new RuntimeException(client.getException());
+ }
+
+ // Caution: The clientChain is the certificate chain from our
+ // client object. It contains the server certificates, of course!
+ X509Certificate[] clientChain = client.getChain();
+ assertTrue("Client cert chain must not be null", clientChain != null);
+ assertTrue("Client cert chain must not be empty", clientChain.length != 0);
+ assertEquals("CN=Test Server, OU=Android, O=Google, L=MTV, ST=California, C=US", clientChain[0].getSubjectDN().toString());
+ // Important part ------^
+
+ // Caution: The serverChain is the certificate chain from our
+ // server object. It contains the client certificates, of course!
+ X509Certificate[] serverChain = server.getChain();
+ assertTrue("Server cert chain must not be null", serverChain != null);
+ assertTrue("Server cert chain must not be empty", serverChain.length != 0);
+ assertEquals("CN=Test Client, OU=Android, O=Google, L=MTV, ST=California, C=US", serverChain[0].getSubjectDN().toString());
+ // Important part ------^
+
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+
+ // -------------------------------------------------------------------------
+ private SSLSocket handshakeSocket;
+
+ private Exception handshakeException;
+
+
+ public void testSSLHandshakeHangTimeout() {
+
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ SSLSocket socket = (SSLSocket)clientFactory.createSocket(
+ "www.heise.de", 80);
+ socket.setSoTimeout(5000);
+ socket.startHandshake();
+ socket.close();
+ } catch (Exception ex) {
+ handshakeException = ex;
+ }
+ }
+ };
+
+ thread.start();
+
+ try {
+ thread.join(10000);
+ } catch (InterruptedException ex) {
+ // Ignore.
+ }
+
+ if (handshakeException == null) {
+ fail("SSL handshake should have failed.");
+ }
+ }
+
+ public void testSSLHandshakeHangClose() {
+
+ Thread thread = new Thread() {
+ @Override
+ public void run() {
+ try {
+ handshakeSocket = (SSLSocket)clientFactory.createSocket(
+ "www.heise.de", 80);
+ handshakeSocket.startHandshake();
+ } catch (Exception ex) {
+ handshakeException = ex;
+ }
+ }
+ };
+
+ thread.start();
+
+
+ try {
+ Thread.sleep(5000);
+ try {
+ handshakeSocket.close();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ thread.join(5000);
+ } catch (InterruptedException ex) {
+ // Ignore.
+ }
+
+ if (handshakeException == null) {
+ fail("SSL handshake should have failed.");
+ }
+ }
+
+ /**
+ * Tests our in-memory and persistent caching support.
+ */
+ public void testClientSessionCaching() throws IOException,
+ KeyManagementException {
+ SSLContextImpl context = new SSLContextImpl();
+
+ // Cache size = 2.
+ FakeClientSessionCache fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(2);
+ makeRequests(socketFactory);
+ List<String> smallCacheOps = Arrays.asList(
+ "get www.fortify.net",
+ "put www.fortify.net",
+ "get www.paypal.com",
+ "put www.paypal.com",
+ "get www.yellownet.ch",
+ "put www.yellownet.ch",
+
+ // At this point, all in-memory cache requests should miss,
+ // but the sessions will still be in the persistent cache.
+ "get www.fortify.net",
+ "get www.paypal.com",
+ "get www.yellownet.ch"
+ );
+ assertEquals(smallCacheOps, fakeCache.ops);
+
+ // Cache size = 3.
+ fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(3);
+ makeRequests(socketFactory);
+ List<String> bigCacheOps = Arrays.asList(
+ "get www.fortify.net",
+ "put www.fortify.net",
+ "get www.paypal.com",
+ "put www.paypal.com",
+ "get www.yellownet.ch",
+ "put www.yellownet.ch"
+
+ // At this point, all results should be in the in-memory
+ // cache, and the persistent cache shouldn't be hit anymore.
+ );
+ assertEquals(bigCacheOps, fakeCache.ops);
+
+ // Cache size = 4.
+ fakeCache = new FakeClientSessionCache();
+ context.engineInit(null, null, null, fakeCache, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(4);
+ makeRequests(socketFactory);
+ assertEquals(bigCacheOps, fakeCache.ops);
+ }
+
+ /**
+ * Executes sequence of requests twice using given socket factory.
+ */
+ private void makeRequests(SSLSocketFactory socketFactory)
+ throws IOException {
+ for (int i = 0; i < 2; i++) {
+ fetch(socketFactory, "www.fortify.net", 443, true, "/sslcheck.html",
+ 1, 1, 0, 60);
+ fetch(socketFactory, "www.paypal.com", 443, true, "/",
+ 1, 1, 0, 60);
+ fetch(socketFactory, "www.yellownet.ch", 443, true, "/",
+ 1, 1, 0, 60);
+ }
+ }
+
+ /**
+ * Fake in the sense that it doesn't actually persist anything.
+ */
+ static class FakeClientSessionCache implements SSLClientSessionCache {
+
+ List<String> ops = new ArrayList<String>();
+ Map<String, byte[]> sessions = new HashMap<String, byte[]>();
+
+ public byte[] getSessionData(String host, int port) {
+ ops.add("get " + host);
+ return sessions.get(host);
+ }
+
+ public void putSessionData(SSLSession session, byte[] sessionData) {
+ String host = session.getPeerHost();
+ System.err.println("length: " + sessionData.length);
+ ops.add("put " + host);
+ sessions.put(host, sessionData);
+ }
+ }
+
+ public void testFileBasedClientSessionCache() throws IOException,
+ KeyManagementException {
+ SSLContextImpl context = new SSLContextImpl();
+ String tmpDir = System.getProperty("java.io.tmpdir");
+ if (tmpDir == null) {
+ fail("Please set 'java.io.tmpdir' system property.");
+ }
+ File cacheDir = new File(tmpDir
+ + "/" + SSLSocketTest.class.getName() + "/cache");
+ deleteDir(cacheDir);
+ SSLClientSessionCache fileCache
+ = FileClientSessionCache.usingDirectory(cacheDir);
+ try {
+ ClientSessionCacheProxy cacheProxy
+ = new ClientSessionCacheProxy(fileCache);
+ context.engineInit(null, null, null, cacheProxy, null);
+ SSLSocketFactory socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(1);
+ makeRequests(socketFactory);
+ List<String> expected = Arrays.asList(
+ "unsuccessful get www.fortify.net",
+ "put www.fortify.net",
+ "unsuccessful get www.paypal.com",
+ "put www.paypal.com",
+ "unsuccessful get www.yellownet.ch",
+ "put www.yellownet.ch",
+
+ // At this point, all in-memory cache requests should miss,
+ // but the sessions will still be in the persistent cache.
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch"
+ );
+ assertEquals(expected, cacheProxy.ops);
+
+ // Try again now that file-based cache is populated.
+ fileCache = FileClientSessionCache.usingDirectory(cacheDir);
+ cacheProxy = new ClientSessionCacheProxy(fileCache);
+ context.engineInit(null, null, null, cacheProxy, null);
+ socketFactory = context.engineGetSocketFactory();
+ context.engineGetClientSessionContext().setSessionCacheSize(1);
+ makeRequests(socketFactory);
+ expected = Arrays.asList(
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch",
+ "successful get www.fortify.net",
+ "successful get www.paypal.com",
+ "successful get www.yellownet.ch"
+ );
+ assertEquals(expected, cacheProxy.ops);
+ } finally {
+ deleteDir(cacheDir);
+ }
+ }
+
+ private static void deleteDir(File directory) {
+ if (!directory.exists()) {
+ return;
+ }
+ for (File file : directory.listFiles()) {
+ file.delete();
+ }
+ directory.delete();
+ }
+
+ static class ClientSessionCacheProxy implements SSLClientSessionCache {
+
+ final SSLClientSessionCache delegate;
+ final List<String> ops = new ArrayList<String>();
+
+ ClientSessionCacheProxy(SSLClientSessionCache delegate) {
+ this.delegate = delegate;
+ }
+
+ public byte[] getSessionData(String host, int port) {
+ byte[] sessionData = delegate.getSessionData(host, port);
+ ops.add((sessionData == null ? "unsuccessful" : "successful")
+ + " get " + host);
+ return sessionData;
+ }
+
+ public void putSessionData(SSLSession session, byte[] sessionData) {
+ delegate.putSessionData(session, sessionData);
+ ops.add("put " + session.getPeerHost());
+ }
+ }
+
+ public static void main(String[] args) throws KeyManagementException, IOException {
+ new SSLSocketTest().testFileBasedClientSessionCache();
+ }
+}
diff --git a/tests/CoreTests/android/core/Sha1Test.java b/tests/CoreTests/android/core/Sha1Test.java
new file mode 100644
index 0000000..dcd4c04
--- /dev/null
+++ b/tests/CoreTests/android/core/Sha1Test.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.security.MessageDigest;
+import android.test.suitebuilder.annotation.SmallTest;
+import junit.framework.TestCase;
+
+/**
+ * Tests SHA1 message digest algorithm.
+ */
+public class Sha1Test extends TestCase {
+ class TestData {
+ private String input;
+ private String result;
+
+ public TestData(String i, String r) {
+ input = i;
+ result = r;
+ }
+ }
+
+ TestData[] mTestData = new TestData[]{
+ new TestData("abc", "a9993e364706816aba3e25717850c26c9cd0d89d"),
+ new TestData("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ "84983e441c3bd26ebaae4aa1f95129e5e54670f1")
+ };
+
+ @SmallTest
+ public void testSha1() throws Exception {
+ MessageDigest digest = MessageDigest.getInstance("SHA-1");
+
+ int numTests = mTestData.length;
+ for (int i = 0; i < numTests; i++) {
+ digest.update(mTestData[i].input.getBytes());
+ byte[] hash = digest.digest();
+ String encodedHash = encodeHex(hash);
+ assertEquals(encodedHash, mTestData[i].result);
+ }
+ }
+
+ private static String encodeHex(byte[] bytes) {
+ StringBuffer hex = new StringBuffer(bytes.length * 2);
+
+ for (int i = 0; i < bytes.length; i++) {
+ if (((int) bytes[i] & 0xff) < 0x10) {
+ hex.append("0");
+ }
+ hex.append(Integer.toString((int) bytes[i] & 0xff, 16));
+ }
+
+ return hex.toString();
+ }
+}
+
diff --git a/tests/CoreTests/android/core/SocketTest.java b/tests/CoreTests/android/core/SocketTest.java
new file mode 100644
index 0000000..b64c156
--- /dev/null
+++ b/tests/CoreTests/android/core/SocketTest.java
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.SocketException;
+import java.net.SocketTimeoutException;
+import java.nio.channels.SocketChannel;
+import java.util.concurrent.Semaphore;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Regression tests for various socket related problems. And a few general
+ * socket tests.
+ */
+public class SocketTest extends TestCase {
+
+ private static final String NON_EXISTING_ADDRESS = "123.123.123.123";
+
+ private static final String KNOW_GOOD_ADDRESS = "209.85.129.147";
+
+ private static final String PACKAGE_DROPPING_ADDRESS = "191.167.0.1";
+
+ // Test for basic bind/connect/accept behavior.
+ @SmallTest
+ public void testSocketSimple() throws Exception {
+ ServerSocket ss;
+ Socket s, s1;
+ int port;
+
+ IOException lastEx = null;
+
+ ss = new ServerSocket();
+
+ for (port = 9900; port < 9999; port++) {
+ try {
+ ss.bind(new InetSocketAddress("127.0.0.1", port));
+ lastEx = null;
+ break;
+ } catch (IOException ex) {
+ lastEx = ex;
+ }
+ }
+
+ if (lastEx != null) {
+ throw lastEx;
+ }
+
+ s = new Socket("127.0.0.1", port);
+
+ s1 = ss.accept();
+
+ s.getOutputStream().write(0xa5);
+
+ assertEquals(0xa5, s1.getInputStream().read());
+
+ s1.getOutputStream().write(0x5a);
+ assertEquals(0x5a, s.getInputStream().read());
+ }
+
+ // Regression test for #820068: Wildcard address
+ @SmallTest
+ public void testWildcardAddress() throws Exception {
+ Socket s2 = new Socket();
+ s2.bind(new InetSocketAddress((InetAddress) null, 12345));
+ byte[] addr = s2.getLocalAddress().getAddress();
+ for (int i = 0; i < 4; i++) {
+ assertEquals("Not the wildcard address", 0, addr[i]);
+ }
+ }
+
+ // Regression test for #865753: server sockets not closing properly
+ @SmallTest
+ public void testServerSocketClose() throws Exception {
+ ServerSocket s3 = new ServerSocket(23456);
+ s3.close();
+ ServerSocket s4 = new ServerSocket(23456);
+ s4.close();
+ }
+
+ // Regression test for #876985: SO_REUSEADDR not working properly
+
+ private Exception serverError = null;
+
+ @LargeTest
+ public void testSetReuseAddress() throws IOException {
+ InetSocketAddress addr = new InetSocketAddress(8383);
+
+ final ServerSocket serverSock = new ServerSocket();
+ serverSock.setReuseAddress(true);
+ serverSock.bind(addr);
+
+ final Semaphore semThreadEnd = new Semaphore(0);
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ Socket sock = serverSock.accept();
+ sock.getInputStream().read();
+ sock.close();
+ } catch (IOException e) {
+ serverError = e;
+ }
+ semThreadEnd.release();
+ }
+ }.start();
+
+ // Give the server a bit of time for startup
+ try {
+ Thread.sleep(2000);
+ } catch (InterruptedException ex) {
+ // Ignored.
+ }
+
+ Socket client = new Socket("localhost", 8383);
+ client.getOutputStream().write(1);
+ // Just leave this connection open from the client side. It will be
+ // closed from the server side so the server stays in the TIME_WAIT
+ // state for a while. setReuseAddress() should be able to handle this.
+
+ try {
+ semThreadEnd.acquire();
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ serverSock.close();
+
+ ServerSocket serverSock2 = new ServerSocket();
+ serverSock2.setReuseAddress(true);
+ serverSock2.bind(addr);
+ serverSock2.close();
+
+ if (serverError != null) {
+ throw new RuntimeException("Server must complete without error", serverError);
+ }
+ }
+
+ // Regression for 916701, a wrong exception was thrown after timeout of
+ // a ServerSocket.
+ @LargeTest
+ public void testTimeoutException() throws IOException {
+ ServerSocket s = new ServerSocket(9800);
+ s.setSoTimeout(2000);
+ try {
+ s.accept();
+ } catch (SocketTimeoutException e) {
+ // this is ok.
+ }
+ }
+
+ // Regression for issue 1001980, openening a SocketChannel threw an Exception
+ @SmallTest
+ public void testNativeSocketChannelOpen() throws IOException {
+ SocketChannel.open();
+ }
+
+ // Regression test for issue 1018016, connecting ignored a set timeout.
+ @LargeTest
+ public void testSocketSetSOTimeout() throws IOException {
+ Socket sock = new Socket();
+ int timeout = 5000;
+ long start = System.currentTimeMillis();
+ try {
+ sock.connect(new InetSocketAddress(NON_EXISTING_ADDRESS, 80), timeout);
+ } catch (SocketTimeoutException e) {
+ // expected
+ long delay = System.currentTimeMillis() - start;
+ if (Math.abs(delay - timeout) > 1000) {
+ fail("timeout was not accurate. expected: " + timeout
+ + " actual: " + delay + " miliseconds.");
+ }
+ } finally {
+ try {
+ sock.close();
+ } catch (IOException ioe) {
+ // ignore
+ }
+ }
+ }
+
+ /**
+ * Regression test for 1062928: Dotted IP addresses (e.g., 192.168.100.1)
+ * appear to be broken in the M5 SDK.
+ *
+ * Tests that a connection given a ip-addressv4 such as 192.168.100.100 does
+ * not fail - sdk m5 seems only to accept dns names instead of ip numbers.
+ * ip 209.85.129.147 (one address of www.google.com) on port 80 (http) is
+ * used to test the connection.
+ */
+
+// Commenting out this test since it is flaky, even at the best of times. See
+// #1191317 for Info.
+ @Suppress
+ public void disable_testConnectWithIP4IPAddr() {
+ // call a Google Web server
+ InetSocketAddress scktAddrss = new InetSocketAddress(KNOW_GOOD_ADDRESS,
+ 80);
+ Socket clntSckt = new Socket();
+ try {
+ clntSckt.connect(scktAddrss, 5000);
+ } catch (Throwable e) {
+ fail("connection problem:" + e.getClass().getName() + ": "
+ + e.getMessage());
+ } finally {
+ try {
+ clntSckt.close();
+ } catch (Exception e) {
+ // ignore
+ }
+ }
+ }
+
+
+ // Regression test for #1058962: Socket.close() does not cause
+ // socket.connect() to return immediately.
+ private Socket client;
+
+ private Exception error;
+
+ private boolean connected;
+
+// This test isn't working now, but really should work.
+// TODO Enable this test again.
+
+ @Suppress
+ public void disable_testSocketConnectClose() {
+ try {
+ client = new Socket();
+
+ new Thread() {
+ @Override
+ public void run() {
+ try {
+ client.connect(new InetSocketAddress(PACKAGE_DROPPING_ADDRESS, 1357));
+ } catch (Exception ex) {
+ error = ex;
+ }
+
+ connected = true;
+ }
+ }.start();
+
+ Thread.sleep(1000);
+
+ Assert.assertNull("Connect must not fail immediately. Maybe try different address.", error);
+ Assert.assertFalse("Connect must not succeed. Maybe try different address.", connected);
+
+ client.close();
+
+ Thread.sleep(1000);
+
+ if (error == null) {
+ fail("Socket connect still ongoing");
+ } else if (!(error instanceof SocketException)) {
+ fail("Socket connect interrupted with wrong error: " + error.toString());
+ }
+
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+
+ }
+
+}
diff --git a/tests/CoreTests/android/core/StreamTokenizerTest.java b/tests/CoreTests/android/core/StreamTokenizerTest.java
new file mode 100644
index 0000000..5013860
--- /dev/null
+++ b/tests/CoreTests/android/core/StreamTokenizerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.StreamTokenizer;
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Tests for the StreamTokenizer
+ */
+public class StreamTokenizerTest extends TestCase {
+
+ @MediumTest
+ public void testStreamTokenizer() throws Exception {
+ String str = "Testing 12345 \n alpha \r\n omega";
+ String strb = "-3.8 'BLIND mice' \r sEe /* how */ they run";
+ StringReader aa = new StringReader(str);
+ StringReader ba = new StringReader(strb);
+ StreamTokenizer a = new StreamTokenizer(aa);
+ StreamTokenizer b = new StreamTokenizer(ba);
+
+ assertEquals(1, a.lineno());
+ assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+ assertEquals("Token[Testing], line 1", a.toString());
+ assertEquals(StreamTokenizer.TT_NUMBER, a.nextToken());
+ assertEquals("Token[n=12345.0], line 1", a.toString());
+ assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+ assertEquals("Token[alpha], line 2", a.toString());
+ assertEquals(StreamTokenizer.TT_WORD, a.nextToken());
+ assertEquals("Token[omega], line 3", a.toString());
+ assertEquals(StreamTokenizer.TT_EOF, a.nextToken());
+ assertEquals("Token[EOF], line 3", a.toString());
+
+ b.commentChar('u');
+ b.eolIsSignificant(true);
+ b.lowerCaseMode(true);
+ b.ordinaryChar('y');
+ b.slashStarComments(true);
+
+ assertEquals(StreamTokenizer.TT_NUMBER, b.nextToken());
+ assertEquals(-3.8, b.nval);
+ assertEquals("Token[n=-3.8], line 1", b.toString());
+ assertEquals(39, b.nextToken()); // '
+ assertEquals("Token[BLIND mice], line 1", b.toString());
+ assertEquals(10, b.nextToken()); // \n
+ assertEquals("Token[EOL], line 2", b.toString());
+ assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+ assertEquals("Token[see], line 2", b.toString());
+ assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+ assertEquals("Token[the], line 2", b.toString());
+ assertEquals(121, b.nextToken()); // y
+ assertEquals("Token['y'], line 2", b.toString());
+ assertEquals(StreamTokenizer.TT_WORD, b.nextToken());
+ assertEquals("Token[r], line 2", b.toString());
+ assertEquals(StreamTokenizer.TT_EOF, b.nextToken());
+ assertEquals("Token[EOF], line 2", b.toString());
+
+ // A harmony regression test
+ byte[] data = new byte[]{(byte) '-'};
+ StreamTokenizer tokenizer = new StreamTokenizer(new ByteArrayInputStream(data));
+ tokenizer.nextToken();
+ String result = tokenizer.toString();
+ assertEquals("Token['-'], line 1", result);
+
+ // another harmony regression test
+ byte[] data2 = new byte[]{(byte) '"',
+ (byte) 'H',
+ (byte) 'e',
+ (byte) 'l',
+ (byte) 'l',
+ (byte) 'o',
+ (byte) '"'};
+ StreamTokenizer tokenizer2 = new StreamTokenizer(new ByteArrayInputStream(data2));
+ tokenizer2.nextToken();
+ result = tokenizer2.toString();
+ assertEquals("Token[Hello], line 1", result);
+ }
+}
diff --git a/tests/CoreTests/android/core/StrictMathTest.java b/tests/CoreTests/android/core/StrictMathTest.java
new file mode 100644
index 0000000..92e6cb6
--- /dev/null
+++ b/tests/CoreTests/android/core/StrictMathTest.java
@@ -0,0 +1,855 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class StrictMathTest extends TestCase {
+
+ private final double HYP = StrictMath.sqrt(2.0);
+
+ private final double OPP = 1.0;
+
+ private final double ADJ = 1.0;
+
+ /* Required to make previous preprocessor flags work - do not remove */
+ int unused = 0;
+
+ /**
+ * @tests java.lang.StrictMath#abs(double)
+ */
+ @SmallTest
+ public void testAbsD() {
+ // Test for method double java.lang.StrictMath.abs(double)
+
+ assertTrue("Incorrect double abs value",
+ (StrictMath.abs(-1908.8976) == 1908.8976));
+ assertTrue("Incorrect double abs value",
+ (StrictMath.abs(1908.8976) == 1908.8976));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#abs(float)
+ */
+ @SmallTest
+ public void testAbsF() {
+ // Test for method float java.lang.StrictMath.abs(float)
+ assertTrue("Incorrect float abs value",
+ (StrictMath.abs(-1908.8976f) == 1908.8976f));
+ assertTrue("Incorrect float abs value",
+ (StrictMath.abs(1908.8976f) == 1908.8976f));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#abs(int)
+ */
+ @SmallTest
+ public void testAbsI() {
+ // Test for method int java.lang.StrictMath.abs(int)
+ assertTrue("Incorrect int abs value",
+ (StrictMath.abs(-1908897) == 1908897));
+ assertTrue("Incorrect int abs value",
+ (StrictMath.abs(1908897) == 1908897));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#abs(long)
+ */
+ @SmallTest
+ public void testAbsJ() {
+ // Test for method long java.lang.StrictMath.abs(long)
+ assertTrue("Incorrect long abs value", (StrictMath
+ .abs(-19088976000089L) == 19088976000089L));
+ assertTrue("Incorrect long abs value",
+ (StrictMath.abs(19088976000089L) == 19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#acos(double)
+ */
+ @SmallTest
+ public void testAcosD() {
+ // Test for method double java.lang.StrictMath.acos(double)
+ assertTrue("Returned incorrect arc cosine", StrictMath.cos(StrictMath
+ .acos(ADJ / HYP)) == ADJ / HYP);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#asin(double)
+ */
+ @SmallTest
+ public void testAsinD() {
+ // Test for method double java.lang.StrictMath.asin(double)
+ assertTrue("Returned incorrect arc sine", StrictMath.sin(StrictMath
+ .asin(OPP / HYP)) == OPP / HYP);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#atan(double)
+ */
+ @SmallTest
+ public void testAtanD() {
+ // Test for method double java.lang.StrictMath.atan(double)
+ double answer = StrictMath.tan(StrictMath.atan(1.0));
+ assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+ && answer >= 9.9999999999999983E-1);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#atan2(double,double)
+ */
+ @SmallTest
+ public void testAtan2DD() {
+ // Test for method double java.lang.StrictMath.atan2(double, double)
+ double answer = StrictMath.atan(StrictMath.tan(1.0));
+ assertTrue("Returned incorrect arc tangent: " + answer, answer <= 1.0
+ && answer >= 9.9999999999999983E-1);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#cbrt(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testCbrtD() {
+ // Test for special situations
+ assertTrue("Should return Double.NaN", Double.isNaN(StrictMath
+ .cbrt(Double.NaN)));
+ assertEquals("Should return Double.POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .cbrt(Double.POSITIVE_INFINITY));
+ assertEquals("Should return Double.NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath
+ .cbrt(Double.NEGATIVE_INFINITY));
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.cbrt(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.cbrt(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.cbrt(-0.0)));
+
+ assertEquals("Should return 3.0", 3.0, StrictMath.cbrt(27.0));
+ assertEquals("Should return 23.111993172558684", 23.111993172558684,
+ StrictMath.cbrt(12345.6));
+ assertEquals("Should return 5.643803094122362E102",
+ 5.643803094122362E102, StrictMath.cbrt(Double.MAX_VALUE));
+ assertEquals("Should return 0.01", 0.01, StrictMath.cbrt(0.000001));
+
+ assertEquals("Should return -3.0", -3.0, StrictMath.cbrt(-27.0));
+ assertEquals("Should return -23.111993172558684", -23.111993172558684,
+ StrictMath.cbrt(-12345.6));
+ assertEquals("Should return 1.7031839360032603E-108",
+ 1.7031839360032603E-108, StrictMath.cbrt(Double.MIN_VALUE));
+ assertEquals("Should return -0.01", -0.01, StrictMath.cbrt(-0.000001));
+
+ try {
+ StrictMath.cbrt((Double) null);
+ fail("Should throw NullPointerException");
+ } catch (NullPointerException e) {
+ //expected
+ }
+ }
+
+ /**
+ * @tests java.lang.StrictMath#ceil(double)
+ */
+ @SmallTest
+ public void testCeilD() {
+ // Test for method double java.lang.StrictMath.ceil(double)
+ assertEquals("Incorrect ceiling for double",
+ 79, StrictMath.ceil(78.89), 0.0);
+ assertEquals("Incorrect ceiling for double",
+ -78, StrictMath.ceil(-78.89), 0.0);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#cos(double)
+ */
+ @SmallTest
+ public void testCosD() {
+ // Test for method double java.lang.StrictMath.cos(double)
+
+ assertTrue("Returned incorrect cosine", StrictMath.cos(StrictMath
+ .acos(ADJ / HYP)) == ADJ / HYP);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#cosh(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testCosh_D() {
+ // Test for special situations
+ assertTrue("Should return NaN", Double.isNaN(StrictMath
+ .cosh(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .cosh(Double.POSITIVE_INFINITY));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .cosh(Double.NEGATIVE_INFINITY));
+ assertEquals("Should return 1.0", 1.0, StrictMath.cosh(+0.0));
+ assertEquals("Should return 1.0", 1.0, StrictMath.cosh(-0.0));
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.cosh(1234.56));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.cosh(-1234.56));
+ assertEquals("Should return 1.0000000000005", 1.0000000000005,
+ StrictMath.cosh(0.000001));
+ assertEquals("Should return 1.0000000000005", 1.0000000000005,
+ StrictMath.cosh(-0.000001));
+ assertEquals("Should return 5.212214351945598", 5.212214351945598,
+ StrictMath.cosh(2.33482));
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.cosh(Double.MAX_VALUE));
+ assertEquals("Should return 1.0", 1.0, StrictMath
+ .cosh(Double.MIN_VALUE));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#exp(double)
+ */
+ @SmallTest
+ public void testExpD() {
+ // Test for method double java.lang.StrictMath.exp(double)
+ assertTrue("Incorrect answer returned for simple power", StrictMath
+ .abs(StrictMath.exp(4D) - StrictMath.E * StrictMath.E
+ * StrictMath.E * StrictMath.E) < 0.1D);
+ assertTrue("Incorrect answer returned for larger power", StrictMath
+ .log(StrictMath.abs(StrictMath.exp(5.5D)) - 5.5D) < 10.0D);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#expm1(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testExpm1D() {
+ //Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(StrictMath.expm1(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.expm1(Double.POSITIVE_INFINITY));
+ assertEquals("Should return -1.0", -1.0, StrictMath
+ .expm1(Double.NEGATIVE_INFINITY));
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.expm1(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.expm1(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.expm1(-0.0)));
+
+ assertEquals("Should return -9.999950000166666E-6",
+ -9.999950000166666E-6, StrictMath.expm1(-0.00001));
+ assertEquals("Should return 1.0145103074469635E60",
+ 1.0145103074469635E60, StrictMath.expm1(138.16951162));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .expm1(123456789123456789123456789.4521584223));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.expm1(Double.MAX_VALUE));
+ assertEquals("Should return MIN_VALUE", Double.MIN_VALUE, StrictMath
+ .expm1(Double.MIN_VALUE));
+
+ }
+
+ /**
+ * @tests java.lang.StrictMath#floor(double)
+ */
+ @SmallTest
+ public void testFloorD() {
+ // Test for method double java.lang.StrictMath.floor(double)
+ assertEquals("Incorrect floor for double",
+ 78, StrictMath.floor(78.89), 0.0);
+ assertEquals("Incorrect floor for double",
+ -79, StrictMath.floor(-78.89), 0.0);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#hypot(double,double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testHypotDD() {
+ // Test for special cases
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY,
+ 1.0));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY,
+ 123.324));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(-758.2587,
+ Double.POSITIVE_INFINITY));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(5687.21,
+ Double.NEGATIVE_INFINITY));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(Double.POSITIVE_INFINITY,
+ Double.NEGATIVE_INFINITY));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.hypot(Double.NEGATIVE_INFINITY,
+ Double.POSITIVE_INFINITY));
+ assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(Double.NaN,
+ 2342301.89843)));
+ assertTrue("Should return NaN", Double.isNaN(StrictMath.hypot(-345.2680,
+ Double.NaN)));
+
+ assertEquals("Should return 2396424.905416697", 2396424.905416697, StrictMath
+ .hypot(12322.12, -2396393.2258));
+ assertEquals("Should return 138.16958070558556", 138.16958070558556,
+ StrictMath.hypot(-138.16951162, 0.13817035864));
+ assertEquals("Should return 1.7976931348623157E308",
+ 1.7976931348623157E308, StrictMath.hypot(Double.MAX_VALUE, 211370.35));
+ assertEquals("Should return 5413.7185", 5413.7185, StrictMath.hypot(
+ -5413.7185, Double.MIN_VALUE));
+
+ }
+
+ /**
+ * @tests java.lang.StrictMath#IEEEremainder(double,double)
+ */
+ @SmallTest
+ public void testIEEEremainderDD() {
+ // Test for method double java.lang.StrictMath.IEEEremainder(double,
+ // double)
+ assertEquals("Incorrect remainder returned", 0.0, StrictMath.IEEEremainder(
+ 1.0, 1.0), 0.0);
+ assertTrue(
+ "Incorrect remainder returned",
+ StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631647E-2
+ || StrictMath.IEEEremainder(1.32, 89.765) >= 1.4705063220631649E-2);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#log(double)
+ */
+ @SmallTest
+ public void testLogD() {
+ // Test for method double java.lang.StrictMath.log(double)
+ for (double d = 10; d >= -10; d -= 0.5) {
+ double answer = StrictMath.log(StrictMath.exp(d));
+ assertTrue("Answer does not equal expected answer for d = " + d
+ + " answer = " + answer,
+ StrictMath.abs(answer - d) <= StrictMath
+ .abs(d * 0.00000001));
+ }
+ }
+
+ /**
+ * @tests java.lang.StrictMath#log10(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testLog10D() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(StrictMath
+ .log10(Double.NaN)));
+ assertTrue("Should return NaN", Double.isNaN(StrictMath
+ .log10(-2541.05745687234187532)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .log10(Double.POSITIVE_INFINITY));
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath.log10(0.0));
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath.log10(+0.0));
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath.log10(-0.0));
+ assertEquals("Should return 14.0", 14.0, StrictMath.log10(StrictMath
+ .pow(10, 14)));
+
+ assertEquals("Should return 3.7389561269540406", 3.7389561269540406,
+ StrictMath.log10(5482.2158));
+ assertEquals("Should return 14.661551142893833", 14.661551142893833,
+ StrictMath.log10(458723662312872.125782332587));
+ assertEquals("Should return -0.9083828622192334", -0.9083828622192334,
+ StrictMath.log10(0.12348583358871));
+ assertEquals("Should return 308.25471555991675", 308.25471555991675,
+ StrictMath.log10(Double.MAX_VALUE));
+ assertEquals("Should return -323.3062153431158", -323.3062153431158,
+ StrictMath.log10(Double.MIN_VALUE));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#log1p(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testLog1pD() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double.isNaN(StrictMath
+ .log1p(Double.NaN)));
+ assertTrue("Should return NaN", Double.isNaN(StrictMath
+ .log1p(-32.0482175)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .log1p(Double.POSITIVE_INFINITY));
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.log1p(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.log1p(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.log1p(-0.0)));
+
+ assertEquals("Should return -0.2941782295312541", -0.2941782295312541,
+ StrictMath.log1p(-0.254856327));
+ assertEquals("Should return 7.368050685564151", 7.368050685564151,
+ StrictMath.log1p(1583.542));
+ assertEquals("Should return 0.4633708685409921", 0.4633708685409921,
+ StrictMath.log1p(0.5894227));
+ assertEquals("Should return 709.782712893384", 709.782712893384,
+ StrictMath.log1p(Double.MAX_VALUE));
+ assertEquals("Should return Double.MIN_VALUE", Double.MIN_VALUE,
+ StrictMath.log1p(Double.MIN_VALUE));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#max(double,double)
+ */
+ @SmallTest
+ public void testMaxDD() {
+ // Test for method double java.lang.StrictMath.max(double, double)
+ assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(
+ -1908897.6000089, 1908897.6000089), 0D);
+ assertEquals("Incorrect double max value", 1908897.6000089, StrictMath.max(2.0,
+ 1908897.6000089), 0D);
+ assertEquals("Incorrect double max value", -2.0, StrictMath.max(-2.0,
+ -1908897.6000089), 0D);
+
+ }
+
+ /**
+ * @tests java.lang.StrictMath#max(float,float)
+ */
+ @SmallTest
+ public void testMaxFF() {
+ // Test for method float java.lang.StrictMath.max(float, float)
+ assertTrue("Incorrect float max value", StrictMath.max(-1908897.600f,
+ 1908897.600f) == 1908897.600f);
+ assertTrue("Incorrect float max value", StrictMath.max(2.0f,
+ 1908897.600f) == 1908897.600f);
+ assertTrue("Incorrect float max value", StrictMath.max(-2.0f,
+ -1908897.600f) == -2.0f);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#max(int,int)
+ */
+ @SmallTest
+ public void testMaxII() {
+ // Test for method int java.lang.StrictMath.max(int, int)
+ assertEquals("Incorrect int max value", 19088976, StrictMath.max(-19088976,
+ 19088976));
+ assertEquals("Incorrect int max value",
+ 19088976, StrictMath.max(20, 19088976));
+ assertEquals("Incorrect int max value",
+ -20, StrictMath.max(-20, -19088976));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#max(long,long)
+ */
+ @SmallTest
+ public void testMaxJJ() {
+ // Test for method long java.lang.StrictMath.max(long, long)
+ assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(-19088976000089L,
+ 19088976000089L));
+ assertEquals("Incorrect long max value", 19088976000089L, StrictMath.max(20,
+ 19088976000089L));
+ assertEquals("Incorrect long max value", -20, StrictMath.max(-20,
+ -19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#min(double,double)
+ */
+ @SmallTest
+ public void testMinDD() {
+ // Test for method double java.lang.StrictMath.min(double, double)
+ assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(
+ -1908897.6000089, 1908897.6000089), 0D);
+ assertEquals("Incorrect double min value", 2.0, StrictMath.min(2.0,
+ 1908897.6000089), 0D);
+ assertEquals("Incorrect double min value", -1908897.6000089, StrictMath.min(-2.0,
+ -1908897.6000089), 0D);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#min(float,float)
+ */
+ @SmallTest
+ public void testMinFF() {
+ // Test for method float java.lang.StrictMath.min(float, float)
+ assertTrue("Incorrect float min value", StrictMath.min(-1908897.600f,
+ 1908897.600f) == -1908897.600f);
+ assertTrue("Incorrect float min value", StrictMath.min(2.0f,
+ 1908897.600f) == 2.0f);
+ assertTrue("Incorrect float min value", StrictMath.min(-2.0f,
+ -1908897.600f) == -1908897.600f);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#min(int,int)
+ */
+ @SmallTest
+ public void testMinII() {
+ // Test for method int java.lang.StrictMath.min(int, int)
+ assertEquals("Incorrect int min value", -19088976, StrictMath.min(-19088976,
+ 19088976));
+ assertEquals("Incorrect int min value",
+ 20, StrictMath.min(20, 19088976));
+ assertEquals("Incorrect int min value",
+ -19088976, StrictMath.min(-20, -19088976));
+
+ }
+
+ /**
+ * @tests java.lang.StrictMath#min(long,long)
+ */
+ @SmallTest
+ public void testMinJJ() {
+ // Test for method long java.lang.StrictMath.min(long, long)
+ assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-19088976000089L,
+ 19088976000089L));
+ assertEquals("Incorrect long min value", 20, StrictMath.min(20,
+ 19088976000089L));
+ assertEquals("Incorrect long min value", -19088976000089L, StrictMath.min(-20,
+ -19088976000089L));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#pow(double,double)
+ */
+ @SmallTest
+ public void testPowDD() {
+ // Test for method double java.lang.StrictMath.pow(double, double)
+ assertTrue("pow returned incorrect value",
+ (long) StrictMath.pow(2, 8) == 256l);
+ assertTrue("pow returned incorrect value",
+ StrictMath.pow(2, -8) == 0.00390625d);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#rint(double)
+ */
+ @SmallTest
+ public void testRintD() {
+ // Test for method double java.lang.StrictMath.rint(double)
+ assertEquals("Failed to round properly - up to odd",
+ 3.0, StrictMath.rint(2.9), 0D);
+ assertTrue("Failed to round properly - NaN", Double.isNaN(StrictMath
+ .rint(Double.NaN)));
+ assertEquals("Failed to round properly down to even", 2.0, StrictMath
+ .rint(2.1), 0D);
+ assertTrue("Failed to round properly " + 2.5 + " to even", StrictMath
+ .rint(2.5) == 2.0);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#round(double)
+ */
+ @SmallTest
+ public void testRoundD() {
+ // Test for method long java.lang.StrictMath.round(double)
+ assertEquals("Incorrect rounding of a float",
+ -91, StrictMath.round(-90.89d));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#round(float)
+ */
+ @SmallTest
+ public void testRoundF() {
+ // Test for method int java.lang.StrictMath.round(float)
+ assertEquals("Incorrect rounding of a float",
+ -91, StrictMath.round(-90.89f));
+ }
+
+ /**
+ * @tests java.lang.StrictMath#signum(double)
+ */
+ @SmallTest
+ public void testSignumD() {
+ assertTrue(Double.isNaN(StrictMath.signum(Double.NaN)));
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.signum(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.signum(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.signum(-0.0)));
+
+ assertEquals(1.0, StrictMath.signum(253681.2187962), 0D);
+ assertEquals(-1.0, StrictMath.signum(-125874693.56), 0D);
+ assertEquals(1.0, StrictMath.signum(1.2587E-308), 0D);
+ assertEquals(-1.0, StrictMath.signum(-1.2587E-308), 0D);
+
+ assertEquals(1.0, StrictMath.signum(Double.MAX_VALUE), 0D);
+ assertEquals(1.0, StrictMath.signum(Double.MIN_VALUE), 0D);
+ assertEquals(-1.0, StrictMath.signum(-Double.MAX_VALUE), 0D);
+ assertEquals(-1.0, StrictMath.signum(-Double.MIN_VALUE), 0D);
+ assertEquals(1.0, StrictMath.signum(Double.POSITIVE_INFINITY), 0D);
+ assertEquals(-1.0, StrictMath.signum(Double.NEGATIVE_INFINITY), 0D);
+
+ }
+
+ /**
+ * @tests java.lang.StrictMath#signum(float)
+ */
+ @SmallTest
+ public void testSignumF() {
+ assertTrue(Float.isNaN(StrictMath.signum(Float.NaN)));
+ assertEquals(Float.floatToIntBits(0.0f), Float
+ .floatToIntBits(StrictMath.signum(0.0f)));
+ assertEquals(Float.floatToIntBits(+0.0f), Float
+ .floatToIntBits(StrictMath.signum(+0.0f)));
+ assertEquals(Float.floatToIntBits(-0.0f), Float
+ .floatToIntBits(StrictMath.signum(-0.0f)));
+
+ assertEquals(1.0f, StrictMath.signum(253681.2187962f), 0f);
+ assertEquals(-1.0f, StrictMath.signum(-125874693.56f), 0f);
+ assertEquals(1.0f, StrictMath.signum(1.2587E-11f), 0f);
+ assertEquals(-1.0f, StrictMath.signum(-1.2587E-11f), 0f);
+
+ assertEquals(1.0f, StrictMath.signum(Float.MAX_VALUE), 0f);
+ assertEquals(1.0f, StrictMath.signum(Float.MIN_VALUE), 0f);
+ assertEquals(-1.0f, StrictMath.signum(-Float.MAX_VALUE), 0f);
+ assertEquals(-1.0f, StrictMath.signum(-Float.MIN_VALUE), 0f);
+ assertEquals(1.0f, StrictMath.signum(Float.POSITIVE_INFINITY), 0f);
+ assertEquals(-1.0f, StrictMath.signum(Float.NEGATIVE_INFINITY), 0f);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#sin(double)
+ */
+ @SmallTest
+ public void testSinD() {
+ // Test for method double java.lang.StrictMath.sin(double)
+ assertTrue("Returned incorrect sine", StrictMath.sin(StrictMath
+ .asin(OPP / HYP)) == OPP / HYP);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#sinh(double)
+ */
+ @SmallTest
+ public void testSinhD() {
+ // Test for special situations
+ assertTrue(Double.isNaN(StrictMath.sinh(Double.NaN)));
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath
+ .sinh(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath
+ .sinh(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.sinh(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.sinh(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.sinh(-0.0)));
+
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.sinh(1234.56), 0D);
+ assertEquals("Should return NEGATIVE_INFINITY",
+ Double.NEGATIVE_INFINITY, StrictMath.sinh(-1234.56), 0D);
+ assertEquals("Should return 1.0000000000001666E-6",
+ 1.0000000000001666E-6, StrictMath.sinh(0.000001), 0D);
+ assertEquals("Should return -1.0000000000001666E-6",
+ -1.0000000000001666E-6, StrictMath.sinh(-0.000001), 0D);
+ assertEquals("Should return 5.115386441963859", 5.115386441963859,
+ StrictMath.sinh(2.33482), 0D);
+ assertEquals("Should return POSITIVE_INFINITY",
+ Double.POSITIVE_INFINITY, StrictMath.sinh(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath
+ .sinh(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#sqrt(double)
+ */
+ @SmallTest
+ public void testSqrtD() {
+ // Test for method double java.lang.StrictMath.sqrt(double)
+ assertEquals("Incorrect root returned1",
+ 2, StrictMath.sqrt(StrictMath.pow(StrictMath.sqrt(2), 4)), 0.0);
+ assertEquals("Incorrect root returned2", 7, StrictMath.sqrt(49), 0.0);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#tan(double)
+ */
+ @SmallTest
+ public void testTanD() {
+ // Test for method double java.lang.StrictMath.tan(double)
+ assertTrue(
+ "Returned incorrect tangent: ",
+ StrictMath.tan(StrictMath.atan(1.0)) <= 1.0
+ || StrictMath.tan(StrictMath.atan(1.0)) >= 9.9999999999999983E-1);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#tanh(double)
+ */
+ @SmallTest
+ public void testTanhD() {
+ // Test for special situations
+ assertTrue(Double.isNaN(StrictMath.tanh(Double.NaN)));
+ assertEquals("Should return +1.0", +1.0, StrictMath
+ .tanh(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Should return -1.0", -1.0, StrictMath
+ .tanh(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals(Double.doubleToLongBits(0.0), Double
+ .doubleToLongBits(StrictMath.tanh(0.0)));
+ assertEquals(Double.doubleToLongBits(+0.0), Double
+ .doubleToLongBits(StrictMath.tanh(+0.0)));
+ assertEquals(Double.doubleToLongBits(-0.0), Double
+ .doubleToLongBits(StrictMath.tanh(-0.0)));
+
+ assertEquals("Should return 1.0", 1.0, StrictMath.tanh(1234.56), 0D);
+ assertEquals("Should return -1.0", -1.0, StrictMath.tanh(-1234.56), 0D);
+ assertEquals("Should return 9.999999999996666E-7",
+ 9.999999999996666E-7, StrictMath.tanh(0.000001), 0D);
+ assertEquals("Should return 0.981422884124941", 0.981422884124941,
+ StrictMath.tanh(2.33482), 0D);
+ assertEquals("Should return 1.0", 1.0, StrictMath
+ .tanh(Double.MAX_VALUE), 0D);
+ assertEquals("Should return 4.9E-324", 4.9E-324, StrictMath
+ .tanh(Double.MIN_VALUE), 0D);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#random()
+ */
+ @MediumTest
+ public void testRandom() {
+ // There isn't a place for these tests so just stick them here
+ assertEquals("Wrong value E",
+ 4613303445314885481L, Double.doubleToLongBits(StrictMath.E));
+ assertEquals("Wrong value PI",
+ 4614256656552045848L, Double.doubleToLongBits(StrictMath.PI));
+
+ for (int i = 500; i >= 0; i--) {
+ double d = StrictMath.random();
+ assertTrue("Generated number is out of range: " + d, d >= 0.0
+ && d < 1.0);
+ }
+ }
+
+ /**
+ * @tests java.lang.StrictMath#toRadians(double)
+ */
+ @MediumTest
+ public void testToRadiansD() {
+ for (double d = 500; d >= 0; d -= 1.0) {
+ double converted = StrictMath.toDegrees(StrictMath.toRadians(d));
+ assertTrue("Converted number not equal to original. d = " + d,
+ converted >= d * 0.99999999 && converted <= d * 1.00000001);
+ }
+ }
+
+ /**
+ * @tests java.lang.StrictMath#toDegrees(double)
+ */
+ @MediumTest
+ public void testToDegreesD() {
+ for (double d = 500; d >= 0; d -= 1.0) {
+ double converted = StrictMath.toRadians(StrictMath.toDegrees(d));
+ assertTrue("Converted number not equal to original. d = " + d,
+ converted >= d * 0.99999999 && converted <= d * 1.00000001);
+ }
+ }
+
+ /**
+ * @tests java.lang.StrictMath#ulp(double)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testUlp_D() {
+ // Test for special cases
+ assertTrue("Should return NaN", Double
+ .isNaN(StrictMath.ulp(Double.NaN)));
+ assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+ StrictMath.ulp(Double.POSITIVE_INFINITY), 0D);
+ assertEquals("Returned incorrect value", Double.POSITIVE_INFINITY,
+ StrictMath.ulp(Double.NEGATIVE_INFINITY), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+ .ulp(0.0), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+ .ulp(+0.0), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+ .ulp(-0.0), 0D);
+ assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+ StrictMath.ulp(Double.MAX_VALUE), 0D);
+ assertEquals("Returned incorrect value", StrictMath.pow(2, 971),
+ StrictMath.ulp(-Double.MAX_VALUE), 0D);
+
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+ .ulp(Double.MIN_VALUE), 0D);
+ assertEquals("Returned incorrect value", Double.MIN_VALUE, StrictMath
+ .ulp(-Double.MIN_VALUE), 0D);
+
+ assertEquals("Returned incorrect value", 2.220446049250313E-16,
+ StrictMath.ulp(1.0), 0D);
+ assertEquals("Returned incorrect value", 2.220446049250313E-16,
+ StrictMath.ulp(-1.0), 0D);
+ assertEquals("Returned incorrect value", 2.2737367544323206E-13,
+ StrictMath.ulp(1153.0), 0D);
+ }
+
+ /**
+ * @tests java.lang.StrictMath#ulp(float)
+ */
+ @SuppressWarnings("boxing")
+ @SmallTest
+ public void testUlpF() {
+ // Test for special cases
+ assertTrue("Should return NaN", Float.isNaN(StrictMath.ulp(Float.NaN)));
+ assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+ StrictMath.ulp(Float.POSITIVE_INFINITY), 0f);
+ assertEquals("Returned incorrect value", Float.POSITIVE_INFINITY,
+ StrictMath.ulp(Float.NEGATIVE_INFINITY), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+ .ulp(0.0f), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+ .ulp(+0.0f), 0f);
+ assertEquals("Returned incorrect value", Float.MIN_VALUE, StrictMath
+ .ulp(-0.0f), 0f);
+ assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+ .ulp(Float.MAX_VALUE), 0f);
+ assertEquals("Returned incorrect value", 2.028241E31f, StrictMath
+ .ulp(-Float.MAX_VALUE), 0f);
+
+ assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+ .ulp(Float.MIN_VALUE), 0f);
+ assertEquals("Returned incorrect value", 1.4E-45f, StrictMath
+ .ulp(-Float.MIN_VALUE), 0f);
+
+ assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+ .ulp(1.0f), 0f);
+ assertEquals("Returned incorrect value", 1.1920929E-7f, StrictMath
+ .ulp(-1.0f), 0f);
+ assertEquals("Returned incorrect value", 1.2207031E-4f, StrictMath
+ .ulp(1153.0f), 0f);
+ assertEquals("Returned incorrect value", 5.6E-45f, Math
+ .ulp(9.403954E-38f), 0f);
+ }
+}
diff --git a/tests/CoreTests/android/core/StringReaderTest.java b/tests/CoreTests/android/core/StringReaderTest.java
new file mode 100644
index 0000000..66b3e81
--- /dev/null
+++ b/tests/CoreTests/android/core/StringReaderTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.StringReader;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class StringReaderTest extends TestCase {
+
+ @SmallTest
+ public void testStringReader() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+
+ StringReader a = new StringReader(str);
+ StringReader b = new StringReader(str);
+ StringReader c = new StringReader(str);
+ StringReader d = new StringReader(str);
+
+ assertEquals(str, IOUtil.read(a));
+ assertEquals("AbCdEfGhIj", IOUtil.read(b, 10));
+ assertEquals("bdfhjlnprtvxz", IOUtil.skipRead(c));
+ assertEquals("AbCdEfGdEfGhIjKlMnOpQrStUvWxYz", IOUtil.markRead(d, 3, 4));
+ }
+}
diff --git a/tests/CoreTests/android/core/StringTest.java b/tests/CoreTests/android/core/StringTest.java
new file mode 100644
index 0000000..957dd40
--- /dev/null
+++ b/tests/CoreTests/android/core/StringTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import com.ibm.icu4jni.text.RuleBasedNumberFormat;
+import com.ibm.icu4jni.text.RuleBasedNumberFormat.RBNFType;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Some String tests.
+ */
+public class StringTest extends TestCase {
+ private String germanSpelloutRule = "%alt-ones:" +
+ " -x: minus >>;" +
+ " x.x: << komma >>;" +
+ " null; eins; =%%main=;" +
+ "%%main:" +
+ " null; ein; zwei; drei; vier; f\u00fcnf; sechs; sieben; acht; neun;\n" +
+ " zehn; elf; zwu00f6lf; >>zehn;" +
+ " 20: [>>und]zwanzig;" +
+ " 30: [>>und]dreiu00dfig;" +
+ " 40: [>>und]vierzig;" +
+ " 50: [>>und]fu00fcnfzig;" +
+ " 60: [>>und]sechzig;" +
+ " 70: [>>und]siebzig;" +
+ " 80: [>>und]achtzig;" +
+ " 90: [>>und]neunzig;" +
+ " 100: hundert[>%alt-ones>];" +
+ " 200: <<hundert[>%alt-ones>];" +
+ " 1000: tausend[>%alt-ones>];" +
+ " 1100: tausendein[>%alt-ones>];" +
+ " 1200: tausend[>%alt-ones>];" +
+ " 2000: <<tausend[>%alt-ones>];";
+
+ @SmallTest
+ public void testString() throws Exception {
+ String test = "0123456789";
+ String test1 = new String("0123456789"); // different object
+ String test2 = new String("0123456780"); // different value
+ String offset = new String("xxx0123456789yyy");
+ String sub = offset.substring(3, 13);
+
+ assertEquals(test, test);
+ assertEquals(test, test1);
+ assertFalse(test.equals(test2));
+
+ assertEquals(0, test.compareTo(test1));
+ assertTrue(test1.compareTo(test2) > 0);
+ assertTrue(test2.compareTo(test1) < 0);
+
+ /* compare string with a nonzero offset, in left/right side */
+ assertEquals(0, test.compareTo(sub));
+ assertEquals(0, sub.compareTo(test));
+ assertEquals(test, sub);
+ assertEquals(sub, test);
+ /* same base, one is a substring */
+ assertFalse(offset.equals(sub));
+ assertFalse(sub.equals(offset));
+ /* wrong class */
+ assertFalse(test.equals(this));
+
+ /* null ptr - throw */
+ try {
+ test.compareTo(null);
+ fail("didn't get expected npe");
+ } catch (NullPointerException npe) {
+ // expected
+ }
+ /* null ptr - ok */
+ assertFalse(test.equals(null));
+
+ test = test.substring(1);
+ assertEquals("123456789", test);
+ assertFalse(test.equals(test1));
+
+ test = test.substring(1);
+ assertEquals("23456789", test);
+
+ test = test.substring(1);
+ assertEquals("3456789", test);
+
+ test = test.substring(1);
+ assertEquals("456789", test);
+
+ test = test.substring(3, 5);
+ assertEquals("78", test);
+
+ test = "this/is/a/path";
+ String[] strings = test.split("/");
+ assertEquals(4, strings.length);
+
+ assertEquals("this is a path", test.replaceAll("/", " "));
+ assertEquals("this is a path", test.replace("/", " "));
+
+ assertEquals(0, "abc".compareToIgnoreCase("ABC"));
+ assertTrue("abc".compareToIgnoreCase("DEF") < 0);
+ assertTrue("ABC".compareToIgnoreCase("def") < 0);
+ assertTrue("Now".compareTo("Mow") > 0);
+ assertTrue("Now".compareToIgnoreCase("Mow") > 0);
+
+ // RuleBasedNumberFormnat tests
+ RuleBasedNumberFormat format = new RuleBasedNumberFormat();
+ format.open(RBNFType.SPELLOUT);
+ String result = format.format(15);
+ assertEquals("Expected spellout format: 'fifteen' but was "
+ + result, "fifteen", result);
+ format.close();
+
+ format.open(RBNFType.DURATION);
+ result = format.format(15);
+ assertEquals("Expected spellout format: '15 sec.' but was "
+ + result, "15 sec.", result);
+ format.close();
+
+ format.open(RBNFType.ORDINAL);
+ result = format.format(15);
+ assertEquals("Expected spellout format: '15th' but was "
+ + result, "15th", result);
+ format.close();
+ format.open(germanSpelloutRule);
+
+ result = format.format(1323);
+ assertEquals("Expected spellout format: 'tausenddrei" +
+ "hundertdreiundzwanzig' but was " + result, "tausend" +
+ "dreihundertdreiundzwanzig", result);
+ int res = format.parse("tausenddreihundertdreiundzwanzig")
+ .intValue();
+ assertEquals("Expected spellout format: 'tausend" +
+ "dreihundertdreiundzwanzig' but was " + res , 1323, res);
+ format.close();
+ }
+}
+
diff --git a/tests/CoreTests/android/core/StringWriterTest.java b/tests/CoreTests/android/core/StringWriterTest.java
new file mode 100644
index 0000000..fed2221
--- /dev/null
+++ b/tests/CoreTests/android/core/StringWriterTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.StringWriter;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class StringWriterTest extends TestCase {
+
+ @SmallTest
+ public void testStringWriter() throws Exception {
+ String str = "AbCdEfGhIjKlMnOpQrStUvWxYz";
+ StringWriter a = new StringWriter(10);
+
+ a.write(str, 0, 26);
+ a.write('X');
+
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzX", a.toString());
+
+ a.write("alphabravodelta", 5, 5);
+ a.append('X');
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoX", a.toString());
+ a.append("omega");
+ assertEquals("AbCdEfGhIjKlMnOpQrStUvWxYzXbravoXomega", a.toString());
+ }
+}
diff --git a/tests/CoreTests/android/core/TestEventHandler.java b/tests/CoreTests/android/core/TestEventHandler.java
new file mode 100644
index 0000000..4cfcade
--- /dev/null
+++ b/tests/CoreTests/android/core/TestEventHandler.java
@@ -0,0 +1,811 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+import org.apache.http.protocol.HTTP;
+import android.util.Log;
+import android.util.Config;
+import android.net.http.*;
+
+/**
+ * Implements EventHandler and provides test functionality to validate
+ * responses to requests from the test server
+ */
+public class TestEventHandler implements EventHandler {
+
+ /**
+ * Status variables
+ */
+ private int majorVersion = -1;
+ private int minorVersion = -1;
+ private int responseCode = -1;
+ private String reasonPhrase;
+
+ /* List of headers received */
+ private Map<String, String> headerMap;
+
+ /* Used to sync low level delayed requests */
+ public static final Object syncObj = new Object();
+
+ /* Indicates whether the low level request testing is in operation */
+ private boolean useLowLevel = false;
+
+ /* Indicates whether responses should be automatically generated or
+ * delayed
+ */
+ private boolean delayResponse = false;
+
+ /* Test method expectation identifiers */
+ public final static int TEST_REQUEST_SENT = 0;
+ public final static int TEST_STATUS = 1;
+ public final static int TEST_HEADERS = 2;
+ public final static int TEST_LOCATION_CHANGED = 3;
+ public final static int TEST_DATA = 4;
+ public final static int TEST_ENDDATA = 5;
+ public final static int TEST_ERROR = 6;
+ public final static int TEST_SSL_CERTIFICATE_ERROR = 7;
+
+ public final static int TEST_NUM_EXPECTS = 8;
+
+ /* Expected status codes */
+ private int expectMajor = -1;
+ private int expectMinor = -1;
+ private int expectCode = -1;
+
+ /* Array indicating which event types are expected */
+ private boolean[] expects = new boolean[TEST_NUM_EXPECTS];
+
+ /* Array indicating which event types are not expected */
+ private boolean[] notExpecting = new boolean[TEST_NUM_EXPECTS];
+
+ /* Indicates which events have been received */
+ private boolean[] eventsReceived = new boolean[TEST_NUM_EXPECTS];
+
+ /* Redirection variables */
+ private String expectLocation;
+ private int expectPermanent = -1;
+
+ /* Content data expected to be received */
+ private byte[] expectData;
+ private int expectDataLength = -1;
+
+ private int expectErrorId = -1;
+
+ private int expectSslErrors = -1;
+ private SslCertificate expectCertificate;
+
+ public class TestHeader {
+ public TestHeader(String n, String v) {
+ name = n;
+ value = v;
+ }
+ public String name;
+ public String value;
+ }
+
+ private ArrayList<TestHeader> expectHeaders = new ArrayList<TestHeader>();
+
+ /* Holds failure details */
+ private StringBuffer expectDetails = new StringBuffer();
+
+ /* If we use a request handle, we retain a reference here for redirects
+ * using setupRedirect
+ */
+ private RequestHandle mRequestHandle;
+
+ /* The low level API uses this reference also for non-delayed requests */
+ private LowLevelNetRunner netRunner;
+
+ public TestEventHandler() {
+ for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+ expects[i] = false;
+ notExpecting[i] = false;
+ eventsReceived[i] = false;
+ }
+ }
+
+ /**
+ * Implementation of EventHandler method called when a request has been
+ * sent. If the test is waiting for this call, it will be signalled,
+ * otherwise this method will trigger the response to be read
+ * automatically.
+ */
+ public void requestSent() {
+ Log.v(LOGTAG, "TestEventHandler:requestSent()");
+ expects[TEST_REQUEST_SENT] = false;
+ eventsReceived[TEST_REQUEST_SENT] = true;
+ if (notExpecting[TEST_REQUEST_SENT]) {
+ expectDetails.append("Request sent event received but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ if (useLowLevel) {
+ if (delayResponse) {
+ synchronized (syncObj) {
+ syncObj.notifyAll();
+ }
+ } else {
+ // mRequest.startReadingResponse();
+ }
+ }
+ }
+
+ /**
+ * Implements the EventHandler status method called when a server status
+ * response is received.
+ * @param major_version The HTTP major version
+ * @param minor_version The HTTP minor version
+ * @param code The status code
+ * @param reason_phrase A reason phrase passed to us by the server
+ */
+ public void status(int major_version, int minor_version,
+ int code, String reason_phrase) {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler:status() major: " + major_version +
+ " minor: " + minor_version +
+ " code: " + code +
+ " reason: " + reason_phrase);
+ }
+
+ eventsReceived[TEST_STATUS] = true;
+ if (notExpecting[TEST_STATUS]) {
+ expectDetails.append("Status event received but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ majorVersion = major_version;
+ minorVersion = minor_version;
+ responseCode = code;
+ reasonPhrase = reason_phrase;
+
+ if (expectMajor != -1) {
+ if (expectMajor == major_version) {
+ expectMajor = -1;
+ } else {
+ expectDetails.append("Major version expected:"+expectMajor+
+ " got:"+major_version);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ if (expectMinor != -1) {
+ if (expectMinor == minor_version) {
+ expectMinor = -1;
+ } else {
+ expectDetails.append("Minor version expected:"+expectMinor+
+ " got:"+minor_version);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ if (expectCode != -1) {
+ if (expectCode == code) {
+ expectCode = -1;
+ } else {
+ expectDetails.append("Status code expected:"+expectCode+
+ " got:"+code);
+ expectDetails.append("\r\n");
+ }
+ }
+
+
+ if ((expectMajor == -1) && (expectMinor == -1) && (expectCode == -1)) {
+ expects[TEST_STATUS] = false;
+ } else {
+ System.out.println("MAJOR = "+expectMajor+" MINOR = "+expectMinor+
+ " CODE = "+expectCode);
+ }
+ }
+
+ /**
+ * Implements the EventHandler headers method called when a server
+ * sends header fields
+ */
+ public void headers(Headers headers) {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler:headers()");
+ }
+ expects[TEST_HEADERS] = false;
+
+ if (notExpecting[TEST_HEADERS]) {
+ expectDetails.append("Header event received but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ /* Check through headers received for matches with expected
+ * headers */
+ if (expectHeaders.isEmpty()) {
+ return;
+ }
+
+ for (int i = expectHeaders.size() - 1; i >= 0; i--) {
+ TestHeader h = expectHeaders.get(i);
+ System.out.println("Expected header name: " + h.name);
+ String s = null;
+ switch (h.name.hashCode()) {
+ case -1132779846:
+ s = Long.toString(headers.getContentLength());
+ break;
+ case 785670158:
+ s = headers.getContentType();
+ break;
+ case 2095084583:
+ s = headers.getContentEncoding();
+ break;
+ case 1901043637:
+ s = headers.getLocation();
+ break;
+ case -243037365:
+ s = headers.getWwwAuthenticate();
+ break;
+ case -301767724:
+ s = headers.getProxyAuthenticate();
+ break;
+ case -1267267485:
+ s = headers.getContentDisposition();
+ break;
+ case 1397189435:
+ s = headers.getAcceptRanges();
+ break;
+ case -1309235404:
+ s = headers.getExpires();
+ break;
+ case -208775662:
+ s = headers.getCacheControl();
+ break;
+ case 150043680:
+ s = headers.getLastModified();
+ break;
+ case 3123477:
+ s = headers.getEtag();
+ break;
+ case -775651618:
+ int ct = headers.getConnectionType();
+ if (ct == Headers.CONN_CLOSE) {
+ s = HTTP.CONN_CLOSE;
+ } else if (ct == Headers.CONN_KEEP_ALIVE) {
+ s = HTTP.CONN_KEEP_ALIVE;
+ }
+ break;
+ default:
+ s = null;
+
+ }
+ if (evaluateHeader(h, s)) {
+ expectHeaders.remove(i);
+ }
+ }
+
+ }
+
+ public boolean evaluateHeader(TestHeader h, String value) {
+ if (value == null) {
+ expects[TEST_HEADERS] = true;
+ System.out.print(" Missing! ");
+ expectDetails.append(" missing header " + h.name);
+ return false;
+ }
+ if (h.value == null) {
+ System.out.println("Expect value = null");
+ return true;
+ }
+ System.out.println("Expect value = " +
+ (h.value.toLowerCase()) + " got " +
+ value.toLowerCase());
+
+ if (!h.value.equalsIgnoreCase(value)) {
+ expectDetails.append("expect header value " + h.value +
+ " got " + value);
+ expects[TEST_HEADERS] = true;
+ return false;
+ }
+ return true;
+ }
+ /**
+ * Implements the EventHandler locationChanged method called when a server
+ * sends a redirect message
+ * @param newLocation The URL to the new server
+ * @param permanent Indicator of whether this is a permanent change
+ */
+ public void locationChanged(String newLocation, boolean permanent) {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler: locationChanged() " +
+ newLocation + " permanent " + permanent);
+ }
+
+ eventsReceived[TEST_LOCATION_CHANGED] = true;
+ if (notExpecting[TEST_LOCATION_CHANGED]) {
+ expectDetails.append("Location changed event received but "+
+ "not expected");
+ expectDetails.append("\r\n");
+ }
+
+ if (expectLocation != null) {
+ if (expectLocation.equals(newLocation)) {
+ expectLocation = null;
+ } else {
+ expectDetails.append("Location expected:"+expectLocation+
+ " got:"+newLocation);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ if (expectPermanent != -1) {
+ if (((expectPermanent == 0) && !permanent) ||
+ ((expectPermanent == 1) && permanent)){
+ expectPermanent = -1;
+ } else {
+ expectDetails.append("Location permanent expected:"+
+ expectPermanent+" got"+permanent);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ if ((expectLocation == null) && (expectPermanent == -1))
+ expects[TEST_LOCATION_CHANGED] = false;
+ }
+
+ /**
+ * Implements the EventHandler data method called when a server
+ * sends content data
+ * @param data The byte array content
+ * @param len The length of the data
+ */
+ public void data(byte[] data, int len) {
+ boolean mismatch = false;
+
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler: data() " + len + " bytes");
+ }
+
+ eventsReceived[TEST_DATA] = true;
+ if (notExpecting[TEST_DATA]) {
+ expectDetails.append("Data event received but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ Log.v(LOGTAG, new String(data, 0, len));
+
+ if (expectDataLength != -1) {
+ if (expectDataLength == len) {
+ expectDataLength = -1;
+ } else {
+ expectDetails.append("expect data length mismatch expected:"+
+ expectDataLength+" got:"+len);
+ expectDetails.append("\r\n");
+ }
+
+ /* Check data only if length is the same */
+ if ((expectDataLength == -1) && expectData != null) {
+ for (int i = 0; i < len; i++) {
+ if (expectData[i] != data[i]) {
+ mismatch = true;
+ expectDetails.append("Expect data mismatch at byte "+
+ i+" expected:"+expectData[i]+" got:"+data[i]);
+ expectDetails.append("\r\n");
+ break;
+ }
+ }
+ }
+ }
+
+ if ((expectDataLength == -1) || !mismatch)
+ expects[TEST_DATA] = false;
+ }
+
+ /**
+ * Implements the EventHandler endData method called to
+ * indicate completion or a request
+ */
+ public void endData() {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler: endData() called");
+ }
+
+ eventsReceived[TEST_ENDDATA] = true;
+ if (notExpecting[TEST_ENDDATA]) {
+ expectDetails.append("End data event received but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ expects[TEST_ENDDATA] = false;
+
+ if (useLowLevel) {
+ if (delayResponse) {
+ synchronized (syncObj) {
+ syncObj.notifyAll();
+ }
+ } else {
+ if (netRunner != null) {
+ System.out.println("TestEventHandler: endData() stopping "+
+ netRunner);
+ netRunner.decrementRunCount();
+ }
+ }
+ }
+ }
+
+ /**
+ * Implements the EventHandler certificate method called every
+ * time a resource is loaded via a secure connection
+ */
+ public void certificate(SslCertificate certificate) {}
+
+ /**
+ * Implements the EventHandler error method called when a server
+ * sends header fields
+ * @param id Status code of the error
+ * @param description Brief description of the error
+ */
+ public void error(int id, String description) {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler: error() called Id:" + id +
+ " description " + description);
+ }
+
+ eventsReceived[TEST_ERROR] = true;
+ if (notExpecting[TEST_ERROR]) {
+ expectDetails.append("Error event received but not expected");
+ expectDetails.append("\r\n");
+ }
+ if (expectErrorId != -1) {
+ if (expectErrorId == id) {
+ expectErrorId = -1;
+ } else {
+ expectDetails.append("Error Id expected:"+expectErrorId+
+ " got:"+id);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ if (expectErrorId == -1)
+ expects[TEST_ERROR] = false;
+
+ if (useLowLevel) {
+ if (delayResponse) {
+ synchronized (syncObj) {
+ syncObj.notifyAll();
+ }
+ } else {
+ if (netRunner != null) {
+ System.out.println("TestEventHandler: endData() stopping "+
+ netRunner);
+ netRunner.decrementRunCount();
+ }
+ }
+ }
+ }
+
+ /**
+ * SSL certificate error callback. Handles SSL error(s) on the way
+ * up to the user.
+ */
+ public void handleSslErrorRequest(SslError error) {
+ int primaryError = error.getPrimaryError();
+
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler: handleSslErrorRequest(): "+
+ " primary error:" + primaryError +
+ " certificate: " + error.getCertificate());
+ }
+
+ eventsReceived[TEST_SSL_CERTIFICATE_ERROR] = true;
+ if (notExpecting[TEST_SSL_CERTIFICATE_ERROR]) {
+ expectDetails.append("SSL Certificate error event received "+
+ "but not expected");
+ expectDetails.append("\r\n");
+ }
+
+ if (expectSslErrors != -1) {
+ if (expectSslErrors == primaryError) {
+ expectSslErrors = -1;
+ } else {
+ expectDetails.append("SslCertificateError id expected:"+
+ expectSslErrors+" got: " + primaryError);
+ expectDetails.append("\r\n");
+ }
+ }
+
+ // SslCertificate match here?
+
+ if (expectSslErrors == -1) // && expectSslCertificate == certificate?
+ expects[TEST_SSL_CERTIFICATE_ERROR] = false;
+ }
+
+ /**
+ * Use the low level net runner with no delayed response
+ * @param runner The LowLevelNetRunner object
+ */
+ public void setNetRunner(LowLevelNetRunner runner) {
+ setNetRunner(runner, false);
+ }
+
+ /**
+ * Use the low level net runner and specify if the response
+ * should be delayed
+ * @param runner The LowLevelNetRunner object
+ * @param delayedResponse Set to true is you will use the
+ * waitForRequestSent/waitForRequestResponse routines
+ */
+ public void setNetRunner(LowLevelNetRunner runner,
+ boolean delayedResponse) {
+ netRunner = runner;
+ useLowLevel = true;
+ delayResponse = delayedResponse;
+
+ if (!delayResponse)
+ netRunner.incrementRunCount();
+ }
+
+ /**
+ * Enable this listeners Request object to read server responses.
+ * This should only be used in conjunction with setDelayResponse(true)
+ */
+ public void waitForRequestResponse() {
+ if (!delayResponse || !useLowLevel) {
+ Log.d(LOGTAG, " Cant do this without delayReponse set ");
+ return;
+ }
+
+ //if (mRequest != null) {
+ // mRequest.startReadingResponse();
+ // }
+ /* Now wait for the response to be completed either through endData
+ * or an error
+ */
+ synchronized (syncObj) {
+ try {
+ syncObj.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ /**
+ * Enable this listeners Request object to read server responses.
+ * This should only be used in conjunction with setDelayResponse(true)
+ */
+ public void waitForRequestSent() {
+ if (!delayResponse || !useLowLevel) {
+ Log.d(LOGTAG, " Cant do this without delayReponse set ");
+ return;
+ }
+
+ /* Now wait for the response to be completed either through endData
+ * or an error
+ */
+ synchronized (syncObj) {
+ try {
+ syncObj.wait();
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+
+ /* Test expected values - these routines set the tests expectations */
+
+ public void expectRequestSent() {
+ expects[TEST_REQUEST_SENT] = true;
+ }
+
+ public void expectNoRequestSent() {
+ notExpecting[TEST_REQUEST_SENT] = true;
+ }
+
+ public void expectStatus() {
+ expects[TEST_STATUS] = true;
+ }
+
+ public void expectNoStatus() {
+ notExpecting[TEST_STATUS] = true;
+ }
+
+ public void expectStatus(int major, int minor, int code) {
+ expects[TEST_STATUS] = true;
+ expectMajor = major;
+ expectMinor = minor;
+ expectCode = code;
+ }
+
+ public void expectStatus(int code) {
+ expects[TEST_STATUS] = true;
+ expectCode = code;
+ }
+
+ public void expectHeaders() {
+ expects[TEST_HEADERS] = true;
+ }
+
+ public void expectNoHeaders() {
+ notExpecting[TEST_HEADERS] = true;
+ }
+
+ public void expectHeaderAdd(String name) {
+ expects[TEST_HEADERS] = true;
+ TestHeader h = new TestHeader(name.toLowerCase(), null);
+ expectHeaders.add(h);
+ }
+
+ public void expectHeaderAdd(String name, String value) {
+ expects[TEST_HEADERS] = true;
+ TestHeader h = new TestHeader(name.toLowerCase(), value);
+ expectHeaders.add(h);
+ }
+
+ public void expectLocationChanged() {
+ expects[TEST_LOCATION_CHANGED] = true;
+ }
+
+ public void expectNoLocationChanged() {
+ notExpecting[TEST_LOCATION_CHANGED] = true;
+ }
+
+ public void expectLocationChanged(String newLocation) {
+ expects[TEST_LOCATION_CHANGED] = true;
+ expectLocation = newLocation;
+ }
+
+ public void expectLocationChanged(String newLocation, boolean permanent) {
+ expects[TEST_LOCATION_CHANGED] = true;
+ expectLocation = newLocation;
+ expectPermanent = permanent ? 1 : 0;
+ }
+
+ public void expectData() {
+ expects[TEST_DATA] = true;
+ }
+
+ public void expectNoData() {
+ notExpecting[TEST_DATA] = true;
+ }
+
+ public void expectData(int len) {
+ expects[TEST_DATA] = true;
+ expectDataLength = len;
+ }
+
+ public void expectData(byte[] data, int len) {
+ expects[TEST_DATA] = true;
+ expectData = new byte[len];
+ expectDataLength = len;
+
+ for (int i = 0; i < len; i++) {
+ expectData[i] = data[i];
+ }
+ }
+
+ public void expectEndData() {
+ expects[TEST_ENDDATA] = true;
+ }
+
+ public void expectNoEndData() {
+ notExpecting[TEST_ENDDATA] = true;
+ }
+
+ public void expectError() {
+ expects[TEST_ERROR] = true;
+ }
+
+ public void expectNoError() {
+ notExpecting[TEST_ERROR] = true;
+ }
+
+ public void expectError(int errorId) {
+ expects[TEST_ERROR] = true;
+ expectErrorId = errorId;
+ }
+
+ public void expectSSLCertificateError() {
+ expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+ }
+
+ public void expectNoSSLCertificateError() {
+ notExpecting[TEST_SSL_CERTIFICATE_ERROR] = true;
+ }
+
+ public void expectSSLCertificateError(int errors) {
+ expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+ expectSslErrors = errors;
+ }
+
+ public void expectSSLCertificateError(SslCertificate certificate) {
+ expects[TEST_SSL_CERTIFICATE_ERROR] = true;
+ expectCertificate = certificate;
+ }
+
+ /**
+ * Test to see if current expectations match recieved information
+ * @return True is all expected results have been matched
+ */
+ public boolean expectPassed() {
+ for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+ if (expects[i] == true) {
+ return false;
+ }
+ }
+
+ for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+ if (eventsReceived[i] && notExpecting[i]) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Return message indicating expectation failures
+ */
+ public String getFailureMessage() {
+ return expectDetails.toString();
+ }
+
+ /**
+ * Reset all expectation values for re-use
+ */
+ public void resetExpects() {
+ expectMajor = -1;
+ expectMinor = -1;
+ expectCode = -1;
+ expectLocation = null;
+ expectPermanent = -1;
+ expectErrorId = -1;
+ expectSslErrors = -1;
+ expectCertificate = null;
+ expectDetails.setLength(0);
+ expectHeaders.clear();
+
+ for (int i = 0; i < TEST_NUM_EXPECTS; i++) {
+ expects[i] = false;
+ notExpecting[i] = false;
+ eventsReceived[i] = false;
+ }
+
+ for (int i = 0; i < expectDataLength; i++) {
+ expectData[i] = 0;
+ }
+
+ expectDataLength = -1;
+ }
+
+ /**
+ * Attach the RequestHandle to this handler
+ * @param requestHandle The RequestHandle
+ */
+ public void attachRequestHandle(RequestHandle requestHandle) {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler.attachRequestHandle(): " +
+ "requestHandle: " + requestHandle);
+ }
+ mRequestHandle = requestHandle;
+ }
+
+ /**
+ * Detach the RequestHandle
+ */
+ public void detachRequestHandle() {
+ if (Config.LOGV) {
+ Log.v(LOGTAG, "TestEventHandler.detachRequestHandle(): " +
+ "requestHandle: " + mRequestHandle);
+ }
+ mRequestHandle = null;
+ }
+
+ protected final static String LOGTAG = "http";
+}
diff --git a/tests/CoreTests/android/core/TestWebData.java b/tests/CoreTests/android/core/TestWebData.java
new file mode 100644
index 0000000..2ef19be
--- /dev/null
+++ b/tests/CoreTests/android/core/TestWebData.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+/**
+ * Represents test data used by the Request API tests
+ */
+public class TestWebData {
+
+ /*
+ * Simple Html body
+ * <html>
+ * <body>
+ * <h1>Hello World!</h1>
+ * </body>
+ * </html>
+ */
+ public final static byte[] test1 = {
+ (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d,
+ (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c,
+ (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79,
+ (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68,
+ (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65,
+ (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20,
+ (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c,
+ (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f,
+ (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a,
+ (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f,
+ (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a,
+ (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74,
+ (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a
+ };
+
+ /*
+ * Simple Html body
+ * <html>
+ * <body>
+ * <h1>Hello World!</h1>
+ * </body>
+ * </html>
+ */
+ public final static byte[] test2 = {
+ (byte)0x3c, (byte)0x68, (byte)0x74, (byte)0x6d,
+ (byte)0x6c, (byte)0x3e, (byte)0x0a, (byte)0x3c,
+ (byte)0x62, (byte)0x6f, (byte)0x64, (byte)0x79,
+ (byte)0x3e, (byte)0x0a, (byte)0x3c, (byte)0x68,
+ (byte)0x31, (byte)0x3e, (byte)0x48, (byte)0x65,
+ (byte)0x6c, (byte)0x6c, (byte)0x6f, (byte)0x20,
+ (byte)0x57, (byte)0x6f, (byte)0x72, (byte)0x6c,
+ (byte)0x64, (byte)0x21, (byte)0x3c, (byte)0x2f,
+ (byte)0x68, (byte)0x31, (byte)0x3e, (byte)0x0a,
+ (byte)0x3c, (byte)0x2f, (byte)0x62, (byte)0x6f,
+ (byte)0x64, (byte)0x79, (byte)0x3e, (byte)0x0a,
+ (byte)0x3c, (byte)0x2f, (byte)0x68, (byte)0x74,
+ (byte)0x6d, (byte)0x6c, (byte)0x3e, (byte)0x0a
+ };
+
+ // string for test request post body
+ public final static String postContent = "user=111";
+
+ // Array of all test data
+ public final static byte[][] tests = {
+ test1,
+ test2
+ };
+
+ /**
+ * List of static test cases for use with test server
+ */
+ public static TestWebData[] testParams = {
+ new TestWebData(52, 14000000, "test1", "text/html", false),
+ new TestWebData(52, 14000002, "test2", "unknown/unknown", false)
+ };
+
+ /**
+ * List of response strings for use by the test server
+ */
+ public static String[] testServerResponse = {
+ "Redirecting 301",
+ "Redirecting 302",
+ "Redirecting 303",
+ "Redirecting 307"
+ };
+
+ // Redirection indices into testServerResponse
+ public final static int REDIRECT_301 = 0;
+ public final static int REDIRECT_302 = 1;
+ public final static int REDIRECT_303 = 2;
+ public final static int REDIRECT_307 = 3;
+
+ /**
+ * Creates a data package with information used by the server when responding
+ * to requests
+ */
+ TestWebData(int length, int lastModified, String name, String type, boolean isDir) {
+ testLength = length;
+ testLastModified = lastModified;
+ testName = name;
+ testType = type;
+ testDir = isDir;
+ }
+
+ // Length of test entity body
+ public int testLength;
+
+ // Last modified date value (milliseconds)
+ public int testLastModified;
+
+ // Test identification name
+ public String testName;
+
+ // The MIME type to assume for this test
+ public String testType;
+
+ // Indicates if this is a directory or not
+ public boolean testDir;
+
+}
diff --git a/tests/CoreTests/android/core/TestWebServer.java b/tests/CoreTests/android/core/TestWebServer.java
new file mode 100644
index 0000000..f73e6ff
--- /dev/null
+++ b/tests/CoreTests/android/core/TestWebServer.java
@@ -0,0 +1,871 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import android.util.Log;
+
+import java.io.*;
+import java.lang.Thread;
+import java.net.*;
+import java.util.*;
+
+/**
+ * TestWebServer is a simulated controllable test server that
+ * can respond to requests from HTTP clients.
+ *
+ * The server can be controlled to change how it reacts to any
+ * requests, and can be told to simulate various events (such as
+ * network failure) that would happen in a real environment.
+ */
+class TestWebServer implements HttpConstants {
+
+ /* static class data/methods */
+
+ /* The ANDROID_LOG_TAG */
+ private final static String LOGTAG = "httpsv";
+
+ /* Where worker threads stand idle */
+ Vector threads = new Vector();
+
+ /* List of all active worker threads */
+ Vector activeThreads = new Vector();
+
+ /* timeout on client connections */
+ int timeout = 0;
+
+ /* max # worker threads */
+ int workers = 5;
+
+ /* Default port for this server to listen on */
+ final static int DEFAULT_PORT = 8080;
+
+ /* Default socket timeout value */
+ final static int DEFAULT_TIMEOUT = 5000;
+
+ /* Version string (configurable) */
+ protected String HTTP_VERSION_STRING = "HTTP/1.1";
+
+ /* Indicator for whether this server is configured as a HTTP/1.1
+ * or HTTP/1.0 server
+ */
+ private boolean http11 = true;
+
+ /* The thread handling new requests from clients */
+ private AcceptThread acceptT;
+
+ /* timeout on client connections */
+ int mTimeout;
+
+ /* Server port */
+ int mPort;
+
+ /* Switch on/off logging */
+ boolean mLog = false;
+
+ /* If set, this will keep connections alive after a request has been
+ * processed.
+ */
+ boolean keepAlive = true;
+
+ /* If set, this will cause response data to be sent in 'chunked' format */
+ boolean chunked = false;
+
+ /* If set, this will indicate a new redirection host */
+ String redirectHost = null;
+
+ /* If set, this indicates the reason for redirection */
+ int redirectCode = -1;
+
+ /* Set the number of connections the server will accept before shutdown */
+ int acceptLimit = 100;
+
+ /* Count of number of accepted connections */
+ int acceptedConnections = 0;
+
+ public TestWebServer() {
+ }
+
+ /**
+ * Initialize a new server with default port and timeout.
+ * @param log Set true if you want trace output
+ */
+ public void initServer(boolean log) throws Exception {
+ initServer(DEFAULT_PORT, DEFAULT_TIMEOUT, log);
+ }
+
+ /**
+ * Initialize a new server with default timeout.
+ * @param port Sets the server to listen on this port
+ * @param log Set true if you want trace output
+ */
+ public void initServer(int port, boolean log) throws Exception {
+ initServer(port, DEFAULT_TIMEOUT, log);
+ }
+
+ /**
+ * Initialize a new server with default port and timeout.
+ * @param port Sets the server to listen on this port
+ * @param timeout Indicates the period of time to wait until a socket is
+ * closed
+ * @param log Set true if you want trace output
+ */
+ public void initServer(int port, int timeout, boolean log) throws Exception {
+ mPort = port;
+ mTimeout = timeout;
+ mLog = log;
+ keepAlive = true;
+
+ if (acceptT == null) {
+ acceptT = new AcceptThread();
+ acceptT.init();
+ acceptT.start();
+ }
+ }
+
+ /**
+ * Print to the log file (if logging enabled)
+ * @param s String to send to the log
+ */
+ protected void log(String s) {
+ if (mLog) {
+ Log.d(LOGTAG, s);
+ }
+ }
+
+ /**
+ * Set the server to be an HTTP/1.0 or HTTP/1.1 server.
+ * This should be called prior to any requests being sent
+ * to the server.
+ * @param set True for the server to be HTTP/1.1, false for HTTP/1.0
+ */
+ public void setHttpVersion11(boolean set) {
+ http11 = set;
+ if (set) {
+ HTTP_VERSION_STRING = "HTTP/1.1";
+ } else {
+ HTTP_VERSION_STRING = "HTTP/1.0";
+ }
+ }
+
+ /**
+ * Call this to determine whether server connection should remain open
+ * @param value Set true to keep connections open after a request
+ * completes
+ */
+ public void setKeepAlive(boolean value) {
+ keepAlive = value;
+ }
+
+ /**
+ * Call this to indicate whether chunked data should be used
+ * @param value Set true to make server respond with chunk encoded
+ * content data.
+ */
+ public void setChunked(boolean value) {
+ chunked = value;
+ }
+
+ /**
+ * Call this to specify the maximum number of sockets to accept
+ * @param limit The number of sockets to accept
+ */
+ public void setAcceptLimit(int limit) {
+ acceptLimit = limit;
+ }
+
+ /**
+ * Call this to indicate redirection port requirement.
+ * When this value is set, the server will respond to a request with
+ * a redirect code with the Location response header set to the value
+ * specified.
+ * @param redirect The location to be redirected to
+ * @param redirectCode The code to send when redirecting
+ */
+ public void setRedirect(String redirect, int code) {
+ redirectHost = redirect;
+ redirectCode = code;
+ log("Server will redirect output to "+redirect+" code "+code);
+ }
+
+ /**
+ * Cause the thread accepting connections on the server socket to close
+ */
+ public void close() {
+ /* Stop the Accept thread */
+ if (acceptT != null) {
+ log("Closing AcceptThread"+acceptT);
+ acceptT.close();
+ acceptT = null;
+ }
+ }
+ /**
+ * The AcceptThread is responsible for initiating worker threads
+ * to handle incoming requests from clients.
+ */
+ class AcceptThread extends Thread {
+
+ ServerSocket ss = null;
+ boolean running = false;
+
+ public void init() {
+ // Networking code doesn't support ServerSocket(port) yet
+ InetSocketAddress ia = new InetSocketAddress(mPort);
+ while (true) {
+ try {
+ ss = new ServerSocket();
+ // Socket timeout functionality is not available yet
+ //ss.setSoTimeout(5000);
+ ss.setReuseAddress(true);
+ ss.bind(ia);
+ break;
+ } catch (IOException e) {
+ log("IOException in AcceptThread.init()");
+ e.printStackTrace();
+ // wait and retry
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e1) {
+ // TODO Auto-generated catch block
+ e1.printStackTrace();
+ }
+ }
+ }
+ }
+
+ /**
+ * Main thread responding to new connections
+ */
+ public synchronized void run() {
+ running = true;
+ try {
+ while (running) {
+ // Log.d(LOGTAG, "TestWebServer run() calling accept()");
+ Socket s = ss.accept();
+ acceptedConnections++;
+ if (acceptedConnections >= acceptLimit) {
+ running = false;
+ }
+
+ Worker w = null;
+ synchronized (threads) {
+ if (threads.isEmpty()) {
+ Worker ws = new Worker();
+ ws.setSocket(s);
+ activeThreads.addElement(ws);
+ (new Thread(ws, "additional worker")).start();
+ } else {
+ w = (Worker) threads.elementAt(0);
+ threads.removeElementAt(0);
+ w.setSocket(s);
+ }
+ }
+ }
+ } catch (SocketException e) {
+ log("SocketException in AcceptThread: probably closed during accept");
+ running = false;
+ } catch (IOException e) {
+ log("IOException in AcceptThread");
+ e.printStackTrace();
+ running = false;
+ }
+ log("AcceptThread terminated" + this);
+ }
+
+ // Close this socket
+ public void close() {
+ try {
+ running = false;
+ /* Stop server socket from processing further. Currently
+ this does not cause the SocketException from ss.accept
+ therefore the acceptLimit functionality has been added
+ to circumvent this limitation */
+ ss.close();
+
+ // Stop worker threads from continuing
+ for (Enumeration e = activeThreads.elements(); e.hasMoreElements();) {
+ Worker w = (Worker)e.nextElement();
+ w.close();
+ }
+ activeThreads.clear();
+
+ } catch (IOException e) {
+ /* We are shutting down the server, so we expect
+ * things to die. Don't propagate.
+ */
+ log("IOException caught by server socket close");
+ }
+ }
+ }
+
+ // Size of buffer for reading from the connection
+ final static int BUF_SIZE = 2048;
+
+ /* End of line byte sequence */
+ static final byte[] EOL = {(byte)'\r', (byte)'\n' };
+
+ /**
+ * The worker thread handles all interactions with a current open
+ * connection. If pipelining is turned on, this will allow this
+ * thread to continuously operate on numerous requests before the
+ * connection is closed.
+ */
+ class Worker implements HttpConstants, Runnable {
+
+ /* buffer to use to hold request data */
+ byte[] buf;
+
+ /* Socket to client we're handling */
+ private Socket s;
+
+ /* Reference to current request method ID */
+ private int requestMethod;
+
+ /* Reference to current requests test file/data */
+ private String testID;
+
+ /* Reference to test number from testID */
+ private int testNum;
+
+ /* Reference to whether new request has been initiated yet */
+ private boolean readStarted;
+
+ /* Indicates whether current request has any data content */
+ private boolean hasContent = false;
+
+ boolean running = false;
+
+ /* Request headers are stored here */
+ private Hashtable<String, String> headers = new Hashtable<String, String>();
+
+ /* Create a new worker thread */
+ Worker() {
+ buf = new byte[BUF_SIZE];
+ s = null;
+ }
+
+ /**
+ * Called by the AcceptThread to unblock this Worker to process
+ * a request.
+ * @param s The socket on which the connection has been made
+ */
+ synchronized void setSocket(Socket s) {
+ this.s = s;
+ notify();
+ }
+
+ /**
+ * Called by the accept thread when it's closing. Potentially unblocks
+ * the worker thread to terminate properly
+ */
+ synchronized void close() {
+ running = false;
+ notify();
+ }
+
+ /**
+ * Main worker thread. This will wait until a request has
+ * been identified by the accept thread upon which it will
+ * service the thread.
+ */
+ public synchronized void run() {
+ running = true;
+ while(running) {
+ if (s == null) {
+ /* nothing to do */
+ try {
+ log(this+" Moving to wait state");
+ wait();
+ } catch (InterruptedException e) {
+ /* should not happen */
+ continue;
+ }
+ if (!running) break;
+ }
+ try {
+ handleClient();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ /* go back in wait queue if there's fewer
+ * than numHandler connections.
+ */
+ s = null;
+ Vector pool = threads;
+ synchronized (pool) {
+ if (pool.size() >= workers) {
+ /* too many threads, exit this one */
+ activeThreads.remove(this);
+ return;
+ } else {
+ pool.addElement(this);
+ }
+ }
+ }
+ log(this+" terminated");
+ }
+
+ /**
+ * Zero out the buffer from last time
+ */
+ private void clearBuffer() {
+ for (int i = 0; i < BUF_SIZE; i++) {
+ buf[i] = 0;
+ }
+ }
+
+ /**
+ * Utility method to read a line of data from the input stream
+ * @param is Inputstream to read
+ * @return number of bytes read
+ */
+ private int readOneLine(InputStream is) {
+
+ int read = 0;
+
+ clearBuffer();
+ try {
+ log("Reading one line: started ="+readStarted+" avail="+is.available());
+ while ((!readStarted) || (is.available() > 0)) {
+ int data = is.read();
+ // We shouldn't get EOF but we need tdo check
+ if (data == -1) {
+ log("EOF returned");
+ return -1;
+ }
+
+ buf[read] = (byte)data;
+
+ System.out.print((char)data);
+
+ readStarted = true;
+ if (buf[read++]==(byte)'\n') {
+ System.out.println();
+ return read;
+ }
+ }
+ } catch (IOException e) {
+ log("IOException from readOneLine");
+ e.printStackTrace();
+ }
+ return read;
+ }
+
+ /**
+ * Read a chunk of data
+ * @param is Stream from which to read data
+ * @param length Amount of data to read
+ * @return number of bytes read
+ */
+ private int readData(InputStream is, int length) {
+ int read = 0;
+ int count;
+ // At the moment we're only expecting small data amounts
+ byte[] buf = new byte[length];
+
+ try {
+ while (is.available() > 0) {
+ count = is.read(buf, read, length-read);
+ read += count;
+ }
+ } catch (IOException e) {
+ log("IOException from readData");
+ e.printStackTrace();
+ }
+ return read;
+ }
+
+ /**
+ * Read the status line from the input stream extracting method
+ * information.
+ * @param is Inputstream to read
+ * @return number of bytes read
+ */
+ private int parseStatusLine(InputStream is) {
+ int index;
+ int nread = 0;
+
+ log("Parse status line");
+ // Check for status line first
+ nread = readOneLine(is);
+ // Bomb out if stream closes prematurely
+ if (nread == -1) {
+ requestMethod = UNKNOWN_METHOD;
+ return -1;
+ }
+
+ if (buf[0] == (byte)'G' &&
+ buf[1] == (byte)'E' &&
+ buf[2] == (byte)'T' &&
+ buf[3] == (byte)' ') {
+ requestMethod = GET_METHOD;
+ log("GET request");
+ index = 4;
+ } else if (buf[0] == (byte)'H' &&
+ buf[1] == (byte)'E' &&
+ buf[2] == (byte)'A' &&
+ buf[3] == (byte)'D' &&
+ buf[4] == (byte)' ') {
+ requestMethod = HEAD_METHOD;
+ log("HEAD request");
+ index = 5;
+ } else if (buf[0] == (byte)'P' &&
+ buf[1] == (byte)'O' &&
+ buf[2] == (byte)'S' &&
+ buf[3] == (byte)'T' &&
+ buf[4] == (byte)' ') {
+ requestMethod = POST_METHOD;
+ log("POST request");
+ index = 5;
+ } else {
+ // Unhandled request
+ requestMethod = UNKNOWN_METHOD;
+ return -1;
+ }
+
+ // A valid method we understand
+ if (requestMethod > UNKNOWN_METHOD) {
+ // Read file name
+ int i = index;
+ while (buf[i] != (byte)' ') {
+ // There should be HTTP/1.x at the end
+ if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) {
+ requestMethod = UNKNOWN_METHOD;
+ return -1;
+ }
+ i++;
+ }
+
+ testID = new String(buf, 0, index, i-index);
+ if (testID.startsWith("/")) {
+ testID = testID.substring(1);
+ }
+
+ return nread;
+ }
+ return -1;
+ }
+
+ /**
+ * Read a header from the input stream
+ * @param is Inputstream to read
+ * @return number of bytes read
+ */
+ private int parseHeader(InputStream is) {
+ int index = 0;
+ int nread = 0;
+ log("Parse a header");
+ // Check for status line first
+ nread = readOneLine(is);
+ // Bomb out if stream closes prematurely
+ if (nread == -1) {
+ requestMethod = UNKNOWN_METHOD;
+ return -1;
+ }
+ // Read header entry 'Header: data'
+ int i = index;
+ while (buf[i] != (byte)':') {
+ // There should be an entry after the header
+
+ if ((buf[i] == (byte)'\n') || (buf[i] == (byte)'\r')) {
+ return UNKNOWN_METHOD;
+ }
+ i++;
+ }
+
+ String headerName = new String(buf, 0, i);
+ i++; // Over ':'
+ while (buf[i] == ' ') {
+ i++;
+ }
+ String headerValue = new String(buf, i, nread-1);
+
+ headers.put(headerName, headerValue);
+ return nread;
+ }
+
+ /**
+ * Read all headers from the input stream
+ * @param is Inputstream to read
+ * @return number of bytes read
+ */
+ private int readHeaders(InputStream is) {
+ int nread = 0;
+ log("Read headers");
+ // Headers should be terminated by empty CRLF line
+ while (true) {
+ int headerLen = 0;
+ headerLen = parseHeader(is);
+ if (headerLen == -1)
+ return -1;
+ nread += headerLen;
+ if (headerLen <= 2) {
+ return nread;
+ }
+ }
+ }
+
+ /**
+ * Read content data from the input stream
+ * @param is Inputstream to read
+ * @return number of bytes read
+ */
+ private int readContent(InputStream is) {
+ int nread = 0;
+ log("Read content");
+ String lengthString = headers.get(requestHeaders[REQ_CONTENT_LENGTH]);
+ int length = new Integer(lengthString).intValue();
+
+ // Read content
+ length = readData(is, length);
+ return length;
+ }
+
+ /**
+ * The main loop, reading requests.
+ */
+ void handleClient() throws IOException {
+ InputStream is = new BufferedInputStream(s.getInputStream());
+ PrintStream ps = new PrintStream(s.getOutputStream());
+ int nread = 0;
+
+ /* we will only block in read for this many milliseconds
+ * before we fail with java.io.InterruptedIOException,
+ * at which point we will abandon the connection.
+ */
+ s.setSoTimeout(mTimeout);
+ s.setTcpNoDelay(true);
+
+ do {
+ nread = parseStatusLine(is);
+ if (requestMethod != UNKNOWN_METHOD) {
+
+ // If status line found, read any headers
+ nread = readHeaders(is);
+
+ // Then read content (if any)
+ // TODO handle chunked encoding from the client
+ if (headers.get(requestHeaders[REQ_CONTENT_LENGTH]) != null) {
+ nread = readContent(is);
+ }
+ } else {
+ if (nread > 0) {
+ /* we don't support this method */
+ ps.print(HTTP_VERSION_STRING + " " + HTTP_BAD_METHOD +
+ " unsupported method type: ");
+ ps.write(buf, 0, 5);
+ ps.write(EOL);
+ ps.flush();
+ } else {
+ }
+ if (!keepAlive || nread <= 0) {
+ headers.clear();
+ readStarted = false;
+
+ log("SOCKET CLOSED");
+ s.close();
+ return;
+ }
+ }
+
+ // Reset test number prior to outputing data
+ testNum = -1;
+
+ // Write out the data
+ printStatus(ps);
+ printHeaders(ps);
+
+ // Write line between headers and body
+ psWriteEOL(ps);
+
+ // Write the body
+ if (redirectCode == -1) {
+ switch (requestMethod) {
+ case GET_METHOD:
+ if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) {
+ send404(ps);
+ } else {
+ sendFile(ps);
+ }
+ break;
+ case HEAD_METHOD:
+ // Nothing to do
+ break;
+ case POST_METHOD:
+ // Post method write body data
+ if ((testNum > 0) || (testNum < TestWebData.tests.length - 1)) {
+ sendFile(ps);
+ }
+
+ break;
+ default:
+ break;
+ }
+ } else { // Redirecting
+ switch (redirectCode) {
+ case 301:
+ // Seems 301 needs a body by neon (although spec
+ // says SHOULD).
+ psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_301]);
+ break;
+ case 302:
+ //
+ psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_302]);
+ break;
+ case 303:
+ psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_303]);
+ break;
+ case 307:
+ psPrint(ps, TestWebData.testServerResponse[TestWebData.REDIRECT_307]);
+ break;
+ default:
+ break;
+ }
+ }
+
+ ps.flush();
+
+ // Reset for next request
+ readStarted = false;
+ headers.clear();
+
+ } while (keepAlive);
+
+ log("SOCKET CLOSED");
+ s.close();
+ }
+
+ // Print string to log and output stream
+ void psPrint(PrintStream ps, String s) throws IOException {
+ log(s);
+ ps.print(s);
+ }
+
+ // Print bytes to log and output stream
+ void psWrite(PrintStream ps, byte[] bytes, int len) throws IOException {
+ log(new String(bytes));
+ ps.write(bytes, 0, len);
+ }
+
+ // Print CRLF to log and output stream
+ void psWriteEOL(PrintStream ps) throws IOException {
+ log("CRLF");
+ ps.write(EOL);
+ }
+
+
+ // Print status to log and output stream
+ void printStatus(PrintStream ps) throws IOException {
+ // Handle redirects first.
+ if (redirectCode != -1) {
+ log("REDIRECTING TO "+redirectHost+" status "+redirectCode);
+ psPrint(ps, HTTP_VERSION_STRING + " " + redirectCode +" Moved permanently");
+ psWriteEOL(ps);
+ psPrint(ps, "Location: " + redirectHost);
+ psWriteEOL(ps);
+ return;
+ }
+
+
+ if (testID.startsWith("test")) {
+ testNum = Integer.valueOf(testID.substring(4))-1;
+ }
+
+ if ((testNum < 0) || (testNum > TestWebData.tests.length - 1)) {
+ psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_NOT_FOUND + " not found");
+ psWriteEOL(ps);
+ } else {
+ psPrint(ps, HTTP_VERSION_STRING + " " + HTTP_OK+" OK");
+ psWriteEOL(ps);
+ }
+
+ log("Status sent");
+ }
+ /**
+ * Create the server response and output to the stream
+ * @param ps The PrintStream to output response headers and data to
+ */
+ void printHeaders(PrintStream ps) throws IOException {
+ psPrint(ps,"Server: TestWebServer"+mPort);
+ psWriteEOL(ps);
+ psPrint(ps, "Date: " + (new Date()));
+ psWriteEOL(ps);
+ psPrint(ps, "Connection: " + ((keepAlive) ? "Keep-Alive" : "Close"));
+ psWriteEOL(ps);
+
+ // Yuk, if we're not redirecting, we add the file details
+ if (redirectCode == -1) {
+
+ if (!TestWebData.testParams[testNum].testDir) {
+ if (chunked) {
+ psPrint(ps, "Transfer-Encoding: chunked");
+ } else {
+ psPrint(ps, "Content-length: "+TestWebData.testParams[testNum].testLength);
+ }
+ psWriteEOL(ps);
+
+ psPrint(ps,"Last Modified: " + (new
+ Date(TestWebData.testParams[testNum].testLastModified)));
+ psWriteEOL(ps);
+
+ psPrint(ps, "Content-type: " + TestWebData.testParams[testNum].testType);
+ psWriteEOL(ps);
+ } else {
+ psPrint(ps, "Content-type: text/html");
+ psWriteEOL(ps);
+ }
+ } else {
+ // Content-length of 301, 302, 303, 307 are the same.
+ psPrint(ps, "Content-length: "+(TestWebData.testServerResponse[TestWebData.REDIRECT_301]).length());
+ psWriteEOL(ps);
+ psWriteEOL(ps);
+ }
+ log("Headers sent");
+
+ }
+
+ /**
+ * Sends the 404 not found message
+ * @param ps The PrintStream to write to
+ */
+ void send404(PrintStream ps) throws IOException {
+ ps.println("Not Found\n\n"+
+ "The requested resource was not found.\n");
+ }
+
+ /**
+ * Sends the data associated with the headers
+ * @param ps The PrintStream to write to
+ */
+ void sendFile(PrintStream ps) throws IOException {
+ // For now just make a chunk with the whole of the test data
+ // It might be worth making this multiple chunks for large
+ // test data to test multiple chunks.
+ int dataSize = TestWebData.tests[testNum].length;
+ if (chunked) {
+ psPrint(ps, Integer.toHexString(dataSize));
+ psWriteEOL(ps);
+ psWrite(ps, TestWebData.tests[testNum], dataSize);
+ psWriteEOL(ps);
+ psPrint(ps, "0");
+ psWriteEOL(ps);
+ psWriteEOL(ps);
+ } else {
+ psWrite(ps, TestWebData.tests[testNum], dataSize);
+ }
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/TreeMapTest.java b/tests/CoreTests/android/core/TreeMapTest.java
new file mode 100644
index 0000000..229d86d
--- /dev/null
+++ b/tests/CoreTests/android/core/TreeMapTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.util.HashMap;
+import java.util.Random;
+import java.util.TreeMap;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Tests for basic functinality of TreeMaps
+ */
+public class TreeMapTest extends TestCase {
+
+ private Random mRandom = new Random(1);
+
+ private static final boolean SPEW = false;
+
+ @LargeTest
+ public void testTreeMap() {
+ for (int i = 0; i < 10; i++) {
+ if (SPEW) System.out.println("Running doTest cycle #" + (i + 1));
+ doTest();
+ }
+ }
+
+ private void doTest() {
+ TreeMap<Integer, String> tm = new TreeMap<Integer, String>();
+ HashMap<Integer, String> hm = new HashMap<Integer, String>();
+
+ int minVal = Integer.MAX_VALUE;
+ int maxVal = Integer.MIN_VALUE;
+
+ for (int i = 0; i < 100; i++) {
+ int val = mRandom.nextInt(1000);
+ if (SPEW) System.out.println("Adding val = " + val);
+ if (val < minVal) {
+ minVal = val;
+ }
+ if (val > maxVal) {
+ maxVal = val;
+ }
+ tm.put(new Integer(val), "V:" + val);
+ hm.put(new Integer(val), "V:" + val);
+
+ if (SPEW) System.out.println("tm = " + tm);
+
+ if (SPEW) System.out.println("tm.size() = " + tm.size());
+ if (SPEW) System.out.println("hm.size() = " + hm.size());
+ assertEquals(tm.size(), hm.size());
+
+ if (SPEW) System.out.println("tm.firstKey() = " + tm.firstKey());
+ if (SPEW) System.out.println("minVal = " + minVal);
+ if (SPEW) System.out.println("tm.lastKey() = " + tm.lastKey());
+ if (SPEW) System.out.println("maxVal = " + maxVal);
+ assertEquals(minVal, tm.firstKey().intValue());
+ assertEquals(maxVal, tm.lastKey().intValue());
+ }
+
+ // Check for equality
+ for (int val = 0; val < 1000; val++) {
+ Integer vv = new Integer(val);
+ String tms = tm.get(vv);
+ String hms = hm.get(vv);
+ assertEquals(tms, hms);
+ }
+
+ for (int i = 0; i < 1000; i++) {
+ int val = mRandom.nextInt(1000);
+ if (SPEW) System.out.println("Removing val = " + val);
+
+ String tms = tm.remove(new Integer(val));
+ String hms = hm.remove(new Integer(val));
+
+ if (SPEW) System.out.println("tm = " + tm);
+
+ assertEquals(tm.size(), hm.size());
+ assertEquals(tms, hms);
+ }
+
+ // Check for equality
+ for (int val = 0; val < 1000; val++) {
+ Integer vv = new Integer(val);
+ String tms = tm.get(vv);
+ String hms = hm.get(vv);
+ assertEquals(tms, hms);
+ }
+ }
+}
diff --git a/tests/CoreTests/android/core/URITest.java b/tests/CoreTests/android/core/URITest.java
new file mode 100644
index 0000000..3b821d8
--- /dev/null
+++ b/tests/CoreTests/android/core/URITest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class URITest extends TestCase {
+
+ @SmallTest
+ public void testConstruct() throws Exception {
+ construct("http://www.google.com/this/is-the/path?query#fragment",
+ "www.google.com", "/this/is-the/path", true);
+ }
+
+ private static void construct(String str, String host, String path, boolean absolute)
+ throws URISyntaxException {
+ URI uri = new URI(str);
+ assertEquals(host, uri.getHost());
+ assertEquals(path, uri.getPath());
+ assertEquals(absolute, uri.isAbsolute());
+ }
+
+ @SmallTest
+ public void testResolve() throws Exception {
+ resolve("http://www.google.com/your",
+ "mom",
+ "http://www.google.com/mom");
+ }
+
+ private static void resolve(String base, String uri, String expected) {
+ URI b = URI.create(base);
+ URI resolved = b.resolve(uri);
+// System.out.println("base=" + base + " uri=" + uri
+// + " resolved=" + resolved);
+ assertEquals(expected, resolved.toString());
+ }
+}
diff --git a/tests/CoreTests/android/core/URLTest.java b/tests/CoreTests/android/core/URLTest.java
new file mode 100644
index 0000000..56f9f7b
--- /dev/null
+++ b/tests/CoreTests/android/core/URLTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.io.PrintWriter;
+import java.net.HttpURLConnection;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.net.URL;
+import java.net.URLConnection;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+@Suppress
+public class URLTest extends TestCase {
+
+ private static void get(String u) throws IOException {
+ URL url = new URL(u);
+ URLConnection cn = url.openConnection();
+ cn.connect();
+// System.out.println("Content-Type: " + cn.getContentType());
+// System.out.println("Content-Length: " + cn.getContentLength());
+
+ InputStream stream = cn.getInputStream();
+ if (stream == null) {
+ throw new RuntimeException("stream is null");
+ }
+ byte[] data = new byte[1024];
+ stream.read(data);
+
+// if (true) {
+// System.out.print("data=");
+// System.out.write(data);
+// System.out.println();
+// }
+
+// System.out.println("Content-Type: " + cn.getContentType());
+// System.out.print("data:");
+// System.out.write(data);
+// System.out.println();
+
+ assertTrue(new String(data).indexOf("<html>") >= 0);
+ }
+
+ public void testGetHTTP() throws Exception {
+ get("http://www.google.com");
+ }
+
+ public void testGetHTTPS() throws Exception {
+ get("https://www.fortify.net/cgi/ssl_2.pl");
+ }
+
+ /**
+ * Dummy HTTP server class for testing keep-alive behavior. Listens a
+ * single time and responds to a given number of requests on the same
+ * socket. Then closes the socket.
+ */
+ private static class DummyServer implements Runnable {
+
+ private int keepAliveCount;
+
+ public DummyServer(int keepAliveCount) {
+ this.keepAliveCount = keepAliveCount;
+ }
+
+ public void run() {
+ try {
+ ServerSocket server = new ServerSocket(8182);
+ Socket socket = server.accept();
+
+ InputStream input = socket.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+ try {
+ for (int i = 0; i < keepAliveCount; i++) {
+ String header = reader.readLine();
+ while (header != null && header.length() != 0) {
+ header = reader.readLine();
+ }
+
+ OutputStream output = socket.getOutputStream();
+ PrintWriter writer = new PrintWriter(output);
+
+ try {
+ writer.println("HTTP/1.1 200 OK");
+ String body = "Hello, Android world #" + i + "!";
+ writer.println("Content-Length: " + body.length());
+ writer.println("");
+ writer.print(body);
+ writer.flush();
+ } finally {
+ writer.close();
+ }
+ }
+ } finally {
+ reader.close();
+ }
+ socket.close();
+ server.close();
+ } catch (Exception ex) {
+ throw new RuntimeException(ex);
+ }
+ }
+ }
+
+ /**
+ * Does a request to the given URL, reads and returns the result.
+ */
+ private String request(URL url) throws Exception {
+ URLConnection connection = url.openConnection();
+ connection.connect();
+
+ InputStream input = connection.getInputStream();
+ BufferedReader reader = new BufferedReader(new InputStreamReader(input));
+ try {
+ return reader.readLine();
+ } finally {
+ reader.close();
+ }
+ }
+
+ /**
+ * Test case for HTTP keep-alive behavior.
+ */
+ public void testGetKeepAlive() throws Exception {
+ new Thread(new DummyServer(3)).start();
+ Thread.sleep(100);
+
+ // We expect the request to work three times, then it fails.
+ URL url = new URL("http://localhost:8182");
+ assertEquals("Hello, Android world #0!", request(url));
+ assertEquals("Hello, Android world #1!", request(url));
+ assertEquals("Hello, Android world #2!", request(url));
+
+ try {
+ request(url);
+ fail("ConnectException expected.");
+ } catch (Exception ex) {
+ // Ok.
+ }
+ }
+
+ /**
+ * Regression for issue 1001814.
+ */
+ public void testHttpConnectionTimeout() throws Exception {
+ int timeout = 5000;
+ HttpURLConnection cn = null;
+ long start = 0;
+ try {
+ start = System.currentTimeMillis();
+ URL url = new URL("http://123.123.123.123");
+ cn = (HttpURLConnection) url.openConnection();
+ cn.setConnectTimeout(5000);
+ cn.connect();
+ fail("should have thrown an exception");
+ } catch (IOException ioe) {
+ long delay = System.currentTimeMillis() - start;
+ if (Math.abs(timeout - delay) > 1000) {
+ fail("Timeout was not accurate. it needed " + delay +
+ " instead of " + timeout + "miliseconds");
+ }
+ } finally {
+ if (cn != null) {
+ cn.disconnect();
+ }
+ }
+ }
+
+ /**
+ * Regression test for issue 1158780 where using '{' and '}' in an URL threw
+ * an NPE. The RI accepts this URL and returns the status 404.
+ */
+ public void testMalformedUrl() throws Exception {
+ URL url = new URL("http://www.google.com/cgi-bin/myscript?g={United+States}+Borders+Mexico+{Climate+change}+Marketing+{Automotive+industry}+News+Health+Internet");
+ HttpURLConnection conn = (HttpURLConnection)url.openConnection();
+ int status = conn.getResponseCode();
+ android.util.Log.d("URLTest", "status: " + status);
+ }
+}
diff --git a/tests/CoreTests/android/core/ZipFileTest.java b/tests/CoreTests/android/core/ZipFileTest.java
new file mode 100644
index 0000000..04b476b
--- /dev/null
+++ b/tests/CoreTests/android/core/ZipFileTest.java
@@ -0,0 +1,200 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Enumeration;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipFile;
+import java.util.zip.ZipOutputStream;
+import android.test.suitebuilder.annotation.MediumTest;
+
+
+/**
+ * Basic tests for ZipFile.
+ */
+public class ZipFileTest extends TestCase {
+ private static final int SAMPLE_SIZE = 128 * 1024;
+
+ @MediumTest
+ public void testZipFile() throws Exception {
+
+ File file = File.createTempFile("ZipFileTest", ".zip");
+ try {
+ // create a test file; assume it's not going to collide w/anything
+ FileOutputStream outStream = new FileOutputStream(file);
+ createCompressedZip(outStream);
+// System.out.println("CREATED " + file);
+
+ scanZip(file.getPath());
+ read2(file.getPath());
+ } finally {
+ file.delete();
+ }
+ }
+
+ /*
+ * stepStep == 0 --> >99% compression
+ * stepStep == 1 --> ~30% compression
+ * stepStep == 2 --> no compression
+ */
+ static byte[] makeSampleFile(int stepStep) throws IOException {
+ byte[] sample = new byte[SAMPLE_SIZE];
+ byte val, step;
+ int i, j, offset;
+
+ val = 0;
+ step = 1;
+ offset = 0;
+ for (i = 0; i < SAMPLE_SIZE / 256; i++) {
+ for (j = 0; j < 256; j++) {
+ sample[offset++] = val;
+ val += step;
+ }
+
+ step += stepStep;
+ }
+
+ return sample;
+ }
+
+ static void createCompressedZip(OutputStream bytesOut) throws IOException {
+ ZipOutputStream out = new ZipOutputStream(bytesOut);
+ try {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ byte[] input = makeSampleFile(i);
+ ZipEntry newEntry = new ZipEntry("file-" + i);
+
+ if (i != 1) {
+ newEntry.setComment("this is file " + i);
+ }
+ out.putNextEntry(newEntry);
+ out.write(input, 0, input.length);
+ out.closeEntry();
+ }
+
+ out.setComment("This is a lovely compressed archive!");
+ } finally {
+ out.close();
+ }
+ }
+
+ static void scanZip(String fileName) throws IOException {
+ ZipFile zipFile = new ZipFile(fileName);
+ Enumeration fileList;
+ int idx = 0;
+
+// System.out.println("Contents of " + zipFile + ":");
+ for (fileList = zipFile.entries(); fileList.hasMoreElements();) {
+ ZipEntry entry = (ZipEntry) fileList.nextElement();
+// System.out.println(" " + entry.getName());
+ assertEquals(entry.getName(), "file-" + idx);
+ idx++;
+ }
+
+ zipFile.close();
+ }
+
+ /*
+ * Read compressed data from two different entries at the same time,
+ * to verify that the streams aren't getting confused. If we do
+ * something wrong, the inflater will choke and throw a ZipException.
+ *
+ * This doesn't test synchronization in multi-threaded use.
+ */
+ static void read2(String fileName) throws IOException {
+ ZipFile zipFile;
+ ZipEntry entry1, entry2;
+ byte buf[] = new byte[16384];
+ InputStream stream1, stream2;
+ int len, totalLen1, totalLen2;
+
+ /* use file-1 and file-2 because the compressed data is large */
+ zipFile = new ZipFile(fileName);
+ entry1 = zipFile.getEntry("file-1");
+ entry2 = zipFile.getEntry("file-2");
+
+ /* make sure we got the right thing */
+ assertEquals("file-1", entry1.getName());
+ assertEquals("file-2", entry2.getName());
+
+ /* create streams */
+ stream1 = zipFile.getInputStream(entry1);
+ stream2 = zipFile.getInputStream(entry2);
+
+ /*
+ * Read a piece of file #1.
+ */
+ totalLen1 = stream1.read(buf);
+ assertTrue("initial read failed on #1", totalLen1 >= 0);
+
+ /*
+ * Read a piece of file #2.
+ */
+ totalLen2 = stream2.read(buf);
+ assertTrue("initial read failed on #2", totalLen2 >= 0);
+
+ /*
+ * Read the rest of file #1, and close the stream.
+ *
+ * If our streams are crossed up, we'll fail here.
+ */
+ while ((len = stream1.read(buf)) > 0) {
+ totalLen1 += len;
+ }
+ assertEquals(SAMPLE_SIZE, totalLen1);
+ stream1.close();
+
+ /*
+ * Read the rest of file #2, and close the stream.
+ */
+ while ((len = stream2.read(buf)) > 0) {
+ totalLen2 += len;
+ }
+ assertEquals(SAMPLE_SIZE, totalLen2);
+ stream2.close();
+
+ /*
+ * Open a new one.
+ */
+ stream1 = zipFile.getInputStream(zipFile.getEntry("file-0"));
+
+ /*
+ * Close the ZipFile. According to the RI, none if its InputStreams can
+ * be read after this point.
+ */
+ zipFile.close();
+
+ Exception error = null;
+ try {
+ stream1.read(buf);
+ } catch (Exception ex) {
+ error = ex;
+ }
+
+ assertNotNull("ZipFile shouldn't allow reading of closed files.", error);
+ }
+}
+
diff --git a/tests/CoreTests/android/core/ZipStreamTest.java b/tests/CoreTests/android/core/ZipStreamTest.java
new file mode 100644
index 0000000..74cfe82
--- /dev/null
+++ b/tests/CoreTests/android/core/ZipStreamTest.java
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.core;
+
+import junit.framework.TestCase;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import java.util.zip.ZipOutputStream;
+import android.test.suitebuilder.annotation.LargeTest;
+
+/**
+ * Basic tests for ZipStream
+ */
+public class ZipStreamTest extends TestCase {
+
+ @LargeTest
+ public void testZipStream() throws Exception {
+ ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
+ createCompressedZip(bytesOut);
+
+ byte[] zipData = bytesOut.toByteArray();
+
+ /*
+ FileOutputStream outFile = new FileOutputStream("/tmp/foo.zip");
+ outFile.write(zipData, 0, zipData.length);
+ outFile.close();
+ */
+
+ /*
+ FileInputStream inFile = new FileInputStream("/tmp/foo.zip");
+ int inputLength = inFile.available();
+ zipData = new byte[inputLength];
+ if (inFile.read(zipData) != inputLength)
+ throw new RuntimeException();
+ inFile.close();
+ */
+
+ ByteArrayInputStream bytesIn = new ByteArrayInputStream(zipData);
+ scanZip(bytesIn);
+
+ bytesOut = new ByteArrayOutputStream();
+ createUncompressedZip(bytesOut);
+
+ zipData = bytesOut.toByteArray();
+
+ bytesIn = new ByteArrayInputStream(zipData);
+ scanZip(bytesIn);
+ }
+
+ /*
+ * stepStep == 0 --> >99% compression
+ * stepStep == 1 --> ~30% compression
+ * stepStep == 2 --> no compression
+ */
+ private static byte[] makeSampleFile(int stepStep) throws IOException {
+ byte[] sample = new byte[128 * 1024];
+ byte val, step;
+ int i, j, offset;
+
+ val = 0;
+ step = 1;
+ offset = 0;
+ for (i = 0; i < (128 * 1024) / 256; i++) {
+ for (j = 0; j < 256; j++) {
+ sample[offset++] = val;
+ val += step;
+ }
+
+ step += stepStep;
+ }
+
+ return sample;
+ }
+
+ private static void createCompressedZip(ByteArrayOutputStream bytesOut) throws IOException {
+ ZipOutputStream out = new ZipOutputStream(bytesOut);
+ try {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ byte[] input = makeSampleFile(i);
+ ZipEntry newEntry = new ZipEntry("file-" + i);
+
+ if (i != 1)
+ newEntry.setComment("this is file " + i);
+ out.putNextEntry(newEntry);
+ out.write(input, 0, input.length);
+ out.closeEntry();
+ }
+
+ out.setComment("This is a lovely compressed archive!");
+ } finally {
+ out.close();
+ }
+ }
+
+ private static void createUncompressedZip(ByteArrayOutputStream bytesOut) throws IOException {
+ ZipOutputStream out = new ZipOutputStream(bytesOut);
+ try {
+ long[] crcs = {0x205fbff3, 0x906fae57L, 0x2c235131};
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ byte[] input = makeSampleFile(i);
+ ZipEntry newEntry = new ZipEntry("file-" + i);
+
+ if (i != 1)
+ newEntry.setComment("this is file " + i);
+ newEntry.setMethod(ZipEntry.STORED);
+ newEntry.setSize(128 * 1024);
+ newEntry.setCrc(crcs[i]);
+ out.putNextEntry(newEntry);
+ out.write(input, 0, input.length);
+ out.closeEntry();
+ }
+
+ out.setComment("This is a lovely, but uncompressed, archive!");
+ } finally {
+ out.close();
+ }
+ }
+
+ private static void scanZip(ByteArrayInputStream bytesIn) throws IOException {
+ ZipInputStream in = new ZipInputStream(bytesIn);
+ try {
+ int i;
+
+ for (i = 0; i < 3; i++) {
+ ZipEntry entry = in.getNextEntry();
+ ByteArrayOutputStream contents = new ByteArrayOutputStream();
+ byte[] buf = new byte[4096];
+ int len, totalLen = 0;
+
+ while ((len = in.read(buf)) > 0) {
+ contents.write(buf, 0, len);
+ totalLen += len;
+ }
+
+ assertEquals(128 * 1024, totalLen);
+
+// System.out.println("ZipStreamTest: name='" + entry.getName()
+// + "', zero=" + contents.toByteArray()[0]
+// + ", tfs=" + contents.toByteArray()[257]
+// + ", crc=" + Long.toHexString(entry.getCrc()));
+ }
+
+ assertNull("should only be three entries", in.getNextEntry());
+ } finally {
+ in.close();
+ }
+ }
+}
+
diff --git a/tests/CoreTests/android/database/MatrixCursorTest.java b/tests/CoreTests/android/database/MatrixCursorTest.java
new file mode 100644
index 0000000..fb8a12f
--- /dev/null
+++ b/tests/CoreTests/android/database/MatrixCursorTest.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.database;
+
+import junit.framework.TestCase;
+
+import java.util.*;
+
+public class MatrixCursorTest extends TestCase {
+
+ public void testEmptyCursor() {
+ Cursor cursor = new MatrixCursor(new String[] { "a" });
+ assertEquals(0, cursor.getCount());
+ }
+
+ public void testNullValue() {
+ MatrixCursor cursor = new MatrixCursor(new String[] { "a" });
+ cursor.newRow().add(null);
+ cursor.moveToNext();
+ assertTrue(cursor.isNull(0));
+ }
+
+ public void testMatrixCursor() {
+ MatrixCursor cursor = newMatrixCursor();
+
+ cursor.newRow()
+ .add("a")
+ .add(1)
+ .add(2)
+ .add(3)
+ .add(4)
+ .add(5);
+
+ cursor.moveToNext();
+
+ checkValues(cursor);
+
+ cursor.newRow()
+ .add("a")
+ .add("1")
+ .add("2")
+ .add("3")
+ .add("4")
+ .add("5");
+
+ cursor.moveToNext();
+ checkValues(cursor);
+
+ cursor.moveToPrevious();
+ checkValues(cursor);
+ }
+
+ public void testAddArray() {
+ MatrixCursor cursor = newMatrixCursor();
+
+ cursor.addRow(new Object[] { "a", 1, 2, 3, 4, 5 });
+ cursor.moveToNext();
+ checkValues(cursor);
+
+ try {
+ cursor.addRow(new Object[0]);
+ fail();
+ } catch (IllegalArgumentException e) { /* expected */ }
+ }
+
+ public void testAddIterable() {
+ MatrixCursor cursor = newMatrixCursor();
+
+ cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5));
+ cursor.moveToNext();
+ checkValues(cursor);
+
+ try {
+ cursor.addRow(Collections.emptyList());
+ fail();
+ } catch (IllegalArgumentException e) { /* expected */ }
+
+ try {
+ cursor.addRow(Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!"));
+ fail();
+ } catch (IllegalArgumentException e) { /* expected */ }
+ }
+
+ public void testAddArrayList() {
+ MatrixCursor cursor = newMatrixCursor();
+
+ cursor.addRow(new NonIterableArrayList<Object>(
+ Arrays.asList("a", 1, 2, 3, 4, 5)));
+ cursor.moveToNext();
+ checkValues(cursor);
+
+ try {
+ cursor.addRow(new NonIterableArrayList<Object>());
+ fail();
+ } catch (IllegalArgumentException e) { /* expected */ }
+
+ try {
+ cursor.addRow(new NonIterableArrayList<Object>(
+ Arrays.asList("a", 1, 2, 3, 4, 5, "Too many!")));
+ fail();
+ } catch (IllegalArgumentException e) { /* expected */ }
+ }
+
+ static class NonIterableArrayList<T> extends ArrayList<T> {
+
+ NonIterableArrayList() {}
+
+ NonIterableArrayList(Collection<? extends T> ts) {
+ super(ts);
+ }
+
+ @Override
+ public Iterator<T> iterator() {
+ throw new AssertionError();
+ }
+ }
+
+ private MatrixCursor newMatrixCursor() {
+ return new MatrixCursor(new String[] {
+ "string", "short", "int", "long", "float", "double" });
+ }
+
+ private void checkValues(MatrixCursor cursor) {
+ assertEquals("a", cursor.getString(0));
+ assertEquals(1, cursor.getShort(1));
+ assertEquals(2, cursor.getInt(2));
+ assertEquals(3, cursor.getLong(3));
+ assertEquals(4.0f, cursor.getFloat(4));
+ assertEquals(5.0D, cursor.getDouble(5));
+ }
+
+}
diff --git a/tests/CoreTests/android/graphics/ColorStateListTest.java b/tests/CoreTests/android/graphics/ColorStateListTest.java
new file mode 100644
index 0000000..68c2fc1
--- /dev/null
+++ b/tests/CoreTests/android/graphics/ColorStateListTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.content.res.Resources;
+import android.content.res.ColorStateList;
+import android.test.AndroidTestCase;
+import android.core.R;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests of {@link android.graphics.ColorStateList}
+ */
+
+public class ColorStateListTest extends AndroidTestCase {
+
+ private Resources mResources;
+ private int mFailureColor;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = mContext.getResources();
+ mFailureColor = mResources.getColor(R.color.failColor);
+ }
+
+ @SmallTest
+ public void testStateIsInList() throws Exception {
+ ColorStateList colorStateList = mResources.getColorStateList(R.color.color1);
+ int[] focusedState = {android.R.attr.state_focused};
+ int focusColor = colorStateList.getColorForState(focusedState, R.color.failColor);
+ assertEquals(mResources.getColor(R.color.testcolor1), focusColor);
+ }
+
+ @SmallTest
+ public void testEmptyState() throws Exception {
+ ColorStateList colorStateList = mResources.getColorStateList(R.color.color1);
+ int[] emptyState = {};
+ int defaultColor = colorStateList.getColorForState(emptyState, mFailureColor);
+ assertEquals(mResources.getColor(R.color.testcolor2), defaultColor);
+ }
+
+ @SmallTest
+ public void testGetColor() throws Exception {
+ int defaultColor = mResources.getColor(R.color.color1);
+ assertEquals(mResources.getColor(R.color.testcolor2), defaultColor);
+ }
+
+ @SmallTest
+ public void testGetColorWhenListHasNoDefault() throws Exception {
+ int defaultColor = mResources.getColor(R.color.color_no_default);
+ assertEquals(mResources.getColor(R.color.testcolor1), defaultColor);
+ }
+}
diff --git a/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java
new file mode 100644
index 0000000..0d9f72e
--- /dev/null
+++ b/tests/CoreTests/android/graphics/drawable/StateListDrawableTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import junit.framework.TestCase;
+
+import android.R;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.util.StateSet;
+import android.view.MockView;
+
+/**
+ * Tests for StateListDrawable
+ *
+ */
+
+public class StateListDrawableTest extends TestCase {
+
+ private StateListDrawable slDrawable;
+ private MockDrawable mockFocusedDrawable;
+ private MockDrawable mockCheckedDrawable;
+ private MockView mockView;
+ private MockDrawable mockDefaultDrawable;
+
+
+ // Re-enable tests when we are running in the framework-test directory which allows
+ // access to package private access for MockView
+
+ public void broken_testFocusScenarioSetStringWildcardFirst() throws Exception {
+ int focusedStateSet[] = {R.attr.state_focused};
+ int checkedStateSet[] = {R.attr.state_checked};
+ slDrawable.addState(StateSet.WILD_CARD,
+ mockDefaultDrawable);
+ slDrawable.addState(checkedStateSet, mockCheckedDrawable);
+ slDrawable.addState(focusedStateSet, mockFocusedDrawable);
+ mockView.requestFocus();
+ mockView.getBackground().draw(null);
+ assertTrue(mockDefaultDrawable.wasDrawn);
+ }
+
+ public void broken_testFocusScenarioStateSetWildcardLast() throws Exception {
+ int focusedStateSet[] = {R.attr.state_focused};
+ int checkedStateSet[] = {R.attr.state_checked};
+ slDrawable.addState(checkedStateSet, mockCheckedDrawable);
+ slDrawable.addState(focusedStateSet, mockFocusedDrawable);
+ slDrawable.addState(StateSet.WILD_CARD,
+ mockDefaultDrawable);
+ mockView.requestFocus();
+ mockView.getBackground().draw(null);
+ assertTrue(mockFocusedDrawable.wasDrawn);
+ }
+
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ slDrawable = new StateListDrawable();
+ mockFocusedDrawable = new MockDrawable();
+ mockCheckedDrawable = new MockDrawable();
+ mockDefaultDrawable = new MockDrawable();
+ mockView = new MockView();
+ mockView.setBackgroundDrawable(slDrawable);
+ }
+
+ static class MockDrawable extends Drawable {
+
+ public boolean wasDrawn = false;
+
+ public void draw(Canvas canvas) {
+ wasDrawn = true;
+ }
+
+ public void setAlpha(int alpha) {
+ }
+
+ public void setColorFilter(ColorFilter cf) {
+ }
+
+ public int getOpacity() {
+ return android.graphics.PixelFormat.UNKNOWN;
+ }
+ }
+
+}
diff --git a/tests/CoreTests/android/location/LocationManagerProximityTest.java b/tests/CoreTests/android/location/LocationManagerProximityTest.java
new file mode 100644
index 0000000..e1501e3
--- /dev/null
+++ b/tests/CoreTests/android/location/LocationManagerProximityTest.java
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.location;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.location.Criteria;
+import android.location.Location;
+import android.location.LocationManager;
+import android.provider.Settings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Log;
+
+/**
+ * Tests for LocationManager.addProximityAlert
+ *
+ * TODO: add tests for more scenarios
+ *
+ * To run:
+ * adb shell am instrument -e class android.location.LocationManagerProximityTest \
+ * -w android.core/android.test.InstrumentationTestRunner
+ *
+ * This test requires that the "Allow mock locations" setting be enabled
+ *
+ */
+@MediumTest
+public class LocationManagerProximityTest extends AndroidTestCase {
+
+ private static final int UPDATE_LOCATION_WAIT_TIME = 1000;
+ private static final int PROXIMITY_WAIT_TIME = 2000;
+
+ private LocationManager mLocationManager;
+ private PendingIntent mPendingIntent;
+ private TestIntentReceiver mIntentReceiver;
+
+ private static final String LOG_TAG = "LocationProximityTest";
+
+ // use network provider as mock location provider, because:
+ // - proximity alert is hardcoded to listen to only network or gps
+ // - 'network' provider is not installed in emulator, so can mock it
+ // using test provider APIs
+ private static final String PROVIDER_NAME = LocationManager.NETWORK_PROVIDER;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // test that mock locations are allowed so a more descriptive error message can be logged
+ if (Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.ALLOW_MOCK_LOCATION, 0) == 0) {
+ fail("Mock locations are currently disabled in Settings - this test requires " +
+ "mock locations");
+ }
+
+ mLocationManager = (LocationManager) getContext().
+ getSystemService(Context.LOCATION_SERVICE);
+ if (mLocationManager.getProvider(PROVIDER_NAME) != null) {
+ mLocationManager.removeTestProvider(PROVIDER_NAME);
+ }
+
+ mLocationManager.addTestProvider(PROVIDER_NAME, true, //requiresNetwork,
+ false, // requiresSatellite,
+ true, // requiresCell,
+ false, // hasMonetaryCost,
+ false, // supportsAltitude,
+ false, // supportsSpeed, s
+ false, // upportsBearing,
+ Criteria.POWER_MEDIUM, // powerRequirement
+ Criteria.ACCURACY_FINE); // accuracy
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mLocationManager.removeTestProvider(PROVIDER_NAME);
+
+ if (mPendingIntent != null) {
+ mLocationManager.removeProximityAlert(mPendingIntent);
+ }
+ if (mIntentReceiver != null) {
+ getContext().unregisterReceiver(mIntentReceiver);
+ }
+ }
+
+ /**
+ * Tests basic proximity alert when entering proximity
+ */
+ public void testEnterProximity() throws Exception {
+ doTestEnterProximity(10000);
+ }
+
+ /**
+ * Tests proximity alert when entering proximity, with no expiration
+ */
+ public void testEnterProximity_noexpire() throws Exception {
+ doTestEnterProximity(-1);
+ }
+
+ /**
+ * Helper variant for testing enter proximity scenario
+ * TODO: add additional parameters as more scenarios are added
+ *
+ * @param expiration - expiry of proximity alert
+ */
+ private void doTestEnterProximity(long expiration) throws Exception {
+ // update location to outside proximity range
+ synchronousSendLocation(30, 30);
+ registerProximityListener(0, 0, 1000, expiration);
+ sendLocation(0, 0);
+ waitForAlert();
+ assertProximityType(true);
+ }
+
+ /**
+ * Tests basic proximity alert when exiting proximity
+ */
+ public void testExitProximity() throws Exception {
+ // first do enter proximity scenario
+ doTestEnterProximity(-1);
+
+ // now update to trigger exit proximity proximity
+ mIntentReceiver.clearReceivedIntents();
+ sendLocation(20, 20);
+ waitForAlert();
+ assertProximityType(false);
+ }
+
+ /**
+ * Registers the proximity intent receiver
+ */
+ private void registerProximityListener(double latitude, double longitude,
+ float radius, long expiration) {
+ String intentKey = "testProximity";
+ Intent proximityIntent = new Intent(intentKey);
+ mPendingIntent = PendingIntent.getBroadcast(getContext(), 0,
+ proximityIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+ mIntentReceiver = new TestIntentReceiver(intentKey);
+
+ mLocationManager.addProximityAlert(latitude, longitude, radius,
+ expiration, mPendingIntent);
+
+ getContext().registerReceiver(mIntentReceiver,
+ mIntentReceiver.getFilter());
+
+ }
+
+ /**
+ * Blocks until proximity intent notification is received
+ * @throws InterruptedException
+ */
+ private void waitForAlert() throws InterruptedException {
+ Log.d(LOG_TAG, "Waiting for proximity update");
+ synchronized (mIntentReceiver) {
+ mIntentReceiver.wait(PROXIMITY_WAIT_TIME);
+ }
+
+ assertNotNull("Did not receive proximity alert",
+ mIntentReceiver.getLastReceivedIntent());
+ }
+
+ /**
+ * Asserts that the received intent had the enter proximity property set as
+ * expected
+ * @param expectedEnterProximity - true if enter proximity expected, false if
+ * exit expected
+ */
+ private void assertProximityType(boolean expectedEnterProximity)
+ throws Exception {
+ boolean proximityTest = mIntentReceiver.getLastReceivedIntent().
+ getBooleanExtra(LocationManager.KEY_PROXIMITY_ENTERING,
+ !expectedEnterProximity);
+ assertEquals("proximity alert not set to expected enter proximity value",
+ expectedEnterProximity, proximityTest);
+ }
+
+ /**
+ * Synchronous variant of sendLocation
+ */
+ private void synchronousSendLocation(final double latitude,
+ final double longitude)
+ throws InterruptedException {
+ sendLocation(latitude, longitude, this);
+ // wait for location to be set
+ synchronized (this) {
+ wait(UPDATE_LOCATION_WAIT_TIME);
+ }
+ }
+
+ /**
+ * Asynchronously update the mock location provider without notification
+ */
+ private void sendLocation(final double latitude, final double longitude) {
+ sendLocation(latitude, longitude, null);
+ }
+
+ /**
+ * Asynchronously update the mock location provider with given latitude and
+ * longitude
+ *
+ * @param latitude - update location
+ * @param longitude - update location
+ * @param observer - optionally, object to notify when update is sent.If
+ * null, no update will be sent
+ */
+ private void sendLocation(final double latitude, final double longitude,
+ final Object observer) {
+ Thread locationUpdater = new Thread() {
+ @Override
+ public void run() {
+ Location loc = new Location(PROVIDER_NAME);
+ loc.setLatitude(latitude);
+ loc.setLongitude(longitude);
+
+ loc.setTime(java.lang.System.currentTimeMillis());
+ Log.d(LOG_TAG, "Sending update for " + PROVIDER_NAME);
+ mLocationManager.setTestProviderLocation(PROVIDER_NAME, loc);
+ if (observer != null) {
+ synchronized (observer) {
+ observer.notify();
+ }
+ }
+ }
+ };
+ locationUpdater.start();
+
+ }
+
+ /**
+ * Helper class that receives a proximity intent and notifies the main class
+ * when received
+ */
+ private static class TestIntentReceiver extends BroadcastReceiver {
+
+ private String mExpectedAction;
+ private Intent mLastReceivedIntent;
+
+ public TestIntentReceiver(String expectedAction) {
+ mExpectedAction = expectedAction;
+ mLastReceivedIntent = null;
+ }
+
+ public IntentFilter getFilter() {
+ IntentFilter filter = new IntentFilter(mExpectedAction);
+ return filter;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent != null && mExpectedAction.equals(intent.getAction())) {
+ Log.d(LOG_TAG, "Intent Received: " + intent.toString());
+ mLastReceivedIntent = intent;
+ synchronized (this) {
+ notify();
+ }
+ }
+ }
+
+ public Intent getLastReceivedIntent() {
+ return mLastReceivedIntent;
+ }
+
+ public void clearReceivedIntents() {
+ mLastReceivedIntent = null;
+ }
+ }
+}
diff --git a/tests/CoreTests/android/location/LocationTest.java b/tests/CoreTests/android/location/LocationTest.java
new file mode 100644
index 0000000..847ac7a
--- /dev/null
+++ b/tests/CoreTests/android/location/LocationTest.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2007 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.location;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.TestCase;
+
+/**
+ * Unit tests for android.location.Location
+ */
+@SmallTest
+public class LocationTest extends TestCase {
+
+ // ***** Tests for Location.convert
+ public void testConvert_DegreesToDouble(){
+ String testDegreesCoord = "-80.075";
+ String message;
+ double result;
+
+ result = Location.convert(testDegreesCoord);
+ message = "degreesToDoubleTest: Double should be -80.075, actual value is " +
+ String.valueOf(result);
+ assertEquals(message, -80.075, result);
+ }
+
+ public void testConvert_MinutesToDouble(){
+ String testMinutesCoord = "-80:05.10000";
+ String message;
+ double result;
+
+ result = Location.convert(testMinutesCoord);
+ message = "minutesToDoubleTest: Double should be -80.085, actual value is " +
+ String.valueOf(result);
+ assertEquals(message, -80.085, result);
+ }
+
+ public void testConvert_SecondsToDouble(){
+ String testSecondsCoord = "-80:04:03.00000";
+ String message;
+ double result;
+
+ result = Location.convert(testSecondsCoord);
+ message = "secondsToDoubleTest: Double should be -80.0675, actual value is " +
+ String.valueOf(result);
+ assertEquals(message, -80.0675, result);
+ }
+
+ public void testConvert_SecondsToDouble2(){
+ String testSecondsCoord = "-80:4:3";
+ String message;
+ double result;
+
+ result = Location.convert(testSecondsCoord);
+ message = "secondsToDouble2Test: Double should be -80.0675, actual value is " +
+ String.valueOf(result);
+ assertEquals(message, -80.0675, result);
+ }
+
+ // Testing the Convert(Double, Int)
+ public void testConvert_CoordinateToDegrees(){
+ String message;
+ String result;
+
+ result = Location.convert(-80.075, Location.FORMAT_DEGREES);
+ message = "coordinateToDegreesTest: Should return a string -80.075, but returned " + result;
+ assertEquals(message, "-80.075", result);
+ }
+
+ public void testConvert_CoordinateToDegrees2(){
+ String message;
+ String result;
+ result = Location.convert(-80.0, Location.FORMAT_DEGREES);
+ message = "coordinateToDegrees2Test: Should return a string -80, but returned " + result;
+ assertEquals(message, "-80", result);
+ }
+
+ public void testConvert_CoordinateToMinutes(){
+ String message;
+ String result;
+ double input = -80.085;
+ result = Location.convert(input, Location.FORMAT_MINUTES);
+ message = "coordinateToMinuteTest: Should return a string -80:5.1, but returned " +
+ result;
+ assertEquals(message, "-80:5.1", result);
+ }
+
+ public void testConvert_CoordinateToMinutes2(){
+ String message;
+ String result;
+ double input = -80;
+ result = Location.convert(input, Location.FORMAT_MINUTES);
+ message = "coordinateToMinute2Test: Should return a string -80:0, but returned " +
+ result;
+ assertEquals(message, "-80:0", result);
+ }
+
+ public void testConvert_CoordinateToSeconds(){
+ String message;
+ String result;
+
+ result = Location.convert(-80.075, Location.FORMAT_SECONDS);
+ message = "coordinateToSecondsTest: Should return a string -80:4:30, but returned " +
+ result;
+ assertEquals(message, "-80:4:30", result);
+ }
+ // **** end tests for Location.convert
+
+
+ public void testBearingTo(){
+ String message;
+ float bearing;
+ Location zeroLocation = new Location("");
+ zeroLocation.setLatitude(0);
+ zeroLocation.setLongitude(0);
+
+ Location testLocation = new Location("");
+ testLocation.setLatitude(1000000);
+ testLocation.setLongitude(0);
+
+ bearing = zeroLocation.bearingTo(zeroLocation);
+ message = "bearingToTest: Bearing should be 0, actual value is " + String.valueOf(bearing);
+ assertEquals(message, 0, bearing, 0);
+
+ bearing = zeroLocation.bearingTo(testLocation);
+ message = "bearingToTest: Bearing should be 180, actual value is " +
+ String.valueOf(bearing);
+ assertEquals(message, 180, bearing, 0);
+
+ testLocation.setLatitude(0);
+ testLocation.setLongitude(1000000);
+ bearing = zeroLocation.bearingTo(testLocation);
+ message = "bearingToTest: Bearing should be -90, actual value is " +
+ String.valueOf(bearing);
+ assertEquals(message, -90, bearing, 0);
+
+ //TODO: Test a Random Middle Value
+ }
+
+ public void testDistanceTo() {
+ String message;
+ boolean result = true;
+ float distance;
+ Location zeroLocation = new Location("");
+ zeroLocation.setLatitude(0);
+ zeroLocation.setLongitude(0);
+
+ Location testLocation = new Location("");
+ testLocation.setLatitude(1000000);
+ testLocation.setLongitude(0);
+
+ distance = zeroLocation.distanceTo(zeroLocation);
+ message = "distanceToTest: Distance should be 0, actual value is " +
+ String.valueOf(distance);
+ assertEquals(message, distance, 0, 0);
+
+ distance = zeroLocation.distanceTo(testLocation);
+ message = "distanceToTest: Distance should be 8885140, actual value is " +
+ String.valueOf(distance);
+ assertEquals(message, distance, 8885140.0, 1);
+ }
+
+ public void testAltitude() {
+ String message;
+ Location loc = new Location("");
+
+ loc.setAltitude(1);
+ message = "altitudeTest: set/getAltitude to 1 didn't work.";
+ assertEquals(message, loc.getAltitude(), 1, 0);
+ message = "altitudeTest: hasAltitude (a) didn't work.";
+ assertTrue(message, loc.hasAltitude());
+
+ loc.removeAltitude();
+ message = "altitudeTest: hasAltitude (b) didn't work.";
+ assertFalse(message, loc.hasAltitude());
+ message = "altitudeTest: getAltitude didn't return 0 when there was no altitude.";
+ assertEquals(message, loc.getAltitude(), 0, 0);
+ }
+
+ public void testSpeed() {
+ String message;
+ Location loc = new Location("");
+
+ loc.setSpeed(1);
+ message = "speedTest: set/getSpeed to 1 didn't work.";
+ assertEquals(message, loc.getSpeed(), 1, 0);
+ message = "speedTest: hasSpeed (a) didn't work.";
+ assertTrue(message, loc.hasSpeed());
+
+ loc.removeSpeed();
+ message = "speedTest: hasSpeed (b) didn't work.";
+ assertFalse(message, loc.hasSpeed());
+ message = "speedTest: getSpeed didn't return 0 when there was no speed.";
+ assertEquals(message, loc.getSpeed(), 0, 0);
+ }
+
+ public void testBearing() {
+ String message;
+ Location loc = new Location("");
+
+ loc.setBearing(1);
+ message = "bearingTest: set/getBearing to 1 didn't work.";
+ assertEquals(message, loc.getBearing(), 1, 0);
+ message = "bearingTest: hasBearing (a) didn't work.";
+ assertTrue(message, loc.hasBearing());
+
+ loc.removeBearing();
+ message = "bearingTest: hasBearing (b) didn't work.";
+ assertFalse(message, loc.hasBearing());
+ message = "bearingTest: getBearing didn't return 0 when there was no bearing.";
+ assertEquals(message, loc.getBearing(), 0, 0);
+ }
+
+}
+
+
diff --git a/tests/CoreTests/android/res/color/color1.xml b/tests/CoreTests/android/res/color/color1.xml
new file mode 100644
index 0000000..87034fa
--- /dev/null
+++ b/tests/CoreTests/android/res/color/color1.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:color="@color/testcolor1"/>
+ <item android:color="@color/testcolor2"/>
+</selector>
diff --git a/tests/CoreTests/android/res/color/color_no_default.xml b/tests/CoreTests/android/res/color/color_no_default.xml
new file mode 100644
index 0000000..41a9b5d
--- /dev/null
+++ b/tests/CoreTests/android/res/color/color_no_default.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:state_focused="true" android:color="@color/testcolor1"/>
+</selector>
diff --git a/tests/CoreTests/android/res/values/colors.xml b/tests/CoreTests/android/res/values/colors.xml
new file mode 100644
index 0000000..7559e65
--- /dev/null
+++ b/tests/CoreTests/android/res/values/colors.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2006, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+ <color name="testcolor1">#ff00ff00</color>
+ <color name="testcolor2">#ffff0000</color>
+ <color name="failColor">#ff0000ff</color>
+</resources>
+
diff --git a/tests/CoreTests/android/test/AndroidTestRunnerTest.java b/tests/CoreTests/android/test/AndroidTestRunnerTest.java
new file mode 100644
index 0000000..0574704
--- /dev/null
+++ b/tests/CoreTests/android/test/AndroidTestRunnerTest.java
@@ -0,0 +1,294 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.TestCase;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import junit.framework.TestListener;
+
+import java.util.List;
+import java.util.Arrays;
+
+/**
+ * Unit tests for {@link AndroidTestRunner}
+ */
+@SmallTest
+public class AndroidTestRunnerTest extends TestCase {
+ private AndroidTestRunner mAndroidTestRunner;
+ private StubContext mStubContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mStubContext = new StubContext(getClass().getClassLoader());
+
+ mAndroidTestRunner = new AndroidTestRunner();
+ mAndroidTestRunner.setContext(mStubContext);
+ }
+
+ public void testLoadNoTestCases() throws Exception {
+ mAndroidTestRunner.setTestClassName(TestSuite.class.getName(), null);
+
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ assertNotNull(testCases);
+ assertEquals(1, testCases.size());
+ assertEquals("warning", testCases.get(0).getName());
+ assertEquals(TestSuite.class.getSimpleName(), mAndroidTestRunner.getTestClassName());
+ }
+
+ public void testSetTestSuiteWithOneTestCase() throws Exception {
+ mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ assertNotNull(testCases);
+ assertEquals(1, testCases.size());
+ assertEquals("testOne", testCases.get(0).getName());
+ assertEquals(OneTestTestCase.class.getSimpleName(), mAndroidTestRunner.getTestClassName());
+ }
+
+ public void testRunTest() throws Exception {
+ mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+ TestListenerStub testListenerStub = new TestListenerStub();
+ mAndroidTestRunner.addTestListener(testListenerStub);
+
+ mAndroidTestRunner.runTest();
+
+ assertTrue(testListenerStub.saw("testOne"));
+ }
+
+ public void testRunTestWithAndroidTestCase() throws Exception {
+ mAndroidTestRunner.setTestClassName(
+ OneAndroidTestTestCase.class.getName(), "testOneAndroid");
+
+ TestListenerStub testListenerStub = new TestListenerStub();
+ mAndroidTestRunner.addTestListener(testListenerStub);
+
+ assertNull(((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext());
+
+ mAndroidTestRunner.runTest();
+
+ assertTrue(testListenerStub.saw("testOneAndroid"));
+ assertSame(mStubContext,
+ ((AndroidTestCase) mAndroidTestRunner.getTestCases().get(0)).getContext());
+ }
+
+ public void testRunTestWithAndroidTestCaseInSuite() throws Exception {
+ mAndroidTestRunner.setTestClassName(OneAndroidTestTestCase.class.getName(), null);
+
+ TestListenerStub testListenerStub = new TestListenerStub();
+ mAndroidTestRunner.addTestListener(testListenerStub);
+
+ mAndroidTestRunner.runTest();
+
+ assertTrue(testListenerStub.saw("testOneAndroid"));
+
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ for (TestCase testCase : testCases) {
+ assertSame(mStubContext, ((AndroidTestCase) testCase).getContext());
+ }
+ }
+
+ public void testRunTestWithAndroidTestCaseInNestedSuite() throws Exception {
+ mAndroidTestRunner.setTestClassName(AndroidTestCaseTestSuite.class.getName(), null);
+
+ TestListenerStub testListenerStub = new TestListenerStub();
+ mAndroidTestRunner.addTestListener(testListenerStub);
+
+ mAndroidTestRunner.runTest();
+
+ assertTrue(testListenerStub.saw("testOneAndroid"));
+
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ for (TestCase testCase : testCases) {
+ assertSame(mStubContext, ((AndroidTestCase) testCase).getContext());
+ }
+ }
+
+ public void testRunTestWithNullListener() throws Exception {
+ mAndroidTestRunner.setTestClassName(OneTestTestCase.class.getName(), null);
+
+ mAndroidTestRunner.addTestListener(null);
+ try {
+ mAndroidTestRunner.runTest();
+ } catch (NullPointerException e) {
+ fail("Should not add a null TestListener");
+ }
+ }
+
+ public void testSetTestClassWithTestSuiteProvider() throws Exception {
+ mAndroidTestRunner.setTestClassName(SampleTestSuiteProvider.class.getName(), null);
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ List<String> testNames = Lists.newArrayList();
+ for (TestCase testCase : testCases) {
+ testNames.add(testCase.getName());
+ }
+
+ // Use the test suite provided by the interface method rather than the static suite method.
+ assertEquals(Arrays.asList("testOne"), testNames);
+ }
+
+ public void testSetTestClassWithTestSuite() throws Exception {
+ mAndroidTestRunner.setTestClassName(SampleTestSuite.class.getName(), null);
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ List<String> testNames = Lists.newArrayList();
+ for (TestCase testCase : testCases) {
+ testNames.add(testCase.getName());
+ }
+ assertEquals(Arrays.asList("testOne", "testOne", "testTwo"), testNames);
+ }
+
+ public void testRunSingleTestMethod() throws Exception {
+ String testMethodName = "testTwo";
+ mAndroidTestRunner.setTestClassName(TwoTestTestCase.class.getName(), testMethodName);
+ List<TestCase> testCases = mAndroidTestRunner.getTestCases();
+ List<String> testNames = Lists.newArrayList();
+ for (TestCase testCase : testCases) {
+ testNames.add(testCase.getName());
+ }
+ assertEquals(Arrays.asList(testMethodName), testNames);
+ }
+
+ public void testSetTestClassInvalidClass() throws Exception {
+ try {
+ mAndroidTestRunner.setTestClassName("class.that.does.not.exist", null);
+ fail("expected exception not thrown");
+ } catch (RuntimeException e) {
+ // expected
+ }
+ }
+
+ public void testRunSkipExecution() throws Exception {
+ String testMethodName = "testFail";
+ mAndroidTestRunner.setTestClassName(
+ OnePassOneErrorOneFailTestCase.class.getName(), testMethodName);
+
+ TestListenerStub testListenerStub = new TestListenerStub();
+ mAndroidTestRunner.addTestListener(testListenerStub);
+
+ // running the failing test should pass - ie as if its not run
+ mAndroidTestRunner.runTest();
+
+ assertTrue(testListenerStub.saw("testFail"));
+ }
+
+ public static class SampleTestSuiteProvider implements TestSuiteProvider {
+
+ public TestSuite getTestSuite() {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(OneTestTestCase.class);
+ return testSuite;
+ }
+
+ public static Test suite() {
+ return SampleTestSuite.suite();
+ }
+ }
+
+ public static class SampleTestSuite {
+ public static TestSuite suite() {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(OneTestTestCase.class);
+ testSuite.addTestSuite(TwoTestTestCase.class);
+ return testSuite;
+ }
+ }
+
+ public static class AndroidTestCaseTestSuite {
+ public static TestSuite suite() {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(OneAndroidTestTestCase.class);
+ return testSuite;
+ }
+ }
+
+ public static class OneAndroidTestTestCase extends AndroidTestCase {
+ public void testOneAndroid() throws Exception {
+ }
+ }
+
+ public static class OneTestTestCase extends TestCase {
+ public void testOne() throws Exception {
+ }
+ }
+
+ public static class TwoTestTestCase extends TestCase {
+ public void testOne() throws Exception {
+ }
+
+ public void testTwo() throws Exception {
+ }
+ }
+
+ public static class OnePassOneErrorOneFailTestCase extends TestCase {
+ public void testPass() throws Exception {
+ }
+
+ public void testError() throws Exception {
+ throw new Exception();
+ }
+
+ public void testFail() throws Exception {
+ fail();
+ }
+ }
+
+ private static class TestListenerStub implements TestListener {
+ List<String> testNames = Lists.newArrayList();
+
+ public void addError(Test test, Throwable t) {
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ }
+
+ public void endTest(Test test) {
+ }
+
+ public void startTest(Test test) {
+ if (test instanceof TestCase) {
+ testNames.add(((TestCase) test).getName());
+ } else if (test instanceof TestSuite) {
+ testNames.add(((TestSuite) test).getName());
+ }
+ }
+
+ public boolean saw(String testName) {
+ return testNames.contains(testName);
+ }
+ }
+
+ private static class StubContext extends MockContext {
+ private ClassLoader mClassLoader;
+
+ public StubContext(ClassLoader classLoader) {
+ this.mClassLoader = classLoader;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return mClassLoader;
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
new file mode 100644
index 0000000..d9afd54
--- /dev/null
+++ b/tests/CoreTests/android/test/InstrumentationTestRunnerTest.java
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.content.Context;
+import android.os.Bundle;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.ListTestCaseNames;
+import android.test.suitebuilder.ListTestCaseNames.TestDescriptor;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+/**
+ * Tests for {@link InstrumentationTestRunner}
+ */
+@SmallTest
+public class InstrumentationTestRunnerTest extends TestCase {
+ private StubInstrumentationTestRunner mInstrumentationTestRunner;
+ private StubAndroidTestRunner mStubAndroidTestRunner;
+ private String mTargetContextPackageName;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mStubAndroidTestRunner = new StubAndroidTestRunner();
+ mTargetContextPackageName = "android.test.suitebuilder.examples";
+ mInstrumentationTestRunner = new StubInstrumentationTestRunner(
+ new StubContext("com.google.foo.tests"),
+ new StubContext(mTargetContextPackageName), mStubAndroidTestRunner);
+ }
+
+ public void testOverrideTestToRunWithClassArgument() throws Exception {
+ String expectedTestClassName = PlaceHolderTest.class.getName();
+ mInstrumentationTestRunner.onCreate(createBundle(
+ InstrumentationTestRunner.ARGUMENT_TEST_CLASS, expectedTestClassName));
+
+ assertTestRunnerCalledWithExpectedParameters(expectedTestClassName, "testPlaceHolder");
+ }
+
+ public void testOverrideTestToRunWithClassAndMethodArgument() throws Exception {
+ String expectedTestClassName = PlaceHolderTest.class.getName();
+ String expectedTestMethodName = "testPlaceHolder";
+ String classAndMethod = expectedTestClassName + "#" + expectedTestMethodName;
+ mInstrumentationTestRunner.onCreate(createBundle(
+ InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classAndMethod));
+
+ assertTestRunnerCalledWithExpectedParameters(expectedTestClassName,
+ expectedTestMethodName);
+ }
+
+ public void testUseSelfAsTestSuiteProviderWhenNoMetaDataOrClassArgument() throws Exception {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(PlaceHolderTest.class);
+ mInstrumentationTestRunner.setAllTestsSuite(testSuite);
+ mInstrumentationTestRunner.onCreate(null);
+ assertTestRunnerCalledWithExpectedParameters(
+ PlaceHolderTest.class.getName(), "testPlaceHolder");
+ }
+
+ public void testMultipleTestClass() throws Exception {
+ String classArg = PlaceHolderTest.class.getName() + "," +
+ PlaceHolderTest2.class.getName();
+ mInstrumentationTestRunner.onCreate(createBundle(
+ InstrumentationTestRunner.ARGUMENT_TEST_CLASS, classArg));
+
+ Test test = mStubAndroidTestRunner.getTest();
+
+ assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test),
+ new TestDescriptor(PlaceHolderTest.class.getName(), "testPlaceHolder"),
+ new TestDescriptor(PlaceHolderTest2.class.getName(), "testPlaceHolder2"));
+
+ }
+
+ public void testDelayParameter() throws Exception {
+ int delayMsec = 1000;
+ Bundle args = new Bundle();
+ args.putInt(InstrumentationTestRunner.ARGUMENT_DELAY_MSEC, delayMsec);
+ args.putString(InstrumentationTestRunner.ARGUMENT_TEST_CLASS,
+ PlaceHolderTest.class.getName() + "," +
+ PlaceHolderTest2.class.getName());
+ mInstrumentationTestRunner.onCreate(args);
+ Thread t = new Thread() { public void run() { mInstrumentationTestRunner.onStart(); } };
+
+ // Should delay three times: before, between, and after the two tests.
+ long beforeTest = System.currentTimeMillis();
+ t.start();
+ t.join();
+ assertTrue(System.currentTimeMillis() > beforeTest + delayMsec * 3);
+ assertTrue(mInstrumentationTestRunner.isStarted());
+ assertTrue(mInstrumentationTestRunner.isFinished());
+ assertTrue(mStubAndroidTestRunner.isRun());
+ }
+
+ private void assertContentsInOrder(List<TestDescriptor> actual, TestDescriptor... source) {
+ TestDescriptor[] clonedSource = source.clone();
+ assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
+ for (int i = 0; i < actual.size(); i++) {
+ TestDescriptor actualItem = actual.get(i);
+ TestDescriptor sourceItem = clonedSource[i];
+ assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem);
+ }
+ }
+
+ private void assertTestRunnerCalledWithExpectedParameters(
+ String expectedTestClassName, String expectedTestMethodName) {
+ Test test = mStubAndroidTestRunner.getTest();
+ assertContentsInOrder(ListTestCaseNames.getTestNames((TestSuite) test),
+ new TestDescriptor(expectedTestClassName, expectedTestMethodName));
+ assertTrue(mInstrumentationTestRunner.isStarted());
+ assertFalse(mInstrumentationTestRunner.isFinished());
+ }
+
+ private Bundle createBundle(String key, String value) {
+ Bundle bundle = new Bundle();
+ bundle.putString(key, value);
+ return bundle;
+ }
+
+ private static class StubInstrumentationTestRunner extends InstrumentationTestRunner {
+ private Context mContext;
+ private Context mTargetContext;
+ private boolean mStarted;
+ private boolean mFinished;
+ private AndroidTestRunner mAndroidTestRunner;
+ private TestSuite mTestSuite;
+ private TestSuite mDefaultTestSuite;
+ private String mPackageNameForDefaultTests;
+
+ public StubInstrumentationTestRunner(Context context, Context targetContext,
+ AndroidTestRunner androidTestRunner) {
+ this.mContext = context;
+ this.mTargetContext = targetContext;
+ this.mAndroidTestRunner = androidTestRunner;
+ }
+
+ public Context getContext() {
+ return mContext;
+ }
+
+ public TestSuite getAllTests() {
+ return mTestSuite;
+ }
+
+ public Context getTargetContext() {
+ return mTargetContext;
+ }
+
+ protected AndroidTestRunner getAndroidTestRunner() {
+ return mAndroidTestRunner;
+ }
+
+ public void start() {
+ mStarted = true;
+ }
+
+ public void finish(int resultCode, Bundle results) {
+ mFinished = true;
+ }
+
+ public boolean isStarted() {
+ return mStarted;
+ }
+
+ public boolean isFinished() {
+ return mFinished;
+ }
+
+ public void setAllTestsSuite(TestSuite testSuite) {
+ mTestSuite = testSuite;
+ }
+
+ public void setDefaultTestsSuite(TestSuite testSuite) {
+ mDefaultTestSuite = testSuite;
+ }
+
+ public String getPackageNameForDefaultTests() {
+ return mPackageNameForDefaultTests;
+ }
+ }
+
+ private static class StubContext extends MockContext {
+ private String mPackageName;
+
+ public StubContext(String packageName) {
+ this.mPackageName = packageName;
+ }
+
+ @Override
+ public String getPackageCodePath() {
+ return mPackageName;
+ }
+
+ @Override
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ @Override
+ public ClassLoader getClassLoader() {
+ return getClass().getClassLoader();
+ }
+ }
+
+ private static class StubAndroidTestRunner extends AndroidTestRunner {
+ private Test mTest;
+ private boolean mRun;
+
+ public boolean isRun() {
+ return mRun;
+ }
+
+ public void setTest(Test test) {
+ super.setTest(test);
+ mTest = test;
+ }
+
+ public Test getTest() {
+ return mTest;
+ }
+
+ public void runTest() {
+ super.runTest();
+ mRun = true;
+ }
+ }
+
+ /**
+ * Empty test used for validation
+ */
+ public static class PlaceHolderTest extends TestCase {
+
+ public PlaceHolderTest() {
+ super("testPlaceHolder");
+ }
+
+ public void testPlaceHolder() throws Exception {
+
+ }
+ }
+
+ /**
+ * Empty test used for validation
+ */
+ public static class PlaceHolderTest2 extends TestCase {
+
+ public PlaceHolderTest2() {
+ super("testPlaceHolder2");
+ }
+
+ public void testPlaceHolder2() throws Exception {
+
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/StubTestBrowserActivity.java b/tests/CoreTests/android/test/StubTestBrowserActivity.java
new file mode 100644
index 0000000..97ed3ce
--- /dev/null
+++ b/tests/CoreTests/android/test/StubTestBrowserActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import junit.framework.TestSuite;
+
+public class StubTestBrowserActivity extends TestBrowserActivity {
+
+ private static TestSuite mTestSuite;
+
+ static void setTopTestSuite(TestSuite testSuite) {
+ mTestSuite = testSuite;
+ }
+
+ @Override
+ public TestSuite getTopTestSuite() {
+ return mTestSuite;
+ }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserActivityTest.java b/tests/CoreTests/android/test/TestBrowserActivityTest.java
new file mode 100644
index 0000000..6afbe37
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserActivityTest.java
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.view.IWindowManager;
+import android.widget.ListView;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class TestBrowserActivityTest extends InstrumentationTestCase {
+
+ private TestBrowserActivity mTestBrowserActivity;
+ private StubTestBrowserController mTestBrowserController;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ StubTestBrowserActivity.setTopTestSuite(null);
+ mTestBrowserController = new StubTestBrowserController();
+ ServiceLocator.setTestBrowserController(mTestBrowserController);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mTestBrowserActivity != null) {
+ mTestBrowserActivity.finish();
+ }
+ mTestBrowserActivity = null;
+ super.tearDown();
+ }
+
+ public void testEmptyListContent() throws Exception {
+ StubTestBrowserActivity.setTopTestSuite(new TestSuite());
+
+ mTestBrowserActivity = createActivity();
+
+ ListView listView = getListView();
+ // There is always an item on the list for running all tests.
+ assertEquals("Unexpected number of items on list view.", 1, listView.getCount());
+
+ assertEquals("Stubbed Test Browser", mTestBrowserActivity.getTitle().toString());
+ }
+
+ public void testOneListContent() throws Exception {
+ List<String> testCaseNames = Lists.newArrayList("AllTests");
+ StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+ mTestBrowserActivity = createActivity();
+
+ ListView listView = getListView();
+ assertListViewContents(testCaseNames, listView);
+ }
+
+ public void testListWithTestCases() throws Exception {
+ List<String> testCaseNames = Lists.newArrayList("AllTests", "Apples", "Bananas", "Oranges");
+ StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+ mTestBrowserActivity = createActivity();
+
+ ListView listView = getListView();
+ assertListViewContents(testCaseNames, listView);
+ }
+
+ public void testListWithTestSuite() throws Exception {
+ List<String> testCaseNames = Lists.newArrayList(OneTestTestCase.class.getSimpleName());
+ StubTestBrowserActivity.setTopTestSuite(new OneTestInTestSuite());
+
+ mTestBrowserActivity = createActivity();
+
+ ListView listView = getListView();
+ assertListViewContents(testCaseNames, listView);
+ }
+
+ public void testSelectATestCase() throws Exception {
+ List<String> testCaseNames = Lists.newArrayList("AllTests");
+ TestSuite testSuite = createTestSuite(testCaseNames);
+ StubTestBrowserActivity.setTopTestSuite(testSuite);
+
+ mTestBrowserController.setTestCase(OneTestTestCase.class);
+ mTestBrowserActivity = createActivity();
+
+ Instrumentation.ActivityMonitor activityMonitor = getInstrumentation().addMonitor(
+ TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME, null, false);
+ try {
+ assertEquals(0, activityMonitor.getHits());
+
+ ListView listView = getListView();
+ int invokedTestCaseIndex = 0;
+ listView.performItemClick(listView, invokedTestCaseIndex, 0);
+
+ Activity activity = activityMonitor.waitForActivityWithTimeout(2000);
+ assertNotNull(activity);
+ try {
+ assertEquals(1, activityMonitor.getHits());
+ assertEquals(invokedTestCaseIndex, mTestBrowserController.getLastPosition());
+ } finally {
+ activity.finish();
+ }
+ } finally {
+ getInstrumentation().removeMonitor(activityMonitor);
+ }
+ }
+
+ public void testCreateFromIntentWithOneTest() throws Exception {
+ List<String> testCaseNames = Lists.newArrayList("testOne");
+
+ mTestBrowserActivity = launchTestBrowserActivity(new TestSuite(OneTestTestCase.class));
+
+ ListView listView = getListView();
+ assertListViewContents(testCaseNames, listView);
+ }
+
+ public void testUpdateListOnStart() throws Exception {
+ StubTestBrowserActivity.setTopTestSuite(new TestSuite());
+
+ mTestBrowserActivity = createActivity();
+
+ ListView listView = getListView();
+ assertEquals("Unexpected number of items on list view.", 1, listView.getCount());
+
+ List<String> testCaseNames = Lists.newArrayList("AllTests");
+ StubTestBrowserActivity.setTopTestSuite(createTestSuite(testCaseNames));
+
+ getInstrumentation().runOnMainSync(new Runnable() {
+ public void run() {
+ ((StubTestBrowserActivity) mTestBrowserActivity).onStart();
+ }
+ });
+
+ listView = getListView();
+ assertListViewContents(testCaseNames, listView);
+ }
+
+ public void testTitleHasTestSuiteName() throws Exception {
+ final String testSuiteName = "com.android.TestSuite";
+ StubTestBrowserActivity.setTopTestSuite(new TestSuite(testSuiteName));
+
+ mTestBrowserActivity = createActivity();
+
+ assertEquals("TestSuite", mTestBrowserActivity.getTitle().toString());
+ }
+
+ private TestSuite createTestSuite(List<String> testCaseNames) {
+ return createTestSuite(testCaseNames.toArray(new String[testCaseNames.size()]));
+ }
+
+ private TestSuite createTestSuite(String... testCaseNames) {
+ TestSuite testSuite = new TestSuite();
+ for (String testCaseName : testCaseNames) {
+ testSuite.addTest(new FakeTestCase(testCaseName));
+ }
+
+ return testSuite;
+ }
+
+ public static class FakeTestCase extends TestCase {
+ public FakeTestCase(String name) {
+ super(name);
+ }
+ }
+
+ public static class OneTestTestCase extends TestCase {
+ public void testOne() throws Exception {
+ }
+ }
+
+ public static class OneTestInTestSuite extends TestSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite(OneTestInTestSuite.class.getName());
+ suite.addTestSuite(OneTestTestCase.class);
+ return suite;
+ }
+ }
+
+ private void assertListViewContents(List<String> expectedTestCaseNames, ListView listView) {
+ assertEquals("Run All", listView.getItemAtPosition(0).toString());
+ assertEquals("Unexpected number of items on list view.",
+ expectedTestCaseNames.size() + 1, listView.getCount());
+ for (int i = 0; i < expectedTestCaseNames.size(); i++) {
+ String expectedTestCaseName = expectedTestCaseNames.get(i);
+ String actualTestCaseName = listView.getItemAtPosition(i + 1).toString();
+ assertEquals("Unexpected test case name. Index: " + i,
+ expectedTestCaseName, actualTestCaseName);
+ }
+ }
+
+ private ListView getListView() {
+ return mTestBrowserActivity.getListView();
+ }
+
+ private TestBrowserActivity createActivity() throws RemoteException {
+ return launchActivity("android.test", StubTestBrowserActivity.class, null);
+ }
+
+ private Intent createIntent(TestSuite testSuite) {
+ Intent intent = new Intent(Intent.ACTION_RUN);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ String className = StubTestBrowserActivity.class.getName();
+ String packageName = className.substring(0, className.lastIndexOf("."));
+ intent.setClassName(packageName, className);
+ intent.setData(Uri.parse(testSuite.getName()));
+ return intent;
+ }
+
+ private TestBrowserActivity launchTestBrowserActivity(TestSuite testSuite)
+ throws RemoteException {
+ getInstrumentation().setInTouchMode(false);
+
+ TestBrowserActivity activity =
+ (TestBrowserActivity) getInstrumentation().startActivitySync(
+ createIntent(testSuite));
+ getInstrumentation().waitForIdleSync();
+ return activity;
+ }
+
+ private static class StubTestBrowserController extends TestBrowserControllerImpl {
+ private int mPosition;
+ private Class<? extends TestCase> mTestCaseClass;
+
+ public Intent getIntentForTestAt(int position) {
+ mPosition = position;
+
+ Intent intent = new Intent();
+ intent.setAction(Intent.ACTION_RUN);
+
+ String className = TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME;
+ String testName = mTestCaseClass.getClass().getName();
+
+ String packageName = className.substring(0, className.lastIndexOf("."));
+ intent.setClassName(packageName, className);
+ intent.setData(Uri.parse(testName));
+
+ return intent;
+ }
+
+ public void setTestCase(Class<? extends TestCase> testCaseClass) {
+ mTestCaseClass = testCaseClass;
+ }
+
+ public int getLastPosition() {
+ return mPosition;
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserControllerImplTest.java b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java
new file mode 100644
index 0000000..1315606
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserControllerImplTest.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import android.content.Intent;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class TestBrowserControllerImplTest extends TestCase {
+ private TestBrowserControllerImpl mTestBrowserController;
+ private TestBrowserViewStub mTestBrowserView;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTestBrowserController = new TestBrowserControllerImpl();
+ mTestBrowserView = new TestBrowserViewStub();
+ mTestBrowserController.registerView(mTestBrowserView);
+ }
+
+ public void testSetTestSuite() throws Exception {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(DummyTestCase.class);
+
+ mTestBrowserController.setTestSuite(testSuite);
+
+ verifyTestNames(Arrays.asList("Run All", DummyTestCase.class.getSimpleName()),
+ mTestBrowserView.getTestNames());
+ }
+
+ private static void verifyTestNames(List<String> expectedTestNames,
+ List<String> actualTestNames) {
+ assertEquals(expectedTestNames.size(), actualTestNames.size());
+
+ // We use endsWith instead of equals because the return value of
+ // class.getSimpleName(), when called on an inner class, varies
+ // from one vm to another.
+ // This allows the test to pass in multiple environments.
+ for (int i = 0; i < expectedTestNames.size(); i++) {
+ assertTrue(actualTestNames.get(i).endsWith(expectedTestNames.get(i)));
+ }
+ }
+
+ public void testGetIntentForTestSuite() throws Exception {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTestSuite(DummyTestCase.class);
+
+ String targetBrowserActvityClassName = "com.android.bogus.DummyActivity";
+ String expectedTargetPackageName = "com.android.bogus";
+ mTestBrowserController.setTargetBrowserActivityClassName(targetBrowserActvityClassName);
+ mTestBrowserController.setTestSuite(testSuite);
+ mTestBrowserController.setTargetPackageName(expectedTargetPackageName);
+ Intent intent = mTestBrowserController.getIntentForTestAt(1);
+ verifyIntent(intent, DummyTestCase.class, expectedTargetPackageName);
+ assertEquals(targetBrowserActvityClassName, intent.getComponent().getClassName());
+ }
+
+ public void testGetIntentForTestCase() throws Exception {
+ TestSuite testSuite = new TestSuite();
+ testSuite.addTest(new DummyTestCase());
+
+ mTestBrowserController.setTestSuite(testSuite);
+ Intent intent = mTestBrowserController.getIntentForTestAt(1);
+ verifyIntent(intent, DummyTestCase.class, "com.android.testharness");
+ assertEquals(TestBrowserControllerImpl.TEST_RUNNER_ACTIVITY_CLASS_NAME,
+ intent.getComponent().getClassName());
+ assertEquals("testDummyTest",
+ intent.getStringExtra(TestBrowserController.BUNDLE_EXTRA_TEST_METHOD_NAME));
+ }
+
+ public void testGetIntentForRunAll() throws Exception {
+ TestSuite testSuite = new DummyTestSuite();
+ testSuite.addTestSuite(DummyTestCase.class);
+
+ mTestBrowserController.setTestSuite(testSuite);
+ Intent intent = mTestBrowserController.getIntentForTestAt(0);
+ verifyIntent(intent, DummyTestSuite.class, "com.android.testharness");
+ }
+
+ private static void verifyIntent(Intent intent, Class testClass, String expectedPackageName) {
+ assertEquals(Intent.ACTION_RUN, intent.getAction());
+ assertEquals(Intent.FLAG_ACTIVITY_NEW_TASK,
+ intent.getFlags() & Intent.FLAG_ACTIVITY_NEW_TASK);
+ assertEquals(Intent.FLAG_ACTIVITY_MULTIPLE_TASK,
+ intent.getFlags() & Intent.FLAG_ACTIVITY_MULTIPLE_TASK);
+ assertEquals(testClass.getName(), intent.getData().toString());
+ assertEquals(expectedPackageName, intent.getComponent().getPackageName());
+ }
+
+ private static class DummyTestSuite extends TestSuite {
+ private DummyTestSuite() {
+ super(DummyTestSuite.class.getName());
+ }
+ }
+
+ private static class DummyTestCase extends TestCase {
+ private DummyTestCase() {
+ super("testDummyTest");
+ }
+
+ public void testDummyTest() throws Exception {
+ }
+ }
+
+ private class TestBrowserViewStub implements TestBrowserView {
+ private List<String> mTestNames;
+
+ public void setTestNames(List<String> testNames) {
+ mTestNames = testNames;
+ }
+
+ public List<String> getTestNames() {
+ return mTestNames;
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/TestBrowserTests.java b/tests/CoreTests/android/test/TestBrowserTests.java
new file mode 100644
index 0000000..535e2f8
--- /dev/null
+++ b/tests/CoreTests/android/test/TestBrowserTests.java
@@ -0,0 +1,22 @@
+// Copyright 2007 The Android Open Source Project
+
+
+package android.test;
+
+import junit.framework.TestSuite;
+
+public class TestBrowserTests extends TestBrowserActivity {
+
+ @Override
+ public TestSuite getTopTestSuite() {
+ return suite();
+ }
+
+ public static TestSuite suite() {
+ TestSuite testSuite = new TestSuite(TestBrowserTests.class.getName());
+ testSuite.addTestSuite(TestBrowserControllerImplTest.class);
+ testSuite.addTestSuite(TestCaseUtilTest.class);
+
+ return testSuite;
+ }
+}
diff --git a/tests/CoreTests/android/test/TestCaseUtilTest.java b/tests/CoreTests/android/test/TestCaseUtilTest.java
new file mode 100644
index 0000000..bc6fa92
--- /dev/null
+++ b/tests/CoreTests/android/test/TestCaseUtilTest.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class TestCaseUtilTest extends TestCase {
+
+ public void testGetTestCaseNamesForTestSuiteWithSuiteMethod() throws Exception {
+ TestSuite testSuite = new TwoTestsInTestSuite();
+
+ List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testSuite, false);
+
+ assertEquals(2, testCaseNames.size());
+ assertTrue(testCaseNames.get(0).endsWith("OneTestTestCase"));
+ assertTrue(testCaseNames.get(1).endsWith("OneTestTestSuite"));
+ }
+
+ public void testGetTestCaseNamesForTestCaseWithSuiteMethod() throws Exception {
+ TestCase testCase = new OneTestTestCaseWithSuite();
+
+ List<String> testCaseNames = TestCaseUtil.getTestCaseNames(testCase, false);
+
+ assertEquals(1, testCaseNames.size());
+ assertTrue(testCaseNames.get(0).endsWith("testOne"));
+ }
+
+ public void testCreateTestForTestCase() throws Exception {
+ Test test = TestCaseUtil.createTestSuite(OneTestTestCase.class);
+ assertEquals(1, test.countTestCases());
+ }
+
+ public void testCreateTestForTestSuiteWithSuiteMethod() throws Exception {
+ Test test = TestCaseUtil.createTestSuite(TwoTestsInTestSuite.class);
+ assertEquals(2, test.countTestCases());
+ }
+
+ public void testCreateTestForTestCaseWithSuiteMethod() throws Exception {
+ Test test = TestCaseUtil.createTestSuite(OneTestTestCaseWithSuite.class);
+ assertEquals(1, test.countTestCases());
+ }
+
+ public void testReturnEmptyStringForTestSuiteWithNoName() throws Exception {
+ assertEquals("", TestCaseUtil.getTestName(new TestSuite()));
+ }
+
+ public static class OneTestTestCase extends TestCase {
+ public void testOne() throws Exception {
+ }
+ }
+
+ public static class OneTestTestCaseWithSuite extends TestCase {
+ public static Test suite() {
+ TestCase testCase = new OneTestTestCase();
+ testCase.setName("testOne");
+ return testCase;
+ }
+
+ public void testOne() throws Exception {
+ }
+
+ public void testTwo() throws Exception {
+ }
+ }
+
+ public static class OneTestTestSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite(OneTestTestSuite.class.getName());
+ suite.addTestSuite(OneTestTestCase.class);
+ return suite;
+ }
+ }
+
+ public static class TwoTestsInTestSuite extends TestSuite {
+ public static Test suite() {
+ TestSuite suite = new TestSuite(TwoTestsInTestSuite.class.getName());
+ suite.addTestSuite(OneTestTestCase.class);
+ suite.addTest(OneTestTestSuite.suite());
+ return suite;
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java
new file mode 100644
index 0000000..0f73e89
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/AssignableFromTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+
+public class AssignableFromTest extends TestCase {
+ private AssignableFrom assignableFrom;
+
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ assignableFrom = new AssignableFrom(Animal.class);
+ }
+
+ public void testSelfIsAssignable() throws Exception {
+ assertTrue(assignableFrom.apply(testMethodFor(Animal.class)));
+ }
+
+ public void testSubclassesAreAssignable() throws Exception {
+ assertTrue(assignableFrom.apply(testMethodFor(Mammal.class)));
+ assertTrue(assignableFrom.apply(testMethodFor(Human.class)));
+ }
+
+ public void testNotAssignable() throws Exception {
+ assertFalse(assignableFrom.apply(testMethodFor(Pencil.class)));
+ }
+
+ public void testImplementorsAreAssignable() throws Exception {
+ assignableFrom = new AssignableFrom(WritingInstrument.class);
+
+ assertTrue(assignableFrom.apply(testMethodFor(Pencil.class)));
+ assertTrue(assignableFrom.apply(testMethodFor(Pen.class)));
+ }
+
+ private TestMethod testMethodFor(Class<? extends TestCase> aClass)
+ throws NoSuchMethodException {
+ Method method = aClass.getMethod("testX");
+ return new TestMethod(method, aClass);
+ }
+
+ private class Animal extends TestCase {
+ public void testX() {
+ }
+ }
+
+ private class Mammal extends Animal {
+ public void testX() {
+ }
+ }
+
+ private class Human extends Mammal {
+ public void testX() {
+ }
+ }
+
+ private interface WritingInstrument {
+ }
+
+ private class Pencil extends TestCase implements WritingInstrument {
+ public void testX() {
+ }
+ }
+
+ private class Pen extends TestCase implements WritingInstrument {
+ public void testX() {
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
new file mode 100644
index 0000000..1872803
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/InstrumentationTestSuiteBuilderTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames;
+import android.test.suitebuilder.examples.OuterTest;
+import android.test.suitebuilder.examples.instrumentation.InstrumentationTest;
+
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+public class InstrumentationTestSuiteBuilderTest extends TestCase {
+
+ private InstrumentationTestSuiteBuilder instrumentationTestSuiteBuilder;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ instrumentationTestSuiteBuilder = new InstrumentationTestSuiteBuilder(getClass());
+ }
+
+ public void testShouldIncludeIntrumentationTests() throws Exception {
+ instrumentationTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class));
+
+ SuiteExecutionRecorder recorder = runSuite(instrumentationTestSuiteBuilder);
+
+ assertEquals(1, recorder.testsSeen.size());
+ assertTrue(recorder.saw("InstrumentationTest.testInstrumentation"));
+ }
+
+ public void testShouldOnlyIncludeIntrumentationTests() throws Exception {
+ TestSuite testSuite = new OuterTest()
+ .buildTestsUnderHereWith(instrumentationTestSuiteBuilder);
+ List<String> testCaseNames = getTestCaseNames(testSuite);
+ assertEquals(1, testCaseNames.size());
+ assertEquals("testInstrumentation", testCaseNames.get(0));
+ }
+
+ private static String packageFor(Class clazz) {
+ String className = clazz.getName();
+ return className.substring(0, className.lastIndexOf('.'));
+ }
+
+ private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+ TestSuite suite = builder.build();
+ SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+ TestResult result = new TestResult();
+ result.addListener(recorder);
+ suite.run(result);
+ return recorder;
+ }
+
+ private class SuiteExecutionRecorder implements TestListener {
+
+ private Set<String> failures = new HashSet<String>();
+ private Set<String> errors = new HashSet<String>();
+ private Set<String> testsSeen = new HashSet<String>();
+
+ public void addError(Test test, Throwable t) {
+ errors.add(testName(test));
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ failures.add(testName(test));
+ }
+
+ public void endTest(Test test) {
+ }
+
+ public void startTest(Test test) {
+ testsSeen.add(testName(test));
+ }
+
+ public boolean saw(String testName) {
+ return testsSeen.contains(testName);
+ }
+
+ public boolean failed(String testName) {
+ return failures.contains(testName);
+ }
+
+ public boolean errored(String testName) {
+ return errors.contains(testName);
+ }
+
+ public boolean passed(String testName) {
+ return saw(testName) && !failed(testName) && !errored(testName);
+ }
+
+ private String testName(Test test) {
+ TestCase testCase = (TestCase) test;
+ return testCase.getClass().getSimpleName() + "." + testCase.getName();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java
new file mode 100644
index 0000000..37ec328
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/ListTestCaseNames.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ListTestCaseNames {
+ public static List<String> getTestCaseNames(TestSuite suite) {
+ // TODO: deprecate this method and move all callers to use getTestNames
+ List<Test> tests = Collections.<Test>list(suite.tests());
+ ArrayList<String> testCaseNames = new ArrayList<String>();
+ for (Test test : tests) {
+ if (test instanceof TestCase) {
+ testCaseNames.add(((TestCase) test).getName());
+ } else if (test instanceof TestSuite) {
+ testCaseNames.addAll(getTestCaseNames((TestSuite) test));
+ }
+ }
+ return testCaseNames;
+ }
+
+ /**
+ * Returns a list of test class and method names for each TestCase in suite.
+ */
+ public static List<TestDescriptor> getTestNames(TestSuite suite) {
+ List<Test> tests = Collections.<Test>list(suite.tests());
+ ArrayList<TestDescriptor> testNames = new ArrayList<TestDescriptor>();
+ for (Test test : tests) {
+ if (test instanceof TestCase) {
+ String className = test.getClass().getName();
+ String testName = ((TestCase) test).getName();
+ testNames.add(new TestDescriptor(className, testName));
+ } else if (test instanceof TestSuite) {
+ testNames.addAll(getTestNames((TestSuite) test));
+ }
+ }
+ return testNames;
+ }
+
+ /**
+ * Data holder for test case info
+ */
+ public static class TestDescriptor {
+ private String mClassName;
+ private String mTestName;
+
+ public TestDescriptor(String className, String testName) {
+ mClassName = className;
+ mTestName = testName;
+ }
+
+ public String getClassName() {
+ return mClassName;
+ }
+
+ public String getTestName() {
+ return mTestName;
+ }
+
+ /**
+ * Override parent to do string-based class and test name comparison
+ */
+ @Override
+ public boolean equals(Object otherObj) {
+ if (otherObj instanceof TestDescriptor) {
+ TestDescriptor otherDesc = (TestDescriptor)otherObj;
+ return otherDesc.getClassName().equals(this.getClassName()) &&
+ otherDesc.getTestName().equals(this.getTestName());
+
+ }
+ return false;
+ }
+
+ /**
+ * Override parent to return a more user-friendly display string
+ */
+ @Override
+ public String toString() {
+ return getClassName() + "#" + getTestName();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
new file mode 100644
index 0000000..f817297
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/SmokeTestSuiteBuilderTest.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+import java.util.List;
+
+public class SmokeTestSuiteBuilderTest extends TestCase {
+
+ public void testShouldOnlyIncludeSmokeTests() throws Exception {
+ TestSuite testSuite = new SmokeTestSuiteBuilder(getClass())
+ .includeAllPackagesUnderHere().build();
+
+ List<String> testCaseNames = ListTestCaseNames.getTestCaseNames(testSuite);
+ assertEquals("Unexpected number of smoke tests.", 1, testCaseNames.size());
+ assertEquals("Unexpected test name", "testSmoke", testCaseNames.get(0));
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java
new file mode 100644
index 0000000..293c813
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/TestSuiteBuilderTest.java
@@ -0,0 +1,218 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import com.android.internal.util.Predicate;
+import static android.test.suitebuilder.ListTestCaseNames.getTestCaseNames;
+import android.test.suitebuilder.examples.OuterTest;
+import android.test.suitebuilder.examples.suppress.SuppressedTest;
+import android.test.suitebuilder.examples.error.ErrorTest;
+import android.test.suitebuilder.examples.error.FailingTest;
+import android.test.suitebuilder.examples.nested.Level1Test;
+import android.test.suitebuilder.examples.nested.nested.Level2Test;
+import android.test.suitebuilder.examples.simple.SimpleTest;
+import android.test.suitebuilder.examples.subclass.SubclassTest;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+
+public class TestSuiteBuilderTest extends TestCase {
+
+ private TestSuiteBuilder testSuiteBuilder;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ testSuiteBuilder = new TestSuiteBuilder(getClass());
+ }
+
+ public void testShouldRunSimpleTests() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(SimpleTest.class));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertTrue(recorder.passed("SimpleTest.testSimpleOne"));
+ assertTrue(recorder.passed("SimpleTest.testSimpleTwo"));
+ assertTrue(recorder.passed("AnotherSimpleTest.testAnotherOne"));
+ }
+
+ public void testShouldOnlyIncludeTestsThatSatisfyAllPredicates() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(SimpleTest.class))
+ .addRequirements(testsWhoseNameContains("test"))
+ .addRequirements(testsWhoseNameContains("Simple"))
+ .addRequirements(testsWhoseNameContains("Two"));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertTrue(recorder.passed("SimpleTest.testSimpleTwo"));
+ }
+
+ public void testShouldAddFailingTestsToSuite() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(FailingTest.class));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertTrue(recorder.failed("FailingTest.testFailOne"));
+ assertTrue(recorder.failed("FailingTest.testFailTwo"));
+ }
+
+ public void testShouldAddTestsWithErrorsToSuite() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(ErrorTest.class));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertTrue(recorder.errored("ErrorTest.testErrorOne"));
+ assertTrue(recorder.errored("ErrorTest.testErrorTwo"));
+ }
+
+ public void testShouldRunTestsInheritedFromSuperclass() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(SubclassTest.class));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertEquals(2, getTestCaseNames(testSuiteBuilder.build()).size());
+
+ assertTrue(recorder.passed("SubclassTest.testSubclass"));
+ assertTrue(recorder.passed("SubclassTest.testSuperclass"));
+ assertFalse(recorder.saw("SuperclassTest.testSuperclass"));
+ }
+
+ public void testShouldIncludeTestsInSubPackagesRecursively() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(Level1Test.class));
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertTrue(recorder.passed("Level1Test.testLevel1"));
+ assertTrue(recorder.passed("Level2Test.testLevel2"));
+ }
+
+ public void testExcludePackage() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(SimpleTest.class),
+ packageFor(Level1Test.class)).excludePackages(packageFor(Level2Test.class));
+
+ TestSuite testSuite = testSuiteBuilder.build();
+ assertContentsInOrder(getTestCaseNames(testSuite),
+ "testLevel1", "testAnotherOne", "testSimpleOne", "testSimpleTwo");
+ }
+
+ public void testShouldExcludeSuppressedTests() throws Exception {
+ testSuiteBuilder.includePackages(packageFor(SuppressedTest.class));
+ testSuiteBuilder.build();
+
+ SuiteExecutionRecorder recorder = runSuite(testSuiteBuilder);
+
+ assertEquals(1, recorder.testsSeen.size());
+ assertTrue(recorder.passed("PartiallySuppressedTest.testUnSuppressedMethod"));
+ }
+
+ /**
+ * This test calls {@link OuterTest#buildTestsUnderHereRecursively()} to control
+ * the packages under test. The call to {@link TestSuiteBuilder#includeAllPackagesUnderHere()}
+ * is made from there so that only return the example tests.
+ */
+ public void testIncludeAllPackagesUnderHere() throws Exception {
+
+ TestSuite testSuite = new OuterTest().buildTestsUnderHereRecursively();
+ assertContentsInOrder(getTestCaseNames(testSuite),
+ "testOuter", "testErrorOne", "testErrorTwo", "testFailOne", "testFailTwo",
+ "testInstrumentation", "testLevel1", "testLevel2", "testAnotherOne",
+ "testSimpleOne", "testSimpleTwo", "testNonSmoke", "testSmoke", "testSubclass",
+ "testSuperclass", "testUnSuppressedMethod");
+ }
+
+ private void assertContentsInOrder(List<String> actual, String... source) {
+ String[] clonedSource = source.clone();
+ assertEquals("Unexpected number of items.", clonedSource.length, actual.size());
+ for (int i = 0; i < actual.size(); i++) {
+ String actualItem = actual.get(i);
+ String sourceItem = clonedSource[i];
+ assertEquals("Unexpected item. Index: " + i, sourceItem, actualItem);
+ }
+ }
+
+ private static String packageFor(Class clazz) {
+ String className = clazz.getName();
+ return className.substring(0, className.lastIndexOf('.'));
+ }
+
+ private Predicate<TestMethod> testsWhoseNameContains(final String string) {
+ return new Predicate<TestMethod>() {
+ public boolean apply(TestMethod testMethod) {
+ return testMethod.getName().contains(string);
+ }
+ };
+ }
+
+ private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+ TestSuite suite = builder.build();
+ SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+ TestResult result = new TestResult();
+ result.addListener(recorder);
+ suite.run(result);
+ return recorder;
+ }
+
+ private class SuiteExecutionRecorder implements TestListener {
+
+ private Set<String> failures = new HashSet<String>();
+ private Set<String> errors = new HashSet<String>();
+ private Set<String> testsSeen = new HashSet<String>();
+
+ public void addError(Test test, Throwable t) {
+ errors.add(testName(test));
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ failures.add(testName(test));
+ }
+
+ public void endTest(Test test) {
+ }
+
+ public void startTest(Test test) {
+ testsSeen.add(testName(test));
+ }
+
+ public boolean saw(String testName) {
+ return testsSeen.contains(testName);
+ }
+
+ public boolean failed(String testName) {
+ return failures.contains(testName);
+ }
+
+ public boolean errored(String testName) {
+ return errors.contains(testName);
+ }
+
+ public boolean passed(String testName) {
+ return saw(testName) && !failed(testName) && !errored(testName);
+ }
+
+ private String testName(Test test) {
+ TestCase testCase = (TestCase) test;
+ return testCase.getClass().getSimpleName() + "." + testCase.getName();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
new file mode 100644
index 0000000..469938e
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/UnitTestSuiteBuilderTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder;
+
+import android.test.suitebuilder.examples.instrumentation.InstrumentationTest;
+
+import junit.framework.Assert;
+import junit.framework.AssertionFailedError;
+import junit.framework.Test;
+import junit.framework.TestCase;
+import junit.framework.TestListener;
+import junit.framework.TestResult;
+import junit.framework.TestSuite;
+
+import java.util.HashSet;
+import java.util.Set;
+
+public class UnitTestSuiteBuilderTest extends TestCase {
+
+ private UnitTestSuiteBuilder unitTestSuiteBuilder;
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ unitTestSuiteBuilder = new UnitTestSuiteBuilder(getClass());
+ }
+
+ public void testShouldExcludeIntrumentationTests() throws Exception {
+ unitTestSuiteBuilder.includePackages(packageFor(InstrumentationTest.class));
+
+ TestSuite testSuite = unitTestSuiteBuilder.build();
+ Assert.assertEquals(0, ListTestCaseNames.getTestCaseNames(testSuite).size());
+
+ SuiteExecutionRecorder recorder = runSuite(unitTestSuiteBuilder);
+
+ assertFalse(recorder.saw("InstrumentationTest.testInstrumentation"));
+ assertTrue(recorder.testsSeen.isEmpty());
+ }
+
+ private static String packageFor(Class clazz) {
+ String className = clazz.getName();
+ return className.substring(0, className.lastIndexOf('.'));
+ }
+
+ private SuiteExecutionRecorder runSuite(TestSuiteBuilder builder) {
+ TestSuite suite = builder.build();
+ SuiteExecutionRecorder recorder = new SuiteExecutionRecorder();
+ TestResult result = new TestResult();
+ result.addListener(recorder);
+ suite.run(result);
+ return recorder;
+ }
+
+ private class SuiteExecutionRecorder implements TestListener {
+
+ private Set<String> failures = new HashSet<String>();
+ private Set<String> errors = new HashSet<String>();
+ private Set<String> testsSeen = new HashSet<String>();
+
+ public void addError(Test test, Throwable t) {
+ errors.add(testName(test));
+ }
+
+ public void addFailure(Test test, AssertionFailedError t) {
+ failures.add(testName(test));
+ }
+
+ public void endTest(Test test) {
+ }
+
+ public void startTest(Test test) {
+ testsSeen.add(testName(test));
+ }
+
+ public boolean saw(String testName) {
+ return testsSeen.contains(testName);
+ }
+
+ public boolean failed(String testName) {
+ return failures.contains(testName);
+ }
+
+ public boolean errored(String testName) {
+ return errors.contains(testName);
+ }
+
+ public boolean passed(String testName) {
+ return saw(testName) && !failed(testName) && !errored(testName);
+ }
+
+ private String testName(Test test) {
+ TestCase testCase = (TestCase) test;
+ return testCase.getClass().getSimpleName() + "." + testCase.getName();
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java
new file mode 100644
index 0000000..edf067d
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasAnnotationTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Method;
+
+public class HasAnnotationTest extends TestCase {
+
+ public void testThatMethodWithAnnotationIsReportedAsBeingAnnotated() throws Exception {
+ assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithAnnotation"));
+ assertTrue(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithAnnotation"));
+ }
+
+ public void testThatMethodWithOutAnnotationIsNotReportedAsBeingAnnotated() throws Exception {
+ assertFalse(hasExampleAnnotation(ClassWithoutAnnotation.class, "testWithoutAnnotation"));
+ }
+
+ public void testThatClassAnnotatioCausesAllMethodsToBeReportedAsBeingAnnotated()
+ throws Exception {
+ assertTrue(hasExampleAnnotation(ClassWithAnnotation.class, "testWithoutAnnotation"));
+ }
+
+ private boolean hasExampleAnnotation(Class<? extends TestCase> aClass, String methodName)
+ throws NoSuchMethodException {
+ Method method = aClass.getMethod(methodName);
+ TestMethod testMethod = new TestMethod(method, aClass);
+ return new HasAnnotation(Example.class).apply(testMethod);
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE, ElementType.METHOD})
+ public @interface Example {
+ }
+
+ @Example
+ static class ClassWithAnnotation extends TestCase {
+
+ @Example
+ public void testWithAnnotation() {
+ }
+
+ public void testWithoutAnnotation() {
+ }
+ }
+
+ static class ClassWithoutAnnotation extends TestCase {
+
+ @Example
+ public void testWithAnnotation() {
+ }
+
+ public void testWithoutAnnotation() {
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
new file mode 100644
index 0000000..051ea54
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasClassAnnotationTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.reflect.Method;
+
+public class HasClassAnnotationTest extends TestCase {
+
+ public void testShouldTellIfParentClassHasSpecifiedClassification()
+ throws NoSuchMethodException {
+ assertTrue(classHasAnnotation(SmokeTestExample.class, Smoke.class));
+ }
+
+ public void testShouldTellIfParentClassDoesNotHaveSpecifiedClassification()
+ throws NoSuchMethodException {
+ assertFalse(classHasAnnotation(NonSmokeTestExample.class, Smoke.class));
+ }
+
+ private boolean classHasAnnotation(
+ Class<? extends TestCase> aClass,
+ Class<Smoke> expectedClassification) throws NoSuchMethodException {
+ Method method = aClass.getMethod("testSomeTest");
+
+ TestMethod testMethod = new TestMethod(method, aClass);
+ return new HasClassAnnotation(expectedClassification).apply(testMethod);
+ }
+
+ @Smoke
+ static class SmokeTestExample extends TestCase {
+
+ public void testSomeTest() {
+ }
+ }
+
+ static class NonSmokeTestExample extends TestCase {
+
+ public void testSomeTest() {
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
new file mode 100644
index 0000000..c864e28
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/annotation/HasMethodAnnotationTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.annotation;
+
+import android.test.suitebuilder.TestMethod;
+import junit.framework.TestCase;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Method;
+
+
+public class HasMethodAnnotationTest extends TestCase {
+
+ public void testMethodWithSpecifiedAttribute() throws Exception {
+ assertTrue(methodHasAnnotation(AnnotatedMethodExample.class,
+ "testThatIsAnnotated", Smoke.class));
+ }
+
+ public void testMethodWithoutSpecifiedAttribute() throws Exception {
+ assertFalse(methodHasAnnotation(AnnotatedMethodExample.class,
+ "testThatIsNotAnnotated", Smoke.class));
+ }
+
+ private boolean methodHasAnnotation(Class<? extends TestCase> aClass,
+ String methodName,
+ Class<? extends Annotation> expectedClassification
+ ) throws NoSuchMethodException {
+ Method method = aClass.getMethod(methodName);
+ TestMethod testMethod = new TestMethod(method, aClass);
+ return new HasMethodAnnotation(expectedClassification).apply(testMethod);
+ }
+
+ static class AnnotatedMethodExample extends TestCase {
+
+ @Smoke
+ public void testThatIsAnnotated() {
+ }
+
+ public void testThatIsNotAnnotated() {
+ }
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java
new file mode 100644
index 0000000..4659bf9
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/OuterTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples;
+
+import android.test.suitebuilder.TestSuiteBuilder;
+
+import junit.framework.TestCase;
+import junit.framework.TestSuite;
+
+public class OuterTest extends TestCase {
+
+ public void testOuter() {
+ assertTrue(true);
+ }
+
+ public TestSuite buildTestsUnderHereRecursively() {
+ return buildTestsUnderHereWith(new TestSuiteBuilder(getClass()));
+ }
+
+ public TestSuite buildTestsUnderHereWith(TestSuiteBuilder testSuiteBuilder) {
+ return testSuiteBuilder.includeAllPackagesUnderHere().build();
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java
new file mode 100644
index 0000000..f1f6113
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/error/ErrorTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.error;
+
+import junit.framework.TestCase;
+
+public class ErrorTest extends TestCase {
+
+ public void testErrorOne() throws Exception {
+ throw new RuntimeException("Expected");
+ }
+
+ public void testErrorTwo() throws Exception {
+ throw new RuntimeException("Expected");
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java
new file mode 100644
index 0000000..428fd23
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/error/FailingTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.error;
+
+import junit.framework.TestCase;
+
+public class FailingTest extends TestCase {
+
+ public void testFailOne() throws Exception {
+ fail("Expected");
+ }
+
+ public void testFailTwo() throws Exception {
+ fail("Expected");
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
new file mode 100644
index 0000000..5158a90
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/instrumentation/InstrumentationTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.instrumentation;
+
+import android.test.InstrumentationTestCase;
+
+public class InstrumentationTest extends InstrumentationTestCase {
+
+ public void testInstrumentation() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java
new file mode 100644
index 0000000..17d39d6
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/Level1Test.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.nested;
+
+import junit.framework.TestCase;
+
+public class Level1Test extends TestCase {
+
+ public void testLevel1() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java
new file mode 100644
index 0000000..6f0daca
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/nested/nested/Level2Test.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.nested.nested;
+
+import junit.framework.TestCase;
+
+public class Level2Test extends TestCase {
+
+ public void testLevel2() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
new file mode 100644
index 0000000..0dfeda8
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/AnotherSimpleTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.simple;
+
+import junit.framework.TestCase;
+
+public class AnotherSimpleTest extends TestCase {
+
+ public void testAnotherOne() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java
new file mode 100644
index 0000000..4dcac44
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/simple/SimpleTest.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.simple;
+
+import junit.framework.TestCase;
+
+public class SimpleTest extends TestCase {
+
+ public void testSimpleOne() throws Exception {
+ assertTrue(true);
+ }
+
+ public void testSimpleTwo() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
new file mode 100644
index 0000000..1512ba7
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/NonSmokeTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.smoke;
+
+import junit.framework.TestCase;
+
+public class NonSmokeTest extends TestCase {
+
+ public void testNonSmoke() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java
new file mode 100644
index 0000000..c3515df
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/smoke/SmokeTest.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.smoke;
+
+import android.test.suitebuilder.annotation.Smoke;
+import junit.framework.TestCase;
+
+@Smoke
+public class SmokeTest extends TestCase {
+
+ public void testSmoke() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java
new file mode 100644
index 0000000..0ab8c72
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SubclassTest.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.subclass;
+
+public class SubclassTest extends SuperclassTest {
+
+ public void testSubclass() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java
new file mode 100644
index 0000000..05513c5
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/subclass/SuperclassTest.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.subclass;
+
+import junit.framework.TestCase;
+
+public abstract class SuperclassTest extends TestCase {
+
+ public void testSuperclass() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
new file mode 100644
index 0000000..3ca0f70
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/PartiallySuppressedTest.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.suppress;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+import junit.framework.TestCase;
+
+public class PartiallySuppressedTest extends TestCase {
+
+ @Suppress
+ public void testSuppressedMethod() throws Exception {
+ assertTrue(true);
+ }
+
+ public void testUnSuppressedMethod() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java
new file mode 100644
index 0000000..c4e0e07
--- /dev/null
+++ b/tests/CoreTests/android/test/suitebuilder/examples/suppress/SuppressedTest.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.test.suitebuilder.examples.suppress;
+
+import android.test.suitebuilder.annotation.Suppress;
+
+import junit.framework.TestCase;
+
+@Suppress
+public class SuppressedTest extends TestCase {
+
+ public void testSuppressedClass() throws Exception {
+ assertTrue(true);
+ }
+}
diff --git a/tests/CoreTests/android/util/DayOfMonthCursorTest.java b/tests/CoreTests/android/util/DayOfMonthCursorTest.java
new file mode 100644
index 0000000..4c5ad76
--- /dev/null
+++ b/tests/CoreTests/android/util/DayOfMonthCursorTest.java
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+
+import java.util.Calendar;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit tests for {@link DayOfMonthCursor}.
+ */
+public class DayOfMonthCursorTest extends TestCase {
+
+ @SmallTest
+ public void testMonthRows() {
+ DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+ Calendar.SEPTEMBER, 11, Calendar.SUNDAY);
+
+ assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+ mc.getDigitsForRow(0));
+ assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8},
+ mc.getDigitsForRow(1));
+ assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6},
+ mc.getDigitsForRow(5));
+ }
+
+ @SmallTest
+ public void testMoveLeft() {
+ DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+ Calendar.SEPTEMBER, 3, Calendar.SUNDAY);
+
+ assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+ assertEquals(3, mc.getSelectedDayOfMonth());
+ assertEquals(1, mc.getSelectedRow());
+ assertEquals(1, mc.getSelectedColumn());
+
+ // move left, still same row
+ assertFalse(mc.left());
+ assertEquals(2, mc.getSelectedDayOfMonth());
+ assertEquals(1, mc.getSelectedRow());
+ assertEquals(0, mc.getSelectedColumn());
+
+ // wrap over to previous column, same month
+ assertFalse(mc.left());
+ assertEquals(1, mc.getSelectedDayOfMonth());
+ assertEquals(0, mc.getSelectedRow());
+ assertEquals(6, mc.getSelectedColumn());
+
+ // wrap to previous month
+ assertTrue(mc.left());
+ assertEquals(Calendar.AUGUST, mc.getMonth());
+ assertEquals(31, mc.getSelectedDayOfMonth());
+ assertEquals(4, mc.getSelectedRow());
+ assertEquals(5, mc.getSelectedColumn());
+ }
+
+ @SmallTest
+ public void testMoveRight() {
+ DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+ Calendar.SEPTEMBER, 28, Calendar.SUNDAY);
+
+ assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+ assertEquals(28, mc.getSelectedDayOfMonth());
+ assertEquals(4, mc.getSelectedRow());
+ assertEquals(5, mc.getSelectedColumn());
+
+ // same row
+ assertFalse(mc.right());
+ assertEquals(29, mc.getSelectedDayOfMonth());
+ assertEquals(4, mc.getSelectedRow());
+ assertEquals(6, mc.getSelectedColumn());
+
+ // wrap to next column, same month
+ assertFalse(mc.right());
+ assertEquals(30, mc.getSelectedDayOfMonth());
+ assertEquals(5, mc.getSelectedRow());
+ assertEquals(0, mc.getSelectedColumn());
+
+ // next month
+ assertTrue(mc.right());
+ assertEquals(Calendar.OCTOBER, mc.getMonth());
+ assertEquals(1, mc.getSelectedDayOfMonth());
+ assertEquals(0, mc.getSelectedRow());
+ assertEquals(1, mc.getSelectedColumn());
+ }
+
+ @SmallTest
+ public void testMoveUp() {
+ DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+ Calendar.SEPTEMBER, 13, Calendar.SUNDAY);
+
+ assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+ assertEquals(13, mc.getSelectedDayOfMonth());
+ assertEquals(2, mc.getSelectedRow());
+ assertEquals(4, mc.getSelectedColumn());
+
+ // up, same month
+ assertFalse(mc.up());
+ assertEquals(6, mc.getSelectedDayOfMonth());
+ assertEquals(1, mc.getSelectedRow());
+ assertEquals(4, mc.getSelectedColumn());
+
+ // up, flips back
+ assertTrue(mc.up());
+ assertEquals(Calendar.AUGUST, mc.getMonth());
+ assertEquals(30, mc.getSelectedDayOfMonth());
+ assertEquals(4, mc.getSelectedRow());
+ assertEquals(4, mc.getSelectedColumn());
+ }
+
+ @SmallTest
+ public void testMoveDown() {
+ DayOfMonthCursor mc = new DayOfMonthCursor(2007,
+ Calendar.SEPTEMBER, 23, Calendar.SUNDAY);
+
+ assertEquals(Calendar.SEPTEMBER, mc.getMonth());
+ assertEquals(23, mc.getSelectedDayOfMonth());
+ assertEquals(4, mc.getSelectedRow());
+ assertEquals(0, mc.getSelectedColumn());
+
+ // down, same month
+ assertFalse(mc.down());
+ assertEquals(30, mc.getSelectedDayOfMonth());
+ assertEquals(5, mc.getSelectedRow());
+ assertEquals(0, mc.getSelectedColumn());
+
+ // down, next month
+ assertTrue(mc.down());
+ assertEquals(Calendar.OCTOBER, mc.getMonth());
+ assertEquals(7, mc.getSelectedDayOfMonth());
+ assertEquals(1, mc.getSelectedRow());
+ assertEquals(0, mc.getSelectedColumn());
+ }
+
+ private void assertArraysEqual(int[] expected, int[] actual) {
+ assertEquals("array length", expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("index " + i,
+ expected[i], actual[i]);
+ }
+ }
+}
diff --git a/tests/CoreTests/android/util/FloatMathTest.java b/tests/CoreTests/android/util/FloatMathTest.java
new file mode 100644
index 0000000..f479e2b
--- /dev/null
+++ b/tests/CoreTests/android/util/FloatMathTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class FloatMathTest extends TestCase {
+
+ @SmallTest
+ public void testSqrt() {
+ assertEquals(7, FloatMath.sqrt(49), 0);
+ assertEquals(10, FloatMath.sqrt(100), 0);
+ assertEquals(0, FloatMath.sqrt(0), 0);
+ assertEquals(1, FloatMath.sqrt(1), 0);
+ }
+
+ @SmallTest
+ public void testFloor() {
+ assertEquals(78, FloatMath.floor(78.89f), 0);
+ assertEquals(-79, FloatMath.floor(-78.89f), 0);
+ }
+
+ @SmallTest
+ public void testCeil() {
+ assertEquals(79, FloatMath.ceil(78.89f), 0);
+ assertEquals(-78, FloatMath.ceil(-78.89f), 0);
+ }
+
+ @SmallTest
+ public void testSin() {
+ assertEquals(0.0, FloatMath.sin(0), 0);
+ assertEquals(0.8414709848078965f, FloatMath.sin(1), 0);
+ }
+
+ @SmallTest
+ public void testCos() {
+ assertEquals(1.0f, FloatMath.cos(0), 0);
+ assertEquals(0.5403023058681398f, FloatMath.cos(1), 0);
+ }
+}
diff --git a/tests/CoreTests/android/util/MonthDisplayHelperTest.java b/tests/CoreTests/android/util/MonthDisplayHelperTest.java
new file mode 100644
index 0000000..5207ad9
--- /dev/null
+++ b/tests/CoreTests/android/util/MonthDisplayHelperTest.java
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import java.util.Calendar;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * Unit tests for {@link MonthDisplayHelper}.
+ */
+public class MonthDisplayHelperTest extends TestCase {
+
+
+ @SmallTest
+ public void testFirstDayOfMonth() {
+
+ assertEquals("august 2007",
+ Calendar.WEDNESDAY,
+ new MonthDisplayHelper(2007, Calendar.AUGUST).getFirstDayOfMonth());
+
+ assertEquals("september, 2007",
+ Calendar.SATURDAY,
+ new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getFirstDayOfMonth());
+ }
+
+ @MediumTest
+ public void testNumberOfDaysInCurrentMonth() {
+ assertEquals(30,
+ new MonthDisplayHelper(2007, Calendar.SEPTEMBER).getNumberOfDaysInMonth());
+ }
+
+ @SmallTest
+ public void testMonthRows() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007, Calendar.SEPTEMBER);
+
+ assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+ helper.getDigitsForRow(0));
+ assertArraysEqual(new int[]{2, 3, 4, 5, 6, 7, 8},
+ helper.getDigitsForRow(1));
+ assertArraysEqual(new int[]{30, 1, 2, 3, 4, 5, 6},
+ helper.getDigitsForRow(5));
+
+ }
+
+ @SmallTest
+ public void testMonthRowsWeekStartsMonday() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.SEPTEMBER, Calendar.MONDAY);
+
+ assertArraysEqual(new int[]{27, 28, 29, 30, 31, 1, 2},
+ helper.getDigitsForRow(0));
+ assertArraysEqual(new int[]{3, 4, 5, 6, 7, 8, 9},
+ helper.getDigitsForRow(1));
+ assertArraysEqual(new int[]{24, 25, 26, 27, 28, 29, 30},
+ helper.getDigitsForRow(4));
+ assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7},
+ helper.getDigitsForRow(5));
+ }
+
+ @SmallTest
+ public void testMonthRowsWeekStartsSaturday() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.SEPTEMBER, Calendar.SATURDAY);
+
+ assertArraysEqual(new int[]{1, 2, 3, 4, 5, 6, 7},
+ helper.getDigitsForRow(0));
+ assertArraysEqual(new int[]{8, 9, 10, 11, 12, 13, 14},
+ helper.getDigitsForRow(1));
+ assertArraysEqual(new int[]{29, 30, 1, 2, 3, 4, 5},
+ helper.getDigitsForRow(4));
+
+
+ helper = new MonthDisplayHelper(2007,
+ Calendar.AUGUST, Calendar.SATURDAY);
+
+ assertArraysEqual(new int[]{28, 29, 30, 31, 1, 2, 3},
+ helper.getDigitsForRow(0));
+ assertArraysEqual(new int[]{4, 5, 6, 7, 8, 9, 10},
+ helper.getDigitsForRow(1));
+ assertArraysEqual(new int[]{25, 26, 27, 28, 29, 30, 31},
+ helper.getDigitsForRow(4));
+ }
+
+ @SmallTest
+ public void testGetDayAt() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+ assertEquals(26, helper.getDayAt(0, 0));
+ assertEquals(1, helper.getDayAt(0, 6));
+ assertEquals(17, helper.getDayAt(3, 1));
+ assertEquals(2, helper.getDayAt(5, 2));
+ }
+
+ @SmallTest
+ public void testPrevMonth() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+ assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+ helper.getDigitsForRow(0));
+
+ helper.previousMonth();
+
+ assertEquals(Calendar.AUGUST, helper.getMonth());
+ assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4},
+ helper.getDigitsForRow(0));
+ }
+
+ @SmallTest
+ public void testPrevMonthRollOver() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.JANUARY);
+
+ helper.previousMonth();
+
+ assertEquals(2006, helper.getYear());
+ assertEquals(Calendar.DECEMBER, helper.getMonth());
+ }
+
+ @SmallTest
+ public void testNextMonth() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.AUGUST, Calendar.SUNDAY);
+
+ assertArraysEqual(new int[]{29, 30, 31, 1, 2, 3, 4},
+ helper.getDigitsForRow(0));
+
+ helper.nextMonth();
+
+ assertEquals(Calendar.SEPTEMBER, helper.getMonth());
+ assertArraysEqual(new int[]{26, 27, 28, 29, 30, 31, 1},
+ helper.getDigitsForRow(0));
+ }
+
+ @SmallTest
+ public void testGetRowOf() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.AUGUST, Calendar.SUNDAY);
+
+ assertEquals(0, helper.getRowOf(2));
+ assertEquals(0, helper.getRowOf(4));
+ assertEquals(2, helper.getRowOf(12));
+ assertEquals(2, helper.getRowOf(18));
+ assertEquals(3, helper.getRowOf(19));
+ }
+
+ @SmallTest
+ public void testGetColumnOf() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.AUGUST, Calendar.SUNDAY);
+
+ assertEquals(3, helper.getColumnOf(1));
+ assertEquals(4, helper.getColumnOf(9));
+ assertEquals(5, helper.getColumnOf(17));
+ assertEquals(6, helper.getColumnOf(25));
+ assertEquals(0, helper.getColumnOf(26));
+ }
+
+ @SmallTest
+ public void testWithinCurrentMonth() {
+ MonthDisplayHelper helper = new MonthDisplayHelper(2007,
+ Calendar.SEPTEMBER, Calendar.SUNDAY);
+
+ // out of bounds
+ assertFalse(helper.isWithinCurrentMonth(-1, 3));
+ assertFalse(helper.isWithinCurrentMonth(6, 3));
+ assertFalse(helper.isWithinCurrentMonth(2, -1));
+ assertFalse(helper.isWithinCurrentMonth(2, 7));
+
+ // last day of previous month
+ assertFalse(helper.isWithinCurrentMonth(0, 5));
+
+ // first day of next month
+ assertFalse(helper.isWithinCurrentMonth(5, 1));
+
+ // first day in month
+ assertTrue(helper.isWithinCurrentMonth(0, 6));
+
+ // last day in month
+ assertTrue(helper.isWithinCurrentMonth(5, 0));
+ }
+
+ private void assertArraysEqual(int[] expected, int[] actual) {
+ assertEquals("array length", expected.length, actual.length);
+ for (int i = 0; i < expected.length; i++) {
+ assertEquals("index " + i,
+ expected[i], actual[i]);
+ }
+ }
+
+}
diff --git a/tests/CoreTests/android/util/StateSetTest.java b/tests/CoreTests/android/util/StateSetTest.java
new file mode 100644
index 0000000..e481ce0
--- /dev/null
+++ b/tests/CoreTests/android/util/StateSetTest.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Tests for {@link StateSet}
+ */
+
+public class StateSetTest extends TestCase {
+
+ @SmallTest
+ public void testStateSetPositiveMatches() throws Exception {
+ int[] stateSpec = new int[2];
+ int[] stateSet = new int[3];
+ // Single states in both sets - match
+ stateSpec[0] = 1;
+ stateSet[0] = 1;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Single states in both sets - non-match
+ stateSet[0] = 2;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add another state to the spec which the stateSet doesn't match
+ stateSpec[1] = 2;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add the missing matching element to the stateSet
+ stateSet[1] = 1;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add an irrelevent state to the stateSpec
+ stateSet[2] = 12345;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ }
+
+ @SmallTest
+ public void testStatesSetMatchMixEmUp() throws Exception {
+ int[] stateSpec = new int[2];
+ int[] stateSet = new int[2];
+ // One element in stateSpec which we must match and one which we must
+ // not match. stateSet only contains the match.
+ stateSpec[0] = 1;
+ stateSpec[1] = -2;
+ stateSet[0] = 1;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ // stateSet now contains just the element we must not match
+ stateSet[0] = 2;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add another matching state to the the stateSet. We still fail
+ // because stateSet contains a must-not-match element
+ stateSet[1] = 1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Switch the must-not-match element in stateSet with a don't care
+ stateSet[0] = 12345;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ }
+
+ @SmallTest
+ public void testStateSetNegativeMatches() throws Exception {
+ int[] stateSpec = new int[2];
+ int[] stateSet = new int[3];
+ // Single states in both sets - match
+ stateSpec[0] = -1;
+ stateSet[0] = 2;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add another arrelevent state to the stateSet
+ stateSet[1] = 12345;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Single states in both sets - non-match
+ stateSet[0] = 1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add another state to the spec which the stateSet doesn't match
+ stateSpec[1] = -2;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // Add an irrelevent state to the stateSet
+ stateSet[2] = 12345;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ }
+
+ @SmallTest
+ public void testEmptySetMatchesNegtives() throws Exception {
+ int[] stateSpec = {-12345, -6789};
+ int[] stateSet = new int[0];
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ int[] stateSet2 = {0};
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
+ }
+
+ @SmallTest
+ public void testEmptySetFailsPositives() throws Exception {
+ int[] stateSpec = {12345};
+ int[] stateSet = new int[0];
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ int[] stateSet2 = {0};
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet2));
+ }
+
+ @SmallTest
+ public void testEmptySetMatchesWildcard() throws Exception {
+ int[] stateSpec = StateSet.WILD_CARD;
+ int[] stateSet = new int[0];
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ int[] stateSet2 = {0};
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet2));
+ }
+
+ @SmallTest
+ public void testSingleStatePositiveMatches() throws Exception {
+ int[] stateSpec = new int[2];
+ int state;
+ // match
+ stateSpec[0] = 1;
+ state = 1;
+ assertTrue(StateSet.stateSetMatches(stateSpec, state));
+ // non-match
+ state = 2;
+ assertFalse(StateSet.stateSetMatches(stateSpec, state));
+ // add irrelevant must-not-match
+ stateSpec[1] = -12345;
+ assertFalse(StateSet.stateSetMatches(stateSpec, state));
+ }
+
+ @SmallTest
+ public void testSingleStateNegativeMatches() throws Exception {
+ int[] stateSpec = new int[2];
+ int state;
+ // match
+ stateSpec[0] = -1;
+ state = 1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, state));
+ // non-match
+ state = 2;
+ assertTrue(StateSet.stateSetMatches(stateSpec, state));
+ // add irrelevant must-not-match
+ stateSpec[1] = -12345;
+ assertTrue(StateSet.stateSetMatches(stateSpec, state));
+ }
+
+ @SmallTest
+ public void testZeroStateOnlyMatchesDefault() throws Exception {
+ int[] stateSpec = new int[3];
+ int state = 0;
+ // non-match
+ stateSpec[0] = 1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, state));
+ // non-match
+ stateSpec[1] = -1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, state));
+ // match
+ stateSpec = StateSet.WILD_CARD;
+ assertTrue(StateSet.stateSetMatches(stateSpec, state));
+ }
+
+ @SmallTest
+ public void testNullStateOnlyMatchesDefault() throws Exception {
+ int[] stateSpec = new int[3];
+ int[] stateSet = null;
+ // non-match
+ stateSpec[0] = 1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // non-match
+ stateSpec[1] = -1;
+ assertFalse(StateSet.stateSetMatches(stateSpec, stateSet));
+ // match
+ stateSpec = StateSet.WILD_CARD;
+ assertTrue(StateSet.stateSetMatches(stateSpec, stateSet));
+ }
+}
diff --git a/tests/CoreTests/android/view/FocusFinderTest.java b/tests/CoreTests/android/view/FocusFinderTest.java
new file mode 100644
index 0000000..7ac8dfc
--- /dev/null
+++ b/tests/CoreTests/android/view/FocusFinderTest.java
@@ -0,0 +1,576 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.graphics.Rect;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class FocusFinderTest extends AndroidTestCase {
+
+ private FocusFinderHelper mFocusFinder;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mFocusFinder = new FocusFinderHelper(FocusFinder.getInstance());
+ }
+
+ @SmallTest
+ public void testPreconditions() {
+ assertNotNull("focus finder instance", mFocusFinder);
+ }
+
+ @SmallTest
+ public void testBelowNotCandidateForDirectionUp() {
+ assertIsNotCandidate(View.FOCUS_UP,
+ new Rect(0, 30, 10, 40), // src (left, top, right, bottom)
+ new Rect(0, 50, 10, 60)); // dest (left, top, right, bottom)
+ }
+
+ @SmallTest
+ public void testAboveShareEdgeEdgeOkForDirectionUp() {
+ final Rect src = new Rect(0, 30, 10, 40);
+
+ final Rect dest = new Rect(src);
+ dest.offset(0, -src.height());
+ assertEquals(src.top, dest.bottom);
+
+ assertDirectionIsCandidate(View.FOCUS_UP, src, dest);
+ }
+
+ @SmallTest
+ public void testCompletelyContainedNotCandidate() {
+ assertIsNotCandidate(
+ View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50),
+ new Rect(0, 1, 50, 49));
+ }
+
+ @SmallTest
+ public void testContinaedWithCommonBottomNotCandidate() {
+ assertIsNotCandidate(
+ View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50),
+ new Rect(0, 1, 50, 50));
+ }
+
+ @SmallTest
+ public void testOverlappingIsCandidateWhenBothEdgesAreInDirection() {
+ assertDirectionIsCandidate(
+ View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50),
+ new Rect(0, 1, 50, 51));
+ }
+
+ @SmallTest
+ public void testTopEdgeOfDestAtOrAboveTopOfSrcNotCandidateForDown() {
+ assertIsNotCandidate(
+ View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50),
+ new Rect(0, 0, 50, 51));
+ assertIsNotCandidate(
+ View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50),
+ new Rect(0, -1, 50, 51));
+ }
+
+ @SmallTest
+ public void testSameRectBeamsOverlap() {
+ final Rect rect = new Rect(0, 0, 20, 20);
+
+ assertBeamsOverlap(View.FOCUS_LEFT, rect, rect);
+ assertBeamsOverlap(View.FOCUS_RIGHT, rect, rect);
+ assertBeamsOverlap(View.FOCUS_UP, rect, rect);
+ assertBeamsOverlap(View.FOCUS_DOWN, rect, rect);
+ }
+
+ @SmallTest
+ public void testOverlapBeamsRightLeftUpToEdge() {
+ final Rect rect1 = new Rect(0, 0, 20, 20);
+ final Rect rect2 = new Rect(rect1);
+
+ // just below bottom edge
+ rect2.offset(0, rect1.height() - 1);
+ assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+ // at edge
+ rect2.offset(0, 1);
+ assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+ // just beyond
+ rect2.offset(0, 1);
+ assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+ // just below top edge
+ rect2.set(rect1);
+ rect2.offset(0, -(rect1.height() - 1));
+ assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+ // at top edge
+ rect2.offset(0, -1);
+ assertBeamsOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_RIGHT, rect1, rect2);
+
+ // just beyond top edge
+ rect2.offset(0, -1);
+ assertBeamsDontOverlap(View.FOCUS_LEFT, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_RIGHT, rect1, rect2);
+ }
+
+ @SmallTest
+ public void testOverlapBeamsUpDownUpToEdge() {
+ final Rect rect1 = new Rect(0, 0, 20, 20);
+ final Rect rect2 = new Rect(rect1);
+
+ // just short of right edge
+ rect2.offset(rect1.width() - 1, 0);
+ assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+ // at edge
+ rect2.offset(1, 0);
+ assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+ // just beyond
+ rect2.offset(1, 0);
+ assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+ // just short of left edge
+ rect2.set(rect1);
+ rect2.offset(-(rect1.width() - 1), 0);
+ assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+ // at edge
+ rect2.offset(-1, 0);
+ assertBeamsOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsOverlap(View.FOCUS_DOWN, rect1, rect2);
+
+ // just beyond edge
+ rect2.offset(-1, 0);
+ assertBeamsDontOverlap(View.FOCUS_UP, rect1, rect2);
+ assertBeamsDontOverlap(View.FOCUS_DOWN, rect1, rect2);
+ }
+
+ @SmallTest
+ public void testDirectlyAboveTrumpsAboveLeft() {
+ Rect src = new Rect(0, 50, 20, 70); // src (left, top, right, bottom)
+
+ Rect directlyAbove = new Rect(src);
+ directlyAbove.offset(0, -(1 + src.height()));
+
+ Rect aboveLeft = new Rect(src);
+ aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
+
+ assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
+ }
+
+ @SmallTest
+ public void testAboveInBeamTrumpsSlightlyCloserOutOfBeam() {
+ Rect src = new Rect(0, 50, 20, 70); // src (left, top, right, bottom)
+
+ Rect directlyAbove = new Rect(src);
+ directlyAbove.offset(0, -(1 + src.height()));
+
+ Rect aboveLeft = new Rect(src);
+ aboveLeft.offset(-(1 + src.width()), -(1 + src.height()));
+
+ // offset directly above a little further up
+ directlyAbove.offset(0, -5);
+ assertBetterCandidate(View.FOCUS_UP, src, directlyAbove, aboveLeft);
+ }
+
+ @SmallTest
+ public void testOutOfBeamBeatsInBeamUp() {
+
+ Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
+
+ Rect aboveLeftOfBeam = new Rect(src);
+ aboveLeftOfBeam.offset(-(src.width() + 1), -src.height());
+ assertBeamsDontOverlap(View.FOCUS_UP, src, aboveLeftOfBeam);
+
+ Rect aboveInBeam = new Rect(src);
+ aboveInBeam.offset(0, -src.height());
+ assertBeamsOverlap(View.FOCUS_UP, src, aboveInBeam);
+
+ // in beam wins
+ assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
+
+ // still wins while aboveInBeam's bottom edge is < out of beams' top
+ aboveInBeam.offset(0, -(aboveLeftOfBeam.height() - 1));
+ assertTrue("aboveInBeam.bottom > aboveLeftOfBeam.top", aboveInBeam.bottom > aboveLeftOfBeam.top);
+ assertBetterCandidate(View.FOCUS_UP, src, aboveInBeam, aboveLeftOfBeam);
+
+ // cross the threshold: the out of beam prevails
+ aboveInBeam.offset(0, -1);
+ assertEquals(aboveInBeam.bottom, aboveLeftOfBeam.top);
+ assertBetterCandidate(View.FOCUS_UP, src, aboveLeftOfBeam, aboveInBeam);
+ }
+
+ /**
+ * A non-candidate (even a much closer one) is always a worse choice
+ * than a real candidate.
+ */
+ @MediumTest
+ public void testSomeCandidateBetterThanNonCandidate() {
+ Rect src = new Rect(0, 0, 50, 50); // (left, top, right, bottom)
+
+ Rect nonCandidate = new Rect(src);
+ nonCandidate.offset(src.width() + 1, 0);
+
+ assertIsNotCandidate(View.FOCUS_LEFT, src, nonCandidate);
+
+ Rect candidate = new Rect(src);
+ candidate.offset(-(4 * src.width()), 0);
+ assertDirectionIsCandidate(View.FOCUS_LEFT, src, candidate);
+
+ assertBetterCandidate(View.FOCUS_LEFT, src, candidate, nonCandidate);
+ }
+
+ /**
+ * Grabbed from {@link com.android.frameworktest.focus.VerticalFocusSearchTest#testSearchFromMidLeft()}
+ */
+ @SmallTest
+ public void testVerticalFocusSearchScenario() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 109, 153, 169), // src
+ new Rect(166, 169, 319, 229), // expectedbetter
+ new Rect(0, 229, 320, 289)); // expectedworse
+
+ // failing test 4/10/2008, the values were tweaked somehow in functional
+ // test...
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 91, 153, 133), // src
+ new Rect(166, 133, 319, 175), // expectedbetter
+ new Rect(0, 175, 320, 217)); // expectedworse
+
+ }
+
+ /**
+ * Example: going down from a thin button all the way to the left of a
+ * screen where, just below, is a very wide button, and just below that,
+ * is an equally skinny button all the way to the left. want to make
+ * sure any minor axis factor doesn't override the fact that the one below
+ * in vertical beam should be next focus
+ */
+ @SmallTest
+ public void testBeamsOverlapMajorAxisCloserMinorAxisFurther() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 100, 100), // src
+ new Rect(0, 100, 480, 200), // expectedbetter
+ new Rect(0, 200, 100, 300)); // expectedworse
+ }
+
+ /**
+ * Real scenario grabbed from song playback screen.
+ */
+ @SmallTest
+ public void testMusicPlaybackScenario() {
+ assertBetterCandidate(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(227, 185, 312, 231), // src
+ new Rect(195, 386, 266, 438), // expectedbetter
+ new Rect(124, 386, 195, 438)); // expectedworse
+ }
+
+ /**
+ * more generalized version of {@link #testMusicPlaybackScenario()}
+ */
+ @SmallTest
+ public void testOutOfBeamOverlapBeatsOutOfBeamFurtherOnMajorAxis() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50), // src
+ new Rect(60, 40, 110, 90), // expectedbetter
+ new Rect(60, 70, 110, 120)); // expectedworse
+ }
+
+ /**
+ * Make sure that going down prefers views that are actually
+ * down (and not those next to but still a candidate because
+ * they are overlapping on the major axis)
+ */
+ @SmallTest
+ public void testInBeamTrumpsOutOfBeamOverlapping() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50), // src
+ new Rect(0, 60, 50, 110), // expectedbetter
+ new Rect(51, 1, 101, 51)); // expectedworse
+ }
+
+ @SmallTest
+ public void testOverlappingBeatsNonOverlapping() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 50, 50), // src
+ new Rect(0, 40, 50, 90), // expectedbetter
+ new Rect(0, 75, 50, 125)); // expectedworse
+ }
+
+ @SmallTest
+ public void testEditContactScenarioLeftFromDiscardChangesGoesToSaveContactInLandscape() {
+ assertBetterCandidate(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(357, 258, 478, 318), // src
+ new Rect(2, 258, 100, 318), // better
+ new Rect(106, 120, 424, 184)); // worse
+ }
+
+ /**
+ * A dial pad with 9 squares arranged in a grid. no padding, so
+ * the edges are equal. see {@link com.android.frameworktest.focus.LinearLayoutGrid}
+ */
+ @SmallTest
+ public void testGridWithTouchingEdges() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(106, 49, 212, 192), // src
+ new Rect(106, 192, 212, 335), // better
+ new Rect(0, 192, 106, 335)); // worse
+
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(106, 49, 212, 192), // src
+ new Rect(106, 192, 212, 335), // better
+ new Rect(212, 192, 318, 335)); // worse
+ }
+
+ @SmallTest
+ public void testSearchFromEmptyRect() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 0, 0), // src
+ new Rect(0, 0, 320, 45), // better
+ new Rect(0, 45, 320, 545)); // worse
+ }
+
+ /**
+ * Reproduce bug 1124559, drilling down to actual bug
+ * (majorAxisDistance was wrong for direction left)
+ */
+ @SmallTest
+ public void testGmailReplyButtonsScenario() {
+ assertBetterCandidate(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417), // src
+ new Rect(102, 380, 210, 417), // better
+ new Rect(111, 443, 206, 480)); // worse
+
+ assertBeamBeats(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417), // src
+ new Rect(102, 380, 210, 417), // better
+ new Rect(111, 443, 206, 480)); // worse
+
+ assertBeamsOverlap(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417),
+ new Rect(102, 380, 210, 417));
+
+ assertBeamsDontOverlap(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417),
+ new Rect(111, 443, 206, 480));
+
+ assertTrue(
+ "major axis distance less than major axis distance to "
+ + "far edge",
+ FocusFinderHelper.majorAxisDistance(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417),
+ new Rect(102, 380, 210, 417)) <
+ FocusFinderHelper.majorAxisDistanceToFarEdge(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(223, 380, 312, 417),
+ new Rect(111, 443, 206, 480)));
+ }
+
+ @SmallTest
+ public void testGmailScenarioBug1203288() {
+ assertBetterCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 2, 480, 82), // src
+ new Rect(344, 87, 475, 124), // better
+ new Rect(0, 130, 480, 203)); // worse
+ }
+
+ @SmallTest
+ public void testHomeShortcutScenarioBug1295354() {
+ assertBetterCandidate(View.FOCUS_RIGHT,
+ // L T R B
+ new Rect(3, 338, 77, 413), // src
+ new Rect(163, 338, 237, 413), // better
+ new Rect(83, 38, 157, 113)); // worse
+ }
+
+ @SmallTest
+ public void testBeamAlwaysBeatsHoriz() {
+ assertBetterCandidate(View.FOCUS_RIGHT,
+ // L T R B
+ new Rect(0, 0, 50, 50), // src
+ new Rect(150, 0, 200, 50), // better, (way further, but in beam)
+ new Rect(60, 51, 110, 101)); // worse, even though it is closer
+
+ assertBetterCandidate(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(150, 0, 200, 50), // src
+ new Rect(0, 50, 50, 50), // better, (way further, but in beam)
+ new Rect(49, 99, 149, 101)); // worse, even though it is closer
+ }
+
+ @SmallTest
+ public void testIsCandidateOverlappingEdgeFromEmptyRect() {
+ assertDirectionIsCandidate(View.FOCUS_DOWN,
+ // L T R B
+ new Rect(0, 0, 0, 0), // src
+ new Rect(0, 0, 20, 1)); // candidate
+
+ assertDirectionIsCandidate(View.FOCUS_UP,
+ // L T R B
+ new Rect(0, 0, 0, 0), // src
+ new Rect(0, -1, 20, 0)); // candidate
+
+ assertDirectionIsCandidate(View.FOCUS_LEFT,
+ // L T R B
+ new Rect(0, 0, 0, 0), // src
+ new Rect(-1, 0, 0, 20)); // candidate
+
+ assertDirectionIsCandidate(View.FOCUS_RIGHT,
+ // L T R B
+ new Rect(0, 0, 0, 0), // src
+ new Rect(0, 0, 1, 20)); // candidate
+ }
+
+ private void assertBeamsOverlap(int direction, Rect rect1, Rect rect2) {
+ String directionStr = validateAndGetStringFor(direction);
+ String assertMsg = String.format("Expected beams to overlap in direction %s "
+ + "for rectangles %s and %s", directionStr, rect1, rect2);
+ assertTrue(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
+ }
+
+ private void assertBeamsDontOverlap(int direction, Rect rect1, Rect rect2) {
+ String directionStr = validateAndGetStringFor(direction);
+ String assertMsg = String.format("Expected beams not to overlap in direction %s "
+ + "for rectangles %s and %s", directionStr, rect1, rect2);
+ assertFalse(assertMsg, mFocusFinder.beamsOverlap(direction, rect1, rect2));
+ }
+
+ /**
+ * Assert that particular rect is a better focus search candidate from a
+ * source rect than another.
+ * @param direction The direction of focus search.
+ * @param srcRect The src rectangle.
+ * @param expectedBetter The candidate that should be better.
+ * @param expectedWorse The candidate that should be worse.
+ */
+ private void assertBetterCandidate(int direction, Rect srcRect,
+ Rect expectedBetter, Rect expectedWorse) {
+
+ String directionStr = validateAndGetStringFor(direction);
+ String assertMsg = String.format(
+ "expected %s to be a better focus search candidate than "
+ + "%s when searching "
+ + "from %s in direction %s",
+ expectedBetter, expectedWorse, srcRect, directionStr);
+
+ assertTrue(assertMsg,
+ mFocusFinder.isBetterCandidate(direction, srcRect,
+ expectedBetter, expectedWorse));
+
+ assertMsg = String.format(
+ "expected %s to not be a better focus search candidate than "
+ + "%s when searching "
+ + "from %s in direction %s",
+ expectedWorse, expectedBetter, srcRect, directionStr);
+
+ assertFalse(assertMsg,
+ mFocusFinder.isBetterCandidate(direction, srcRect,
+ expectedWorse, expectedBetter));
+ }
+
+ private void assertIsNotCandidate(int direction, Rect src, Rect dest) {
+ String directionStr = validateAndGetStringFor(direction);
+
+ final String assertMsg = String.format(
+ "expected going from %s to %s in direction %s to be an invalid "
+ + "focus search candidate",
+ src, dest, directionStr);
+ assertFalse(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
+ }
+
+ private void assertBeamBeats(int direction, Rect srcRect,
+ Rect rect1, Rect rect2) {
+
+ String directionStr = validateAndGetStringFor(direction);
+ String assertMsg = String.format(
+ "expecting %s to beam beat %s w.r.t %s in direction %s",
+ rect1, rect2, srcRect, directionStr);
+ assertTrue(assertMsg, mFocusFinder.beamBeats(direction, srcRect, rect1, rect2));
+ }
+
+
+ private void assertDirectionIsCandidate(int direction, Rect src, Rect dest) {
+ String directionStr = validateAndGetStringFor(direction);
+
+ final String assertMsg = String.format(
+ "expected going from %s to %s in direction %s to be a valid "
+ + "focus search candidate",
+ src, dest, directionStr);
+ assertTrue(assertMsg, mFocusFinder.isCandidate(src, dest, direction));
+ }
+
+ private String validateAndGetStringFor(int direction) {
+ String directionStr = "??";
+ switch(direction) {
+ case View.FOCUS_UP:
+ directionStr = "FOCUS_UP";
+ break;
+ case View.FOCUS_DOWN:
+ directionStr = "FOCUS_DOWN";
+ break;
+ case View.FOCUS_LEFT:
+ directionStr = "FOCUS_LEFT";
+ break;
+ case View.FOCUS_RIGHT:
+ directionStr = "FOCUS_RIGHT";
+ break;
+ default:
+ fail("passed in unknown direction, ya blewit!");
+ }
+ return directionStr;
+ }
+
+
+}
diff --git a/tests/CoreTests/android/view/MockView.java b/tests/CoreTests/android/view/MockView.java
new file mode 100644
index 0000000..1d416bd
--- /dev/null
+++ b/tests/CoreTests/android/view/MockView.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+/**
+ * Mock View class for testing
+ */
+
+public class MockView extends View{
+
+}
diff --git a/tests/CoreTests/android/view/ViewGroupAttributesTest.java b/tests/CoreTests/android/view/ViewGroupAttributesTest.java
new file mode 100644
index 0000000..b4ef0e7
--- /dev/null
+++ b/tests/CoreTests/android/view/ViewGroupAttributesTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ViewGroupAttributesTest extends AndroidTestCase {
+
+ private MyViewGroup mViewGroup;
+
+ private static final class MyViewGroup extends ViewGroup {
+
+ public MyViewGroup(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ }
+
+ @Override
+ public boolean isChildrenDrawnWithCacheEnabled() {
+ return super.isChildrenDrawnWithCacheEnabled();
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mViewGroup = new MyViewGroup(getContext());
+ }
+
+ @SmallTest
+ public void testDescendantFocusabilityEnum() {
+ assertEquals("expected ViewGroup.FOCUS_BEFORE_DESCENDANTS to be default",
+ ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+ // remember some state before we muck with flags
+ final boolean isAnimationCachEnabled = mViewGroup.isAnimationCacheEnabled();
+ final boolean isAlwaysDrawnWithCacheEnabled = mViewGroup.isAlwaysDrawnWithCacheEnabled();
+ final boolean isChildrenDrawnWithCacheEnabled = mViewGroup.isChildrenDrawnWithCacheEnabled();
+
+ mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
+ assertEquals(ViewGroup.FOCUS_AFTER_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+ mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
+ assertEquals(ViewGroup.FOCUS_BLOCK_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+ mViewGroup.setDescendantFocusability(ViewGroup.FOCUS_BEFORE_DESCENDANTS);
+ assertEquals(ViewGroup.FOCUS_BEFORE_DESCENDANTS, mViewGroup.getDescendantFocusability());
+
+ // verify we didn't change something unrelated
+ final String msg = "setDescendantFocusability messed with an unrelated flag";
+ assertEquals(msg, isAnimationCachEnabled, mViewGroup.isAnimationCacheEnabled());
+ assertEquals(msg, isAlwaysDrawnWithCacheEnabled, mViewGroup.isAlwaysDrawnWithCacheEnabled());
+ assertEquals(msg, isChildrenDrawnWithCacheEnabled, mViewGroup.isChildrenDrawnWithCacheEnabled());
+ }
+
+ @SmallTest
+ public void testWrongIntSetForDescendantFocusabilityEnum() {
+ try {
+ mViewGroup.setDescendantFocusability(0);
+ fail("expected setting wrong flag to throw an exception");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+}
diff --git a/tests/CoreTests/android/webkit/CookieTest.java b/tests/CoreTests/android/webkit/CookieTest.java
new file mode 100644
index 0000000..1c3d671
--- /dev/null
+++ b/tests/CoreTests/android/webkit/CookieTest.java
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.webkit;
+
+import android.content.Context;
+import android.test.AndroidTestCase;
+import android.util.Log;
+import android.webkit.CookieManager;
+import android.webkit.CookieSyncManager;
+
+public class CookieTest extends AndroidTestCase {
+
+ /**
+ * To run these tests: $ mmm frameworks/base/tests/CoreTests/android && adb
+ * remount && adb sync $ adb shell am instrument -w \ -e class
+ * android.webkit.CookieTest \
+ * android.core/android.test.InstrumentationTestRunner
+ */
+
+ private CookieManager mCookieManager;
+
+ @Override
+ public void setContext(Context context) {
+ assertTrue(mContext == null);
+ super.setContext(context);
+ CookieSyncManager.createInstance(context);
+ mCookieManager = CookieManager.getInstance();
+ mCookieManager.removeAllCookie();
+ }
+
+ public void testParse() {
+ mCookieManager.removeAllCookie();
+ String url = "http://www.foo.com";
+
+ // basic
+ mCookieManager.setCookie(url, "a=b");
+ String cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b"));
+
+ // quoted
+ mCookieManager.setCookie(url, "c=\"d;\"");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b; c=\"d;\""));
+ }
+
+ public void testDomain() {
+ mCookieManager.removeAllCookie();
+ String url = "http://www.foo.com";
+
+ // basic
+ mCookieManager.setCookie(url, "a=b");
+ String cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b"));
+
+ // no cross domain cookie
+ cookie = mCookieManager.getCookie("http://bar.com");
+ assertTrue(cookie == null);
+
+ // more than one cookie
+ mCookieManager.setCookie(url, "c=d; domain=.foo.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b; c=d"));
+
+ // host cookie should not be accessible from a sub-domain.
+ cookie = mCookieManager.getCookie("http://bar.www.foo.com");
+ assertTrue(cookie.equals("c=d"));
+
+ // test setting a domain= that doesn't start w/ a dot, should
+ // treat it as a domain cookie, as if there was a pre-pended dot.
+ mCookieManager.setCookie(url, "e=f; domain=www.foo.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=b; c=d; e=f"));
+ cookie = mCookieManager.getCookie("http://sub.www.foo.com");
+ assertTrue(cookie.equals("c=d; e=f"));
+ cookie = mCookieManager.getCookie("http://foo.com");
+ assertTrue(cookie.equals("c=d"));
+ }
+
+ public void testSubDomain() {
+ mCookieManager.removeAllCookie();
+ String url_abcd = "http://a.b.c.d.com";
+ String url_bcd = "http://b.c.d.com";
+ String url_cd = "http://c.d.com";
+ String url_d = "http://d.com";
+
+ mCookieManager.setCookie(url_abcd, "a=1; domain=.a.b.c.d.com");
+ mCookieManager.setCookie(url_abcd, "b=2; domain=.b.c.d.com");
+ mCookieManager.setCookie(url_abcd, "c=3; domain=.c.d.com");
+ mCookieManager.setCookie(url_abcd, "d=4; domain=.d.com");
+
+ String cookie = mCookieManager.getCookie(url_abcd);
+ assertTrue(cookie.equals("a=1; b=2; c=3; d=4"));
+ cookie = mCookieManager.getCookie(url_bcd);
+ assertTrue(cookie.equals("b=2; c=3; d=4"));
+ cookie = mCookieManager.getCookie(url_cd);
+ assertTrue(cookie.equals("c=3; d=4"));
+ cookie = mCookieManager.getCookie(url_d);
+ assertTrue(cookie.equals("d=4"));
+
+ // check that the same cookie can exist on different sub-domains.
+ mCookieManager.setCookie(url_bcd, "x=bcd; domain=.b.c.d.com");
+ mCookieManager.setCookie(url_bcd, "x=cd; domain=.c.d.com");
+ cookie = mCookieManager.getCookie(url_bcd);
+ assertTrue(cookie.equals("b=2; c=3; d=4; x=bcd; x=cd"));
+ cookie = mCookieManager.getCookie(url_cd);
+ assertTrue(cookie.equals("c=3; d=4; x=cd"));
+ }
+
+ public void testInvalidDomain() {
+ mCookieManager.removeAllCookie();
+ String url = "http://foo.bar.com";
+
+ mCookieManager.setCookie(url, "a=1; domain=.yo.foo.bar.com");
+ String cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "b=2; domain=.foo.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "c=3; domain=.bar.foo.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "d=4; domain=.foo.bar.com.net");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "e=5; domain=.ar.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "f=6; domain=.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "g=7; domain=.co.uk");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "h=8; domain=.foo.bar.com.com");
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+ }
+
+ public void testPath() {
+ mCookieManager.removeAllCookie();
+ String url = "http://www.foo.com";
+
+ mCookieManager.setCookie(url, "a=b; path=/wee");
+ String cookie = mCookieManager.getCookie(url + "/wee");
+ assertTrue(cookie.equals("a=b"));
+ cookie = mCookieManager.getCookie(url + "/wee/");
+ assertTrue(cookie.equals("a=b"));
+ cookie = mCookieManager.getCookie(url + "/wee/hee");
+ assertTrue(cookie.equals("a=b"));
+ cookie = mCookieManager.getCookie(url + "/wee/hee/more");
+ assertTrue(cookie.equals("a=b"));
+ cookie = mCookieManager.getCookie(url + "/weehee");
+ assertTrue(cookie == null);
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie == null);
+
+ mCookieManager.setCookie(url, "a=c; path=");
+ cookie = mCookieManager.getCookie(url + "/wee");
+ assertTrue(cookie.equals("a=b; a=c"));
+ cookie = mCookieManager.getCookie(url);
+ assertTrue(cookie.equals("a=c"));
+
+ mCookieManager.setCookie(url, "a=d");
+ cookie = mCookieManager.getCookie(url + "/wee");
+ assertTrue(cookie.equals("a=b; a=c; a=d"));
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java
new file mode 100644
index 0000000..81727e4
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/ATResponseParserTest.java
@@ -0,0 +1,113 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ATResponseParserTest extends TestCase {
+ @SmallTest
+ public void testBasic() throws Exception {
+ ATResponseParser p = new ATResponseParser("+CREG: 0");
+
+ assertEquals(0, p.nextInt());
+
+ assertFalse(p.hasMore());
+
+ try {
+ p.nextInt();
+ fail("exception expected");
+ } catch (ATParseEx ex) {
+ //test pass
+ }
+
+ p = new ATResponseParser("+CREG: 0,1");
+ assertEquals(0, p.nextInt());
+ assertEquals(1, p.nextInt());
+ assertFalse(p.hasMore());
+
+ p = new ATResponseParser("+CREG: 0, 1");
+ assertEquals(0, p.nextInt());
+ assertEquals(1, p.nextInt());
+ assertFalse(p.hasMore());
+
+ p = new ATResponseParser("+CREG: 0, 1,");
+ assertEquals(0, p.nextInt());
+ assertEquals(1, p.nextInt());
+ // this seems odd but is probably OK
+ assertFalse(p.hasMore());
+ try {
+ p.nextInt();
+ fail("exception expected");
+ } catch (ATParseEx ex) {
+ //test pass
+ }
+
+ p = new ATResponseParser("+CREG: 0, 1 ");
+ assertEquals(0, p.nextInt());
+ assertEquals(1, p.nextInt());
+ assertFalse(p.hasMore());
+
+ p = new ATResponseParser("0, 1 ");
+ // no prefix -> exception
+ try {
+ p.nextInt();
+ fail("exception expected");
+ } catch (ATParseEx ex) {
+ //test pass
+ }
+
+ p = new ATResponseParser("+CREG: 0, 1, 5");
+ assertFalse(p.nextBoolean());
+ assertTrue(p.nextBoolean());
+ try {
+ // is this over-constraining?
+ p.nextBoolean();
+ fail("exception expected");
+ } catch (ATParseEx ex) {
+ //test pass
+ }
+
+ p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212\",145");
+
+ assertEquals(1, p.nextInt());
+ assertFalse(p.nextBoolean());
+ assertEquals(2, p.nextInt());
+ assertEquals(0, p.nextInt());
+ assertEquals(0, p.nextInt());
+ assertEquals("+18005551212", p.nextString());
+ assertEquals(145, p.nextInt());
+ assertFalse(p.hasMore());
+
+ p = new ATResponseParser("+CLCC: 1,0,2,0,0,\"+18005551212,145");
+
+ assertEquals(1, p.nextInt());
+ assertFalse(p.nextBoolean());
+ assertEquals(2, p.nextInt());
+ assertEquals(0, p.nextInt());
+ assertEquals(0, p.nextInt());
+ try {
+ p.nextString();
+ fail("expected ex");
+ } catch (ATParseEx ex) {
+ //test pass
+ }
+
+ p = new ATResponseParser("+FOO: \"\"");
+ assertEquals("", p.nextString());
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
new file mode 100644
index 0000000..e8bd239
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberUtilsTest.java
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.SpannableStringBuilder;
+import android.telephony.PhoneNumberUtils;
+
+import junit.framework.TestCase;
+
+public class PhoneNumberUtilsTest extends TestCase {
+
+ @SmallTest
+ public void testA() throws Exception {
+ assertEquals(
+ "+17005554141",
+ PhoneNumberUtils.extractNetworkPortion("+17005554141")
+ );
+
+ assertEquals(
+ "+17005554141",
+ PhoneNumberUtils.extractNetworkPortion("+1 (700).555-4141")
+ );
+
+ assertEquals(
+ "17005554141",
+ PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141")
+ );
+
+ // This may seem wrong, but it's probably ok
+ assertEquals(
+ "17005554141*#",
+ PhoneNumberUtils.extractNetworkPortion("1 (700).555-4141*#")
+ );
+
+ assertEquals(
+ "170055541NN",
+ PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN")
+ );
+
+ assertEquals(
+ "170055541NN",
+ PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN,1234")
+ );
+
+ assertEquals(
+ "170055541NN",
+ PhoneNumberUtils.extractNetworkPortion("1 (700).555-41NN;1234")
+ );
+
+ // An MMI string is unperterbed, even though it contains a
+ // (valid in this case) embedded +
+ assertEquals(
+ "**21**17005554141#",
+ PhoneNumberUtils.extractNetworkPortion("**21**+17005554141#")
+ //TODO this is the correct result, although the above
+ //result has been returned since change 31776
+ //"**21**+17005554141#"
+ );
+
+ assertEquals("", PhoneNumberUtils.extractNetworkPortion(""));
+
+ assertEquals("", PhoneNumberUtils.extractNetworkPortion(",1234"));
+
+ byte [] b = new byte[20];
+ b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+ b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0;
+ assertEquals("17005550020",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+ b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xF0;
+ assertEquals("+17005550020",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+ byte[] bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("+17005550020");
+ assertEquals(7, bRet.length);
+ for (int i = 0; i < 7; i++) {
+ assertEquals(b[i], bRet[i]);
+ }
+
+ bRet = PhoneNumberUtils.networkPortionToCalledPartyBCD("7005550020");
+ assertEquals("7005550020",
+ PhoneNumberUtils.calledPartyBCDToString(bRet, 0, bRet.length));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+ b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0;
+ assertEquals("17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0x71; b[2] = (byte) 0x00; b[3] = (byte) 0x55;
+ b[4] = (byte) 0x05; b[5] = (byte) 0x20; b[6] = (byte) 0xB0;
+ assertEquals("+17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 7));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1;
+ assertEquals("*21#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0x2B; b[2] = (byte) 0xB1;
+ assertEquals("#21#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1;
+ assertEquals("*21#+",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 3));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB;
+ assertEquals("**21#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 4));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0xFB;
+ assertEquals("**21#+",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 4));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71;
+ b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+ b[8] = (byte) 0xB0;
+ assertEquals("*99*17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0x9A; b[2] = (byte) 0xA9; b[3] = (byte) 0x71;
+ b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+ b[8] = (byte) 0xB0;
+ assertEquals("*99*+17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A;
+ b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00;
+ b[8] = (byte) 0x02; b[9] = (byte) 0xFB;
+ assertEquals("**21*17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 10));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0xAA; b[2] = (byte) 0x12; b[3] = (byte) 0x1A;
+ b[4] = (byte) 0x07; b[5] = (byte) 0x50; b[6] = (byte) 0x55; b[7] = (byte) 0x00;
+ b[8] = (byte) 0x02; b[9] = (byte) 0xFB;
+ assertEquals("**21*+17005550020#",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 10));
+
+ b[0] = (byte) 0x81; b[1] = (byte) 0x2A; b[2] = (byte) 0xA1; b[3] = (byte) 0x71;
+ b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+ b[8] = (byte) 0xF0;
+ assertEquals("*21*17005550020",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+ b[0] = (byte) 0x91; b[1] = (byte) 0x2A; b[2] = (byte) 0xB1; b[3] = (byte) 0x71;
+ b[4] = (byte) 0x00; b[5] = (byte) 0x55; b[6] = (byte) 0x05; b[7] = (byte) 0x20;
+ b[8] = (byte) 0xF0;
+ assertEquals("*21#+17005550020",
+ PhoneNumberUtils.calledPartyBCDToString(b, 0, 9));
+
+ assertNull(PhoneNumberUtils.extractNetworkPortion(null));
+ assertNull(PhoneNumberUtils.extractPostDialPortion(null));
+ assertTrue(PhoneNumberUtils.compare(null, null));
+ assertFalse(PhoneNumberUtils.compare(null, "123"));
+ assertFalse(PhoneNumberUtils.compare("123", null));
+ assertNull(PhoneNumberUtils.toCallerIDMinMatch(null));
+ assertNull(PhoneNumberUtils.getStrippedReversed(null));
+ assertNull(PhoneNumberUtils.stringFromStringAndTOA(null, 1));
+ }
+
+ @SmallTest
+ public void testB() throws Exception {
+ assertEquals("", PhoneNumberUtils.extractPostDialPortion("+17005554141"));
+ assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-4141"));
+ assertEquals("", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN"));
+ assertEquals(",1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN,1234"));
+ assertEquals(";1234", PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1234"));
+ assertEquals(";1234,;N",
+ PhoneNumberUtils.extractPostDialPortion("+1 (700).555-41NN;1-2.34 ,;N"));
+ }
+
+ @SmallTest
+ public void testCompare() throws Exception {
+ // this is odd
+ assertFalse(PhoneNumberUtils.compare("", ""));
+
+ assertTrue(PhoneNumberUtils.compare("911", "911"));
+ assertFalse(PhoneNumberUtils.compare("911", "18005550911"));
+ assertTrue(PhoneNumberUtils.compare("5555", "5555"));
+ assertFalse(PhoneNumberUtils.compare("5555", "180055555555"));
+
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "+17005554141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "+1 (700).555-4141,1234"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "17005554141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "7005554141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "5554141"));
+ assertTrue(PhoneNumberUtils.compare("17005554141", "5554141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "01117005554141"));
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "0017005554141"));
+ assertTrue(PhoneNumberUtils.compare("17005554141", "0017005554141"));
+
+
+ assertTrue(PhoneNumberUtils.compare("+17005554141", "**31#+17005554141"));
+
+ assertFalse(PhoneNumberUtils.compare("+1 999 7005554141", "+1 7005554141"));
+ assertTrue(PhoneNumberUtils.compare("011 1 7005554141", "7005554141"));
+
+ assertFalse(PhoneNumberUtils.compare("011 11 7005554141", "+17005554141"));
+
+ assertFalse(PhoneNumberUtils.compare("+17005554141", "7085882300"));
+
+ assertTrue(PhoneNumberUtils.compare("+44 207 792 3490", "0 207 792 3490"));
+
+ assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "00 207 792 3490"));
+ assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "011 207 792 3490"));
+
+ /***** FIXME's ******/
+ //
+ // MMI header should be ignored
+ assertFalse(PhoneNumberUtils.compare("+17005554141", "**31#17005554141"));
+
+ // It's too bad this is false
+ // +44 (0) 207 792 3490 is not a dialable number
+ // but it is commonly how European phone numbers are written
+ assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "+44 (0) 207 792 3490"));
+
+ // The japanese international prefix, for example, messes us up
+ // But who uses a GSM phone in Japan?
+ assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "010 44 207 792 3490"));
+
+ // The Australian one messes us up too
+ assertFalse(PhoneNumberUtils.compare("+44 207 792 3490", "0011 44 207 792 3490"));
+
+ // The Russian trunk prefix messes us up, as does current
+ // Russian area codes (which bein with 0)
+
+ assertFalse(PhoneNumberUtils.compare("+7(095)9100766", "8(095)9100766"));
+
+ // 444 is not a valid country code, but
+ // matchIntlPrefixAndCC doesnt know this
+ assertTrue(PhoneNumberUtils.compare("+444 207 792 3490", "0 207 792 3490"));
+ }
+
+
+ @SmallTest
+ public void testToCallerIDIndexable() throws Exception {
+ assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("17005554141"));
+ assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141"));
+ assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141,1234"));
+ assertEquals("14145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-4141;1234"));
+
+ //this seems wrong, or at least useless
+ assertEquals("NN145", PhoneNumberUtils.toCallerIDMinMatch("1-700-555-41NN"));
+
+ //<shrug> -- these are all not useful, but not terribly wrong
+ assertEquals("", PhoneNumberUtils.toCallerIDMinMatch(""));
+ assertEquals("0032", PhoneNumberUtils.toCallerIDMinMatch("2300"));
+ assertEquals("0032+", PhoneNumberUtils.toCallerIDMinMatch("+2300"));
+ assertEquals("#130#", PhoneNumberUtils.toCallerIDMinMatch("*#031#"));
+ }
+
+ @SmallTest
+ public void testGetIndexable() throws Exception {
+ assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141"));
+ assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141,1234"));
+ assertEquals("14145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-4141;1234"));
+
+ //this seems wrong, or at least useless
+ assertEquals("NN145550071", PhoneNumberUtils.getStrippedReversed("1-700-555-41NN"));
+
+ //<shrug> -- these are all not useful, but not terribly wrong
+ assertEquals("", PhoneNumberUtils.getStrippedReversed(""));
+ assertEquals("0032", PhoneNumberUtils.getStrippedReversed("2300"));
+ assertEquals("0032+", PhoneNumberUtils.getStrippedReversed("+2300"));
+ assertEquals("#130#*", PhoneNumberUtils.getStrippedReversed("*#031#"));
+ }
+
+ @SmallTest
+ public void testNanpFormatting() {
+ SpannableStringBuilder number = new SpannableStringBuilder();
+ number.append("8005551212");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("800-555-1212", number.toString());
+
+ number.clear();
+ number.append("800555121");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("800-555-121", number.toString());
+
+ number.clear();
+ number.append("555-1212");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("555-1212", number.toString());
+
+ number.clear();
+ number.append("800-55512");
+ PhoneNumberUtils.formatNanpNumber(number);
+ assertEquals("800-555-12", number.toString());
+ }
+
+ @SmallTest
+ public void testConvertKeypadLettersToDigits() {
+ assertEquals("1-800-4664-411",
+ PhoneNumberUtils.convertKeypadLettersToDigits("1-800-GOOG-411"));
+ assertEquals("18004664411",
+ PhoneNumberUtils.convertKeypadLettersToDigits("1800GOOG411"));
+ assertEquals("1-800-466-4411",
+ PhoneNumberUtils.convertKeypadLettersToDigits("1-800-466-4411"));
+ assertEquals("18004664411",
+ PhoneNumberUtils.convertKeypadLettersToDigits("18004664411"));
+ assertEquals("222-333-444-555-666-7777-888-9999",
+ PhoneNumberUtils.convertKeypadLettersToDigits(
+ "ABC-DEF-GHI-JKL-MNO-PQRS-TUV-WXYZ"));
+ assertEquals("222-333-444-555-666-7777-888-9999",
+ PhoneNumberUtils.convertKeypadLettersToDigits(
+ "abc-def-ghi-jkl-mno-pqrs-tuv-wxyz"));
+ assertEquals("(800) 222-3334",
+ PhoneNumberUtils.convertKeypadLettersToDigits("(800) ABC-DEFG"));
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java
new file mode 100644
index 0000000..88eaecd
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/PhoneNumberWatcherTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import android.telephony.PhoneNumberFormattingTextWatcher;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.text.Selection;
+import android.text.SpannableStringBuilder;
+import android.text.TextWatcher;
+
+import junit.framework.TestCase;
+
+public class PhoneNumberWatcherTest extends TestCase {
+ @SmallTest
+ public void testHyphenation() throws Exception {
+ SpannableStringBuilder number = new SpannableStringBuilder();
+ TextWatcher tw = new PhoneNumberFormattingTextWatcher();
+ number.append("555-1212");
+ // Move the cursor to the left edge
+ Selection.setSelection(number, 0);
+ tw.beforeTextChanged(number, 0, 0, 1);
+ // Insert an 8 at the beginning
+ number.insert(0, "8");
+ tw.afterTextChanged(number);
+ assertEquals("855-512-12", number.toString());
+ }
+
+ @SmallTest
+ public void testHyphenDeletion() throws Exception {
+ SpannableStringBuilder number = new SpannableStringBuilder();
+ TextWatcher tw = new PhoneNumberFormattingTextWatcher();
+ number.append("555-1212");
+ // Move the cursor to after the hyphen
+ Selection.setSelection(number, 4);
+ // Delete the hyphen
+ tw.beforeTextChanged(number, 3, 1, 0);
+ number.delete(3, 4);
+ tw.afterTextChanged(number);
+ // Make sure that it deleted the character before the hyphen
+ assertEquals("551-212", number.toString());
+
+ // Make sure it deals with left edge boundary case
+ number.insert(0, "-");
+ Selection.setSelection(number, 1);
+ tw.beforeTextChanged(number, 0, 1, 0);
+ number.delete(0, 1);
+ tw.afterTextChanged(number);
+ // Make sure that it deleted the character before the hyphen
+ assertEquals("551-212", number.toString());
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
new file mode 100644
index 0000000..eb2bd23
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TelephonyTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+import com.android.internal.telephony.gsm.AdnRecordTest;
+import com.android.internal.telephony.gsm.GSMPhoneTest;
+import com.android.internal.telephony.gsm.GsmAlphabetTest;
+import com.android.internal.telephony.gsm.SMSDispatcherTest;
+import com.android.internal.telephony.gsm.SimPhoneBookTest;
+import com.android.internal.telephony.gsm.SimSmsTest;
+import com.android.internal.telephony.gsm.SimUtilsTest;
+
+import junit.framework.TestSuite;
+
+/**
+ * To run these tests:
+ * $ mmm java/tests && adb sync
+ * $ adb shell am instrument -w \
+ * -e class com.android.internal.telephony.TelephonyTests \
+ * android.core/android.test.InstrumentationTestRunner
+ */
+public class TelephonyTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(TelephonyTests.class.getName());
+
+ suite.addTestSuite(PhoneNumberWatcherTest.class);
+ suite.addTestSuite(ATResponseParserTest.class);
+ suite.addTestSuite(PhoneNumberUtilsTest.class);
+ suite.addTestSuite(SMSDispatcherTest.class);
+ //suite.addTestSuite(GSMPhoneTest.class);
+ suite.addTestSuite(AdnRecordTest.class);
+ suite.addTestSuite(GsmAlphabetTest.class);
+ suite.addTestSuite(SimUtilsTest.class);
+ suite.addTestSuite(SimPhoneBookTest.class);
+ suite.addTestSuite(SimSmsTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java
new file mode 100644
index 0000000..427795b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/TestPhoneNotifier.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony;
+
+/**
+ * Stub class used for unit tests
+ */
+
+public class TestPhoneNotifier implements PhoneNotifier {
+ public TestPhoneNotifier() {
+ }
+
+ public void notifyPhoneState(Phone sender) {
+ }
+
+ public void notifyServiceState(Phone sender) {
+ }
+
+ public void notifyCellLocation(Phone sender) {
+ }
+
+ public void notifySignalStrength(Phone sender) {
+ }
+
+ public void notifyMessageWaitingChanged(Phone sender) {
+ }
+
+ public void notifyCallForwardingChanged(Phone sender) {
+ }
+
+ public void notifyDataConnection(Phone sender, String reason) {
+ }
+
+ public void notifyDataConnectionFailed(Phone sender, String reason) {
+ }
+
+ public void notifyDataActivity(Phone sender) {
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java
new file mode 100644
index 0000000..6cafdf0
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/AdnRecordTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * {@hide}
+ */
+public class AdnRecordTest extends TestCase {
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ AdnRecord adn;
+
+ //
+ // Typical record
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C07918150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("+18056377243", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // Empty records, empty strings
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF"));
+
+ assertEquals("", adn.getAlphaTag());
+ assertEquals("", adn.getNumber());
+ assertTrue(adn.isEmpty());
+
+ //
+ // Record too short
+ //
+ adn = new AdnRecord(SimUtils.hexStringToBytes( "FF"));
+
+ assertEquals("", adn.getAlphaTag());
+ assertEquals("", adn.getNumber());
+ assertTrue(adn.isEmpty());
+
+ //
+ // TOA = 0xff ("control string")
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C07FF8150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("18056377243", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // TOA = 0x81 (unknown)
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C07818150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("18056377243", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // Number Length is too long
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C0F918150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // Number Length is zero (invalid)
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C00918150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // Number Length is 2, first number byte is FF, TOA is international
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C0291FF50367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // Number Length is 2, first number digit is valid, TOA is international
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes("566F696365204D61696C0291F150367742F3FFFFFFFFFFFF"));
+
+ assertEquals("Voice Mail", adn.getAlphaTag());
+ assertEquals("+1", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // An extended record
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes(
+ "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678", adn.getNumber());
+ assertFalse(adn.isEmpty());
+ assertTrue(adn.hasExtendedRecord());
+
+ adn.appendExtRecord(SimUtils.hexStringToBytes("0206092143658709ffffffffff"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678901234567890", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // An extended record with an invalid extension
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes(
+ "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678", adn.getNumber());
+ assertFalse(adn.isEmpty());
+ assertTrue(adn.hasExtendedRecord());
+
+ adn.appendExtRecord(SimUtils.hexStringToBytes("0106092143658709ffffffffff"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678", adn.getNumber());
+ assertFalse(adn.isEmpty());
+
+ //
+ // An extended record with an invalid extension
+ //
+ adn = new AdnRecord(
+ SimUtils.hexStringToBytes(
+ "4164676A6DFFFFFFFFFFFFFFFFFFFFFF0B918188551512C221436587FF01"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678", adn.getNumber());
+ assertFalse(adn.isEmpty());
+ assertTrue(adn.hasExtendedRecord());
+
+ adn.appendExtRecord(SimUtils.hexStringToBytes("020B092143658709ffffffffff"));
+
+ assertEquals("Adgjm", adn.getAlphaTag());
+ assertEquals("+18885551212,12345678", adn.getNumber());
+ assertFalse(adn.isEmpty());
+ }
+}
+
+
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
new file mode 100644
index 0000000..7107412
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMPhoneTest.java
@@ -0,0 +1,1938 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF GSMTestHandler.ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Process;
+import android.telephony.ServiceState;
+import android.test.AndroidTestCase;
+import android.test.PerformanceTestCase;
+import android.util.Log;
+
+import com.android.internal.telephony.Call;
+import com.android.internal.telephony.CallStateException;
+import com.android.internal.telephony.Connection;
+import com.android.internal.telephony.MmiCode;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.TestPhoneNotifier;
+import com.android.internal.telephony.gsm.CallFailCause;
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.gsm.GSMTestHandler;
+import com.android.internal.telephony.gsm.GsmMmiCode;
+import com.android.internal.telephony.gsm.SuppServiceNotification;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.test.SimulatedRadioControl;
+
+import java.util.List;
+
+
+public class GSMPhoneTest extends AndroidTestCase implements PerformanceTestCase {
+ private SimulatedRadioControl mRadioControl;
+ private GSMPhone mGSMPhone;
+ private GSMTestHandler mGSMTestHandler;
+ private Handler mHandler;
+
+ private static final int EVENT_PHONE_STATE_CHANGED = 1;
+ private static final int EVENT_DISCONNECT = 2;
+ private static final int EVENT_RINGING = 3;
+ private static final int EVENT_CHANNEL_OPENED = 4;
+ private static final int EVENT_POST_DIAL = 5;
+ private static final int EVENT_DONE = 6;
+ private static final int EVENT_SSN = 7;
+ private static final int EVENT_MMI_INITIATE = 8;
+ private static final int EVENT_MMI_COMPLETE = 9;
+ private static final int EVENT_IN_SERVICE = 10;
+ private static final int SUPP_SERVICE_FAILED = 11;
+ private static final int SERVICE_STATE_CHANGED = 12;
+ private static final int EVENT_OEM_RIL_MESSAGE = 13;
+ public static final int ANY_MESSAGE = -1;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mGSMTestHandler = new GSMTestHandler(mContext);
+
+ mGSMTestHandler.start();
+ synchronized (mGSMTestHandler) {
+ do {
+ mGSMTestHandler.wait();
+ } while (mGSMTestHandler.getGSMPhone() == null);
+ }
+
+ mGSMPhone = mGSMTestHandler.getGSMPhone();
+ mRadioControl = mGSMTestHandler.getSimulatedCommands();
+
+ mHandler = mGSMTestHandler.getHandler();
+ mGSMPhone.registerForPhoneStateChanged(mHandler, EVENT_PHONE_STATE_CHANGED, null);
+ mGSMPhone.registerForNewRingingConnection(mHandler, EVENT_RINGING, null);
+ mGSMPhone.registerForDisconnect(mHandler, EVENT_DISCONNECT, null);
+
+ mGSMPhone.setOnPostDialCharacter(mHandler, EVENT_POST_DIAL, null);
+
+ mGSMPhone.registerForSuppServiceNotification(mHandler, EVENT_SSN, null);
+ mGSMPhone.registerForMmiInitiate(mHandler, EVENT_MMI_INITIATE, null);
+ mGSMPhone.registerForMmiComplete(mHandler, EVENT_MMI_COMPLETE, null);
+ mGSMPhone.registerForSuppServiceFailed(mHandler, SUPP_SERVICE_FAILED, null);
+
+ mGSMPhone.registerForServiceStateChanged(mHandler, SERVICE_STATE_CHANGED, null);
+
+ // wait until we get phone in both voice and data service
+ Message msg;
+ ServiceState state;
+
+ do {
+ msg = mGSMTestHandler.waitForMessage(SERVICE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
+ state = (ServiceState) ((AsyncResult) msg.obj).result;
+ } while (state.getState() != ServiceState.STATE_IN_SERVICE);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mRadioControl.shutdown();
+
+ mGSMPhone.unregisterForPhoneStateChanged(mHandler);
+ mGSMPhone.unregisterForNewRingingConnection(mHandler);
+ mGSMPhone.unregisterForDisconnect(mHandler);
+ mGSMPhone.setOnPostDialCharacter(mHandler, 0, null);
+ mGSMPhone.unregisterForSuppServiceNotification(mHandler);
+ mGSMPhone.unregisterForMmiInitiate(mHandler);
+ mGSMPhone.unregisterForMmiComplete(mHandler);
+
+ mGSMPhone = null;
+ mRadioControl = null;
+ mHandler = null;
+ mGSMTestHandler.cleanup();
+
+ super.tearDown();
+ }
+
+ // These test can only be run once.
+ public int startPerformance(Intermediates intermediates) {
+ return 1;
+ }
+
+ public boolean isPerformanceOnly() {
+ return false;
+ }
+
+
+ //This test is causing the emulator screen to turn off. I don't understand
+ //why, but I'm removing it until we can figure it out.
+ public void brokenTestGeneral() throws Exception {
+ Connection cn;
+ Message msg;
+ AsyncResult ar;
+
+ // IDLE state
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+ assertFalse(mGSMPhone.canConference());
+
+ // One DIALING connection
+
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ mGSMPhone.dial("+13125551212");
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertEquals(Call.State.DIALING, mGSMPhone.getForegroundCall().getState());
+ assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ /*do {
+ mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ } while (mGSMPhone.getForegroundCall().getConnections().size() == 0);*/
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DIALING,
+ mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+ assertTrue(!cn.isIncoming());
+ assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+ assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // One ALERTING connection
+
+ mRadioControl.progressConnectingCallState();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ }
+ while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ALERTING, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+ assertTrue(!cn.isIncoming());
+ assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+ assertFalse(mGSMPhone.canConference());
+
+ // One ACTIVE connection
+
+ mRadioControl.progressConnectingCallState();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+ cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+ assertTrue(!cn.isIncoming());
+ assertEquals(Connection.PostDialState.COMPLETE, cn.getPostDialState());
+ assertFalse(mGSMPhone.canConference());
+
+ // One disconnected connection
+ mGSMPhone.getForegroundCall().hangup();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+ assertFalse(mGSMPhone.canConference());
+
+ cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ // Back to idle state
+
+ mGSMPhone.clearDisconnected();
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // cn left over from before phone.clearDisconnected();
+
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ // One ringing (INCOMING) call
+
+ mRadioControl.triggerRing("18005551212");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ ar = (AsyncResult) msg.obj;
+ cn = (Connection) ar.result;
+ assertTrue(cn.isRinging());
+ assertEquals(mGSMPhone.getRingingCall(), cn.getCall());
+
+ assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ cn = mGSMPhone.getRingingCall().getConnections().get(0);
+ assertTrue(cn.isIncoming());
+ assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // One mobile terminated active call
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getConnections().size() == 1);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE,
+ mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+ cn = mGSMPhone.getForegroundCall().getConnections().get(0);
+ assertTrue(cn.isIncoming());
+ assertEquals(Connection.PostDialState.NOT_STARTED, cn.getPostDialState());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // One disconnected (local hangup) call
+
+ try {
+ Connection conn;
+ conn = mGSMPhone.getForegroundCall().getConnections().get(0);
+ conn.hangup();
+ } catch (CallStateException ex) {
+ ex.printStackTrace();
+ fail("unexpected ex");
+ }
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED,
+ mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestConnectTime() > 0);
+
+ cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // Back to idle state
+
+ mGSMPhone.clearDisconnected();
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // cn left over from before phone.clearDisconnected();
+
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ // One ringing call
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getConnections().isEmpty());
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.INCOMING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // One rejected call
+ mGSMPhone.rejectCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(1, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getRingingCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getRingingCall().getEarliestConnectTime());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ cn = mGSMPhone.getRingingCall().getEarliestConnection();
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+
+ assertFalse(mGSMPhone.canConference());
+
+ // Back to idle state
+
+ mGSMPhone.clearDisconnected();
+
+ assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestCreateTime());
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ assertFalse(mGSMPhone.canConference());
+ assertEquals(Call.State.DISCONNECTED, cn.getState());
+
+ // One ringing call
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getConnections().isEmpty());
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+ // Ringing call disconnects
+
+ mRadioControl.triggerHangupForeground();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+ assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+
+ // One Ringing Call
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+
+ cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+ // One answered call
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // one holding call
+ mGSMPhone.switchHoldingAndActive();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // one active call
+ mGSMPhone.switchHoldingAndActive();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ }
+ while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // One disconnected call in the foreground slot
+
+ mRadioControl.triggerHangupAll();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+ // Test missed calls
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+ mGSMPhone.rejectCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (msg.what != EVENT_DISCONNECT);
+
+ ar = (AsyncResult) msg.obj;
+ cn = (Connection) ar.result;
+
+ assertEquals(Connection.DisconnectCause.INCOMING_MISSED, cn.getDisconnectCause());
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+
+ // Test incoming not missed calls
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+ cn = mGSMPhone.getRingingCall().getEarliestConnection();
+
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ assertEquals(Connection.DisconnectCause.NOT_DISCONNECTED, cn.getDisconnectCause());
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+
+ try {
+ mGSMPhone.getForegroundCall().hangup();
+ } catch (CallStateException ex) {
+ ex.printStackTrace();
+ fail("unexpected ex");
+ }
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState()
+ != Call.State.DISCONNECTED);
+
+ assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+ //
+ // Test held and hangup held calls
+ //
+
+ // One ALERTING call
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ assertTrue(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ mRadioControl.progressConnectingCallState();
+ mRadioControl.progressConnectingCallState();
+
+ // One ACTIVE call
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ // One ACTIVE call, one ringing call
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ // One HOLDING call, one ACTIVE call
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertTrue(mGSMPhone.canConference());
+
+ // Conference the two
+ mGSMPhone.conference();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertTrue(mGSMPhone.getForegroundCall().isMultiparty());
+ assertFalse(mGSMPhone.canConference());
+
+ // Hold the multiparty call
+ mGSMPhone.switchHoldingAndActive();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ }
+ while (mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertTrue(mGSMPhone.getBackgroundCall().isMultiparty());
+ assertFalse(mGSMPhone.canConference());
+
+ // Multiparty call on hold, call waiting added
+
+ mRadioControl.triggerRing("18005558355");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.RINGING);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertTrue(mGSMPhone.getBackgroundCall().isMultiparty());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertFalse(mGSMPhone.canConference());
+
+ // Hangup conference call, ringing call still around
+ mGSMPhone.getBackgroundCall().hangup();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.DISCONNECTED);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState());
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+
+ // Reject waiting call
+ mGSMPhone.rejectCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.IDLE);
+
+ assertFalse(mGSMPhone.getForegroundCall().isDialingOrAlerting());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+ }
+
+ public void testOutgoingCallFailImmediately() throws Exception {
+ Message msg;
+
+ // Test outgoing call fail-immediately edge case
+ // This happens when a call terminated before ever appearing in a
+ // call list
+ // This should land the immediately-failing call in the
+ // ForegroundCall list as an IDLE call
+ mRadioControl.setNextDialFailImmediately(true);
+
+ Connection cn = mGSMPhone.dial("+13125551212");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+ }
+
+ public void testHangupOnOutgoing() throws Exception {
+ Connection cn;
+ Message msg;
+
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ // Test 1: local hangup in "DIALING" state
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ }
+ while (mGSMPhone.getForegroundCall().getState() != Call.State.DIALING);
+
+ cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+ mGSMPhone.getForegroundCall().hangup();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+ // Test 2: local hangup in "ALERTING" state
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ mRadioControl.progressConnectingCallState();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ }
+ while (mGSMPhone.getForegroundCall().getState() != Call.State.ALERTING);
+
+ cn = mGSMPhone.getForegroundCall().getEarliestConnection();
+
+ mGSMPhone.getForegroundCall().hangup();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Connection.DisconnectCause.LOCAL, cn.getDisconnectCause());
+
+ // Test 3: local immediate hangup before GSM index is
+ // assigned (CallTracker.hangupPendingMO case)
+
+ mRadioControl.pauseResponses();
+
+ cn = mGSMPhone.dial("+13125551212");
+
+ cn.hangup();
+
+ mRadioControl.resumeResponses();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+
+ assertEquals(Connection.DisconnectCause.LOCAL,
+ mGSMPhone.getForegroundCall().getEarliestConnection().getDisconnectCause());
+ }
+
+ public void testHangupOnChannelClose() throws Exception {
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getConnections().isEmpty());
+
+ mRadioControl.shutdown();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ mGSMPhone.clearDisconnected();
+ } while (!mGSMPhone.getForegroundCall().getConnections().isEmpty());
+ }
+
+ public void testIncallMmiCallDeflection() throws Exception {
+ Message msg;
+
+ // establish an active call
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // establish a ringing (WAITING) call
+
+ mRadioControl.triggerRing("18005551212");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering 0 followed by SEND: release all held calls
+ // or sets UDUB for a waiting call.
+ mGSMPhone.handleInCallMmiCommands("0");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // change the active call to holding call
+ mGSMPhone.switchHoldingAndActive();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering 0 followed by SEND: release all held calls
+ // or sets UDUB for a waiting call.
+ mGSMPhone.handleInCallMmiCommands("0");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() == Call.State.HOLDING);
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getBackgroundCall().getState());
+ }
+
+ public void testIncallMmiCallWaiting() throws Exception {
+ Message msg;
+
+ // establish an active call
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // establish a ringing (WAITING) call
+
+ mRadioControl.triggerRing("18005551212");
+
+ do {
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+ } while (msg.what != EVENT_RINGING);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering 1 followed by SEND: release all active calls
+ // (if any exist) and accepts the other (held or waiting) call.
+
+ mGSMPhone.handleInCallMmiCommands("1");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+ // change the active call to holding call
+ mGSMPhone.switchHoldingAndActive();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering 1 followed by SEND: release all active calls
+ // (if any exist) and accepts the other (held or waiting) call.
+ mGSMPhone.handleInCallMmiCommands("1");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+ // at this point, the active call with number==18005551212 should
+ // have the gsm index of 2
+
+ mRadioControl.triggerRing("16505550100");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering "12" followed by SEND: release the call with
+ // gsm index equals to 2.
+ mGSMPhone.handleInCallMmiCommands("12");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getState() != Phone.State.OFFHOOK);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // at this point, the call with number==16505550100 should
+ // have the gsm index of 1
+ mGSMPhone.dial("+13125551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE ||
+ mGSMPhone.getBackgroundCall().getState() != Call.State.HOLDING);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // at this point, the active call with number==13125551212 should
+ // have the gsm index of 2
+
+ // Simulate entering "11" followed by SEND: release the call with
+ // gsm index equals to 1. This should not be allowed, and a
+ // Supplementary Service notification must be received.
+ mGSMPhone.handleInCallMmiCommands("11");
+
+ msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+ assertNotNull("Message Time Out", msg);
+ assertFalse("IncallMmiCallWaiting: command should not work on holding call", msg == null);
+
+ // Simulate entering "12" followed by SEND: release the call with
+ // gsm index equals to 2.
+ mGSMPhone.handleInCallMmiCommands("12");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // Simulate entering 1 followed by SEND: release all active calls
+ // (if any exist) and accepts the other (held or waiting) call.
+ mGSMPhone.handleInCallMmiCommands("1");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("16505550100",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+
+ // Simulate entering "11" followed by SEND: release the call with
+ // gsm index equals to 1.
+ mGSMPhone.handleInCallMmiCommands("11");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ }
+
+ public void testIncallMmiCallHold() throws Exception {
+ Message msg;
+
+ // establish an active call
+ mGSMPhone.dial("13125551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // establish a ringing (WAITING) call
+
+ mRadioControl.triggerRing("18005551212");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // simulate entering 2 followed by SEND: place all active calls
+ // (if any exist) on hold and accepts the other (held or waiting)
+ // call
+
+ mGSMPhone.handleInCallMmiCommands("2");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getState() == Call.State.WAITING);
+
+
+ assertFalse(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE,
+ mGSMPhone.getForegroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("13125551212",
+ mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+ // swap the active and holding calls
+ mGSMPhone.handleInCallMmiCommands("2");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_PHONE_STATE_CHANGED);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("13125551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+ // merge the calls
+ mGSMPhone.conference();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ assertEquals(2, mGSMPhone.getForegroundCall().getConnections().size());
+
+ // at this point, we have an active conference call, with
+ // call(1) = 13125551212 and call(2) = 18005551212
+
+ // Simulate entering "23" followed by SEND: places all active call
+ // on hold except call 3. This should fail and a supplementary service
+ // failed notification should be received.
+
+ mGSMPhone.handleInCallMmiCommands("23");
+
+ msg = mGSMTestHandler.waitForMessage(SUPP_SERVICE_FAILED);
+ assertNotNull("Message Time Out", msg);
+ assertFalse("IncallMmiCallHold: separate should have failed!", msg == null);
+
+ // Simulate entering "21" followed by SEND: places all active call
+ // on hold except call 1.
+ mGSMPhone.handleInCallMmiCommands("21");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() == Call.State.IDLE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("13125551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+ }
+
+ public void testIncallMmiMultipartyServices() throws Exception {
+ // establish an active call
+ mGSMPhone.dial("13125551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ // dial another call
+ mGSMPhone.dial("18005551212");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ mGSMPhone.handleInCallMmiCommands("3");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertEquals(Phone.State.OFFHOOK, mGSMPhone.getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals("13125551212",
+ mGSMPhone.getForegroundCall().getConnections().get(1).getAddress());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ }
+
+ public void testCallIndex() throws Exception {
+ Message msg;
+
+ // establish the first call
+ mGSMPhone.dial("16505550100");
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ String baseNumber = "1650555010";
+
+ for (int i = 1; i < 6; i++) {
+ String number = baseNumber + i;
+
+ mGSMPhone.dial(number);
+
+ do {
+ mRadioControl.progressConnectingCallState();
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ if (mGSMPhone.getBackgroundCall().getConnections().size() >= 5) {
+ break;
+ }
+
+ mGSMPhone.conference();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getBackgroundCall().getState() != Call.State.IDLE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ }
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("16505550105",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // create an incoming call, this call should have the call index
+ // of 7
+ mRadioControl.triggerRing("18005551212");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_RINGING);
+ assertNotNull("Message Time Out", msg);
+
+ assertEquals(Phone.State.RINGING, mGSMPhone.getState());
+ assertTrue(mGSMPhone.getRingingCall().isRinging());
+ assertEquals(Call.State.WAITING, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+
+ // hangup the background call and accept the ringing call
+ mGSMPhone.getBackgroundCall().hangup();
+ mGSMPhone.acceptCall();
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getRingingCall().getState() != Call.State.IDLE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals("18005551212",
+ mGSMPhone.getForegroundCall().getConnections().get(0).getAddress());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("16505550105",
+ mGSMPhone.getBackgroundCall().getConnections().get(0).getAddress());
+
+ mGSMPhone.handleInCallMmiCommands("17");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.HOLDING, mGSMPhone.getBackgroundCall().getState());
+ assertEquals("16505550105",
+ mGSMPhone.getBackgroundCall().getConnections().get(0).
+ getAddress());
+
+ mGSMPhone.handleInCallMmiCommands("1");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() != Call.State.ACTIVE);
+
+ assertEquals(Call.State.ACTIVE, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ mGSMPhone.handleInCallMmiCommands("16");
+
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (mGSMPhone.getForegroundCall().getState() == Call.State.ACTIVE);
+
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+ }
+
+ public void testPostDialSequences() throws Exception {
+ Message msg;
+ AsyncResult ar;
+ Connection cn;
+
+ mGSMPhone.dial("+13125551212,1234;5N8xx");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(',', msg.arg1);
+ assertEquals("1234;5N8", cn.getRemainingPostDialString());
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('1', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('2', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('3', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('4', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(';', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState());
+ assertEquals(Connection.PostDialState.WAIT, ar.userObj);
+ cn.proceedAfterWaitChar();
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('5', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertEquals('N', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(Connection.PostDialState.WILD, cn.getPostDialState());
+ assertEquals(Connection.PostDialState.WILD, ar.userObj);
+ cn.proceedAfterWildChar(",6;7");
+
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(',', msg.arg1);
+ assertEquals("6;78", cn.getRemainingPostDialString());
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('6', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(';', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(Connection.PostDialState.WAIT, cn.getPostDialState());
+ assertEquals(Connection.PostDialState.WAIT, ar.userObj);
+ cn.proceedAfterWaitChar();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('7', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals('8', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ assertEquals(Connection.PostDialState.STARTED, ar.userObj);
+
+ // Bogus chars at end should be ignored
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(0, msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(Connection.PostDialState.COMPLETE,
+ cn.getPostDialState());
+ assertEquals(Connection.PostDialState.COMPLETE, ar.userObj);
+ }
+
+ public void testPostDialCancel() throws Exception {
+ Message msg;
+ AsyncResult ar;
+ Connection cn;
+
+ mGSMPhone.dial("+13125551212,N");
+ mRadioControl.progressConnectingToActive();
+
+ mRadioControl.progressConnectingToActive();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(',', msg.arg1);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_POST_DIAL);
+ assertEquals('N', msg.arg1);
+ ar = (AsyncResult) (msg.obj);
+ cn = (Connection) (ar.result);
+ assertEquals(Connection.PostDialState.WILD, cn.getPostDialState());
+ cn.cancelPostDial();
+
+ assertEquals(Connection.PostDialState.CANCELLED, cn.getPostDialState());
+ }
+
+ public void testOutgoingCallFail() throws Exception {
+ Message msg;
+ /*
+ * normal clearing
+ */
+
+ mRadioControl.setNextCallFailCause(CallFailCause.NORMAL_CLEARING);
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ Connection cn = mGSMPhone.dial("+13125551212");
+
+ mRadioControl.progressConnectingCallState();
+
+ // I'm just progressing the call state to
+ // ensure getCurrentCalls() gets processed...
+ // Normally these failure conditions would happen in DIALING
+ // not ALERTING
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (cn.getState() == Call.State.DIALING);
+
+
+ mRadioControl.triggerHangupAll();
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Connection.DisconnectCause.NORMAL, cn.getDisconnectCause());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ /*
+ * busy
+ */
+
+ mRadioControl.setNextCallFailCause(CallFailCause.USER_BUSY);
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ cn = mGSMPhone.dial("+13125551212");
+
+ mRadioControl.progressConnectingCallState();
+
+ // I'm just progressing the call state to
+ // ensure getCurrentCalls() gets processed...
+ // Normally these failure conditions would happen in DIALING
+ // not ALERTING
+ do {
+ assertNotNull("Message Time Out", mGSMTestHandler.waitForMessage(ANY_MESSAGE));
+ } while (cn.getState() == Call.State.DIALING);
+
+
+ mRadioControl.triggerHangupAll();
+ msg = mGSMTestHandler.waitForMessage(EVENT_DISCONNECT);
+ assertNotNull("Message Time Out", msg);
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Connection.DisconnectCause.BUSY, cn.getDisconnectCause());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED,
+ mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+
+ /*
+ * congestion
+ */
+
+ mRadioControl.setNextCallFailCause(CallFailCause.NO_CIRCUIT_AVAIL);
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ cn = mGSMPhone.dial("+13125551212");
+
+ mRadioControl.progressConnectingCallState();
+
+ // I'm just progressing the call state to
+ // ensure getCurrentCalls() gets processed...
+ // Normally these failure conditions would happen in DIALING
+ // not ALERTING
+ do {
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+ } while (cn.getState() == Call.State.DIALING);
+
+
+ mRadioControl.triggerHangupAll();
+
+ // Unlike the while loops above, this one waits
+ // for a "phone state changed" message back to "idle"
+ do {
+ msg = mGSMTestHandler.waitForMessage(ANY_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+ } while (!(msg.what == EVENT_PHONE_STATE_CHANGED
+ && mGSMPhone.getState() == Phone.State.IDLE));
+
+ assertEquals(Phone.State.IDLE, mGSMPhone.getState());
+
+ assertEquals(Connection.DisconnectCause.CONGESTION, cn.getDisconnectCause());
+
+ assertEquals(0, mGSMPhone.getRingingCall().getConnections().size());
+ assertEquals(1, mGSMPhone.getForegroundCall().getConnections().size());
+ assertEquals(0, mGSMPhone.getBackgroundCall().getConnections().size());
+
+ assertEquals(Call.State.IDLE, mGSMPhone.getRingingCall().getState());
+ assertEquals(Call.State.DISCONNECTED, mGSMPhone.getForegroundCall().getState());
+ assertEquals(Call.State.IDLE, mGSMPhone.getBackgroundCall().getState());
+
+ assertTrue(mGSMPhone.getForegroundCall().getEarliestCreateTime() > 0);
+ assertEquals(0, mGSMPhone.getForegroundCall().getEarliestConnectTime());
+ }
+
+ public void testSSNotification() throws Exception {
+ // MO
+ runTest(0, SuppServiceNotification.MO_CODE_UNCONDITIONAL_CF_ACTIVE);
+ runTest(0, SuppServiceNotification.MO_CODE_CALL_IS_WAITING);
+ runTest(0, SuppServiceNotification.MO_CODE_CALL_DEFLECTED);
+
+ // MT
+ runTest(1, SuppServiceNotification.MT_CODE_FORWARDED_CALL);
+ runTest(1, SuppServiceNotification.MT_CODE_CALL_CONNECTED_ECT);
+ runTest(1, SuppServiceNotification.MT_CODE_ADDITIONAL_CALL_FORWARDED);
+ }
+
+ private void runTest(int type, int code) {
+ Message msg;
+
+ mRadioControl.triggerSsn(type, code);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_SSN);
+ assertNotNull("Message Time Out", msg);
+ AsyncResult ar = (AsyncResult) msg.obj;
+
+ assertNull(ar.exception);
+
+ SuppServiceNotification notification =
+ (SuppServiceNotification) ar.result;
+
+ assertEquals(type, notification.notificationType);
+ assertEquals(code, notification.code);
+ }
+
+ public void testUssd() throws Exception {
+ // Quick hack to work around a race condition in this test:
+ // We may initiate a USSD MMI before GSMPhone receives its initial
+ // GSMTestHandler.EVENT_RADIO_OFF_OR_NOT_AVAILABLE event. When the phone sees this
+ // event, it will cancel the just issued USSD MMI, which we don't
+ // want. So sleep a little first.
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException ex) {
+ // do nothing
+ }
+
+ verifyNormal();
+ verifyCancel();
+ varifyNetworkInitiated();
+ }
+
+ private void varifyNetworkInitiated() {
+ Message msg;
+ AsyncResult ar;
+ MmiCode mmi;
+
+ // Receive an incoming NOTIFY
+ mRadioControl.triggerIncomingUssd("0", "NOTIFY message");
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertFalse(mmi.isUssdRequest());
+
+ // Receive a REQUEST and send response
+ mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertTrue(mmi.isUssdRequest());
+
+ mGSMPhone.sendUssdResponse("## TEST: TEST_GSMPhone responding...");
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ GsmMmiCode gsmMmi = (GsmMmiCode) mmi;
+ assertTrue(gsmMmi.isPendingUSSD());
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertNull(ar.exception);
+ assertFalse(mmi.isUssdRequest());
+
+ // Receive a REQUEST and cancel
+ mRadioControl.triggerIncomingUssd("1", "REQUEST Message");
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertTrue(mmi.isUssdRequest());
+
+ mmi.cancel();
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertNull(ar.exception);
+ assertEquals(MmiCode.State.CANCELLED, mmi.getState());
+
+ List mmiList = mGSMPhone.getPendingMmiCodes();
+ assertEquals(0, mmiList.size());
+ }
+
+ private void verifyNormal() throws CallStateException {
+ Message msg;
+ AsyncResult ar;
+ MmiCode mmi;
+
+ mGSMPhone.dial("#646#");
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+ assertEquals(MmiCode.State.COMPLETE, mmi.getState());
+ }
+
+
+ private void verifyCancel() throws CallStateException {
+ /**
+ * This case makes an assumption that dial() will add the USSD
+ * to the "pending MMI codes" list before it returns. This seems
+ * like reasonable semantics. It also assumes that the USSD
+ * request in question won't complete until we get back to the
+ * event loop, thus cancel() is safe.
+ */
+ Message msg;
+
+ mGSMPhone.dial("#646#");
+
+ List<? extends MmiCode> pendingMmis = mGSMPhone.getPendingMmiCodes();
+
+ assertEquals(1, pendingMmis.size());
+
+ MmiCode mmi = pendingMmis.get(0);
+ assertTrue(mmi.isCancelable());
+ mmi.cancel();
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+
+ AsyncResult ar = (AsyncResult) msg.obj;
+ mmi = (MmiCode) ar.result;
+
+ assertEquals(MmiCode.State.CANCELLED, mmi.getState());
+ }
+
+ public void testRilHooks() throws Exception {
+ //
+ // These test cases all assume the RIL OEM hooks
+ // just echo back their input
+ //
+
+ Message msg;
+ AsyncResult ar;
+
+ // null byte array
+
+ mGSMPhone.invokeOemRilRequestRaw(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertNull(ar.result);
+ assertNull(ar.exception);
+
+ // empty byte array
+
+ mGSMPhone.invokeOemRilRequestRaw(new byte[0], mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertEquals(0, ((byte[]) (ar.result)).length);
+ assertNull(ar.exception);
+
+ // byte array with data
+
+ mGSMPhone.invokeOemRilRequestRaw("Hello".getBytes("utf-8"),
+ mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertEquals("Hello", new String(((byte[]) (ar.result)), "utf-8"));
+ assertNull(ar.exception);
+
+ // null strings
+
+ mGSMPhone.invokeOemRilRequestStrings(null, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertNull(ar.result);
+ assertNull(ar.exception);
+
+ // empty byte array
+
+ mGSMPhone.invokeOemRilRequestStrings(new String[0],
+ mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertEquals(0, ((String[]) (ar.result)).length);
+ assertNull(ar.exception);
+
+ // Strings with data
+
+ String s[] = new String[1];
+
+ s[0] = "Hello";
+
+ mGSMPhone.invokeOemRilRequestStrings(s, mHandler.obtainMessage(EVENT_OEM_RIL_MESSAGE));
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_OEM_RIL_MESSAGE);
+ assertNotNull("Message Time Out", msg);
+
+ ar = ((AsyncResult) msg.obj);
+
+ assertEquals("Hello", ((String[]) (ar.result))[0]);
+ assertEquals(1, ((String[]) (ar.result)).length);
+ assertNull(ar.exception);
+ }
+
+ public void testMmi() throws Exception {
+ mRadioControl.setAutoProgressConnectingCall(false);
+
+ // "valid" MMI sequences
+ runValidMmi("*#67#", false);
+ runValidMmi("##43*11#", false);
+ runValidMmi("#33*1234*11#", false);
+ runValidMmi("*21*6505551234**5#", false);
+ runValidMmi("**03**1234*4321*4321#", false);
+ // pound string
+ runValidMmi("5308234092307540923#", true);
+ // short code
+ runValidMmi("22", true);
+ // as part of call setup
+ runValidMmiWithConnect("*31#6505551234");
+
+ // invalid MMI sequences
+ runNotMmi("6505551234");
+ runNotMmi("1234#*12#34566654");
+ runNotMmi("*#*#12#*");
+ }
+
+ private void runValidMmi(String dialString, boolean cancelable) throws CallStateException {
+ Connection c = mGSMPhone.dial(dialString);
+ assertNull(c);
+ Message msg = mGSMTestHandler.waitForMessage(EVENT_MMI_INITIATE);
+ assertNotNull("Message Time Out", msg);
+ // Should not be cancelable.
+ AsyncResult ar = (AsyncResult) msg.obj;
+ MmiCode mmi = (MmiCode) ar.result;
+ assertEquals(cancelable, mmi.isCancelable());
+
+ msg = mGSMTestHandler.waitForMessage(EVENT_MMI_COMPLETE);
+ assertNotNull("Message Time Out", msg);
+ }
+
+ private void runValidMmiWithConnect(String dialString) throws CallStateException {
+ mRadioControl.pauseResponses();
+
+ Connection c = mGSMPhone.dial(dialString);
+ assertNotNull(c);
+
+ hangup(c);
+ }
+
+ private void hangup(Connection cn) throws CallStateException {
+ cn.hangup();
+
+ mRadioControl.resumeResponses();
+ assertNotNull(mGSMTestHandler.waitForMessage(EVENT_DISCONNECT));
+
+ }
+
+ private void runNotMmi(String dialString) throws CallStateException {
+ mRadioControl.pauseResponses();
+
+ Connection c = mGSMPhone.dial(dialString);
+ assertNotNull(c);
+
+ hangup(c);
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
new file mode 100644
index 0000000..fb8a5d9
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GSMTestHandler.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.content.Context;
+
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.os.Message;
+import android.util.Log;
+
+import com.android.internal.telephony.gsm.GSMPhone;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.TestPhoneNotifier;
+
+/**
+ * This class creates a HandlerThread which waits for the various messages.
+ */
+public class GSMTestHandler extends HandlerThread implements Handler.Callback {
+
+ private Handler mHandler;
+ private Message mCurrentMessage;
+
+ private Boolean mMsgConsumed;
+ private SimulatedCommands sc;
+ private GSMPhone mGSMPhone;
+ private Context mContext;
+
+ private static final int FAIL_TIMEOUT_MILLIS = 5 * 1000;
+
+ public GSMTestHandler(Context context) {
+ super("GSMPhoneTest");
+ mMsgConsumed = false;
+ mContext = context;
+ }
+
+ @Override
+ protected void onLooperPrepared() {
+ sc = new SimulatedCommands();
+ mGSMPhone = new GSMPhone(mContext, sc, new TestPhoneNotifier(), true);
+ mHandler = new Handler(getLooper(), this);
+ synchronized (this) {
+ notifyAll();
+ }
+ }
+
+ public boolean handleMessage(Message msg) {
+ synchronized (this) {
+ mCurrentMessage = msg;
+ this.notifyAll();
+ while(!mMsgConsumed) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) {}
+ }
+ mMsgConsumed = false;
+ }
+ return true;
+ }
+
+
+ public void cleanup() {
+ Looper looper = getLooper();
+ if (looper != null) looper.quit();
+ mHandler = null;
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ public SimulatedCommands getSimulatedCommands() {
+ return sc;
+ }
+
+ public GSMPhone getGSMPhone() {
+ return mGSMPhone;
+ }
+
+ public Message waitForMessage(int code) {
+ Message msg;
+ while(true) {
+ msg = null;
+ synchronized (this) {
+ try {
+ this.wait(FAIL_TIMEOUT_MILLIS);
+ } catch (InterruptedException e) {
+ }
+
+ // Check if timeout has occurred.
+ if (mCurrentMessage != null) {
+ // Consume the message
+ msg = Message.obtain();
+ msg.copyFrom(mCurrentMessage);
+ mCurrentMessage = null;
+ mMsgConsumed = true;
+ this.notifyAll();
+ }
+ }
+ if (msg == null || code == GSMPhoneTest.ANY_MESSAGE || msg.what == code) return msg;
+ }
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java
new file mode 100644
index 0000000..f36d96b
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/GsmAlphabetTest.java
@@ -0,0 +1,309 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+public class GsmAlphabetTest extends TestCase {
+
+ private static final String sGsmExtendedChars = "{|}\\[~]\f\u20ac";
+
+ @SmallTest
+ public void test7bitWithHeader() throws Exception {
+ byte[] data = new byte[3];
+ data[0] = (byte) 1;
+ data[1] = (byte) 2;
+ data[2] = (byte) 2;
+ SmsHeader header = new SmsHeader();
+ header.add(new SmsHeader.Element(SmsHeader.CONCATENATED_8_BIT_REFERENCE, data));
+
+ String message = "aaaaaaaaaabbbbbbbbbbcccccccccc";
+ byte[] userData = GsmAlphabet.stringToGsm7BitPackedWithHeader(message, header.toByteArray());
+ int septetCount = GsmAlphabet.countGsmSeptets(message, false);
+ String parsedMessage = GsmAlphabet.gsm7BitPackedToString(
+ userData, header.toByteArray().length+1, septetCount, 1);
+ assertEquals(message, parsedMessage);
+ }
+
+ // TODO: This method should *really* be a series of individual test methods.
+ @LargeTest
+ public void testBasic() throws Exception {
+ // '@' maps to char 0
+ assertEquals(0, GsmAlphabet.charToGsm('@'));
+
+ // `a (a with grave accent) maps to last GSM charater
+ assertEquals(0x7f, GsmAlphabet.charToGsm('\u00e0'));
+
+ //
+ // These are the extended chars
+ // They should all return GsmAlphabet.GSM_EXTENDED_ESCAPE
+ //
+
+ for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+ assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE,
+ GsmAlphabet.charToGsm(sGsmExtendedChars.charAt(i)));
+
+ }
+
+ // euro symbol
+ assertEquals(GsmAlphabet.GSM_EXTENDED_ESCAPE,
+ GsmAlphabet.charToGsm('\u20ac'));
+
+ // An unmappable char (the 'cent' char) maps to a space
+ assertEquals(GsmAlphabet.charToGsm(' '),
+ GsmAlphabet.charToGsm('\u00a2'));
+
+ // unmappable = space = 1 septet
+ assertEquals(1, GsmAlphabet.countGsmSeptets('\u00a2'));
+
+ //
+ // Test extended table
+ //
+
+ for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+ assertEquals(sGsmExtendedChars.charAt(i),
+ GsmAlphabet.gsmExtendedToChar(
+ GsmAlphabet.charToGsmExtended(sGsmExtendedChars.charAt(i))));
+
+ }
+
+ // Unmappable extended char
+ assertEquals(GsmAlphabet.charToGsm(' '),
+ GsmAlphabet.charToGsmExtended('@'));
+
+ //
+ // gsmToChar()
+ //
+
+ assertEquals('@', GsmAlphabet.gsmToChar(0));
+
+ // `a (a with grave accent) maps to last GSM charater
+ assertEquals('\u00e0', GsmAlphabet.gsmToChar(0x7f));
+
+ assertEquals('\uffff',
+ GsmAlphabet.gsmToChar(GsmAlphabet.GSM_EXTENDED_ESCAPE));
+
+ // Out-of-range/unmappable value
+ assertEquals(' ', GsmAlphabet.gsmToChar(0x80));
+
+ //
+ // gsmExtendedToChar()
+ //
+
+ assertEquals('{', GsmAlphabet.gsmExtendedToChar(0x28));
+
+ // No double-escapes
+ assertEquals(' ', GsmAlphabet.gsmExtendedToChar(
+ GsmAlphabet.GSM_EXTENDED_ESCAPE));
+
+ // Unmappable
+ assertEquals(' ', GsmAlphabet.gsmExtendedToChar(0));
+
+ //
+ // stringTo7BitPacked, gsm7BitPackedToString
+ //
+
+ byte[] packed;
+ StringBuilder testString = new StringBuilder(300);
+
+ // Check all alignment cases
+ for (int i = 0; i < 9; i++, testString.append('@')) {
+ packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ assertEquals(testString.toString(),
+ GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+ }
+
+ // Check full non-extended alphabet
+ for (int i = 0; i < 0x80; i++) {
+ char c;
+
+ if (i == GsmAlphabet.GSM_EXTENDED_ESCAPE) {
+ continue;
+ }
+
+ c = GsmAlphabet.gsmToChar(i);
+ testString.append(c);
+
+ // These are all non-extended chars, so it should be
+ // one septet per char
+ assertEquals(1, GsmAlphabet.countGsmSeptets(c));
+ }
+
+ packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ assertEquals(testString.toString(),
+ GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+ // Test extended chars too
+
+ testString.append(sGsmExtendedChars);
+
+ for (int i = 0, s = sGsmExtendedChars.length(); i < s; i++) {
+ // These are all extended chars, so it should be
+ // two septets per char
+ assertEquals(2, GsmAlphabet.countGsmSeptets(sGsmExtendedChars.charAt(i)));
+
+ }
+
+ packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ assertEquals(testString.toString(),
+ GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+ // stringTo7BitPacked handles up to 255 septets
+
+ testString.setLength(0);
+ for (int i = 0; i < 255; i++) {
+ testString.append('@');
+ }
+
+ packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ assertEquals(testString.toString(),
+ GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+ // > 255 septets throws runtime exception
+ testString.append('@');
+
+ try {
+ GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ fail("expected exception");
+ } catch (EncodeException ex) {
+ // exception expected
+ }
+
+ // Try 254 septets with 127 extended chars
+
+ testString.setLength(0);
+ for (int i = 0; i < (255 / 2); i++) {
+ testString.append('{');
+ }
+
+ packed = GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ assertEquals(testString.toString(),
+ GsmAlphabet.gsm7BitPackedToString(packed, 1, 0xff & packed[0]));
+
+ // > 255 septets throws runtime exception
+ testString.append('{');
+
+ try {
+ GsmAlphabet.stringToGsm7BitPacked(testString.toString());
+ fail("expected exception");
+ } catch (EncodeException ex) {
+ // exception expected
+ }
+
+ //
+ // 8 bit unpacked format
+ //
+ // Note: we compare hex strings here
+ // because Assert doesnt have array-comparisons
+
+ byte unpacked[];
+
+ unpacked = SimUtils.hexStringToBytes("566F696365204D61696C");
+ assertEquals("Voice Mail",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ assertEquals(SimUtils.bytesToHexString(unpacked),
+ SimUtils.bytesToHexString(
+ GsmAlphabet.stringToGsm8BitPacked("Voice Mail")));
+
+ unpacked = GsmAlphabet.stringToGsm8BitPacked(sGsmExtendedChars);
+ // two bytes for every extended char
+ assertEquals(2 * sGsmExtendedChars.length(), unpacked.length);
+ assertEquals(sGsmExtendedChars,
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ // should be two bytes per extended char
+ assertEquals(2 * sGsmExtendedChars.length(), unpacked.length);
+
+ // Test truncation of unaligned extended chars
+ unpacked = new byte[3];
+ GsmAlphabet.stringToGsm8BitUnpackedField(sGsmExtendedChars, unpacked,
+ 0, unpacked.length);
+
+ // Should be one extended char and an 0xff at the end
+
+ assertEquals(0xff, 0xff & unpacked[2]);
+ assertEquals(sGsmExtendedChars.substring(0, 1),
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ // Test truncation of normal chars
+ unpacked = new byte[3];
+ GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked,
+ 0, unpacked.length);
+
+ assertEquals("abc",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ // Test truncation of mixed normal and extended chars
+ unpacked = new byte[3];
+ GsmAlphabet.stringToGsm8BitUnpackedField("a{cd", unpacked,
+ 0, unpacked.length);
+
+ assertEquals("a{",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ // Test padding after normal char
+ unpacked = new byte[3];
+ GsmAlphabet.stringToGsm8BitUnpackedField("a", unpacked,
+ 0, unpacked.length);
+
+ assertEquals("a",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ assertEquals(0xff, 0xff & unpacked[1]);
+ assertEquals(0xff, 0xff & unpacked[2]);
+
+ // Test malformed input -- escape char followed by end of field
+ unpacked[0] = 0;
+ unpacked[1] = 0;
+ unpacked[2] = GsmAlphabet.GSM_EXTENDED_ESCAPE;
+
+ assertEquals("@@",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 0, unpacked.length));
+
+ // non-zero offset
+ assertEquals("@",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+
+ // test non-zero offset
+ unpacked[0] = 0;
+ GsmAlphabet.stringToGsm8BitUnpackedField("abcd", unpacked,
+ 1, unpacked.length - 1);
+
+
+ assertEquals(0, unpacked[0]);
+
+ assertEquals("ab",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+
+ // test non-zero offset with truncated extended char
+ unpacked[0] = 0;
+
+ GsmAlphabet.stringToGsm8BitUnpackedField("a{", unpacked,
+ 1, unpacked.length - 1);
+
+ assertEquals(0, unpacked[0]);
+
+ assertEquals("a",
+ GsmAlphabet.gsm8BitUnpackedToString(unpacked, 1, unpacked.length - 1));
+ }
+}
+
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
new file mode 100644
index 0000000..6db230f
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SMSDispatcherTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import com.android.internal.telephony.TestPhoneNotifier;
+import com.android.internal.telephony.test.SimulatedCommands;
+import com.android.internal.telephony.test.SimulatedRadioControl;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.telephony.gsm.SmsMessage;
+
+import java.util.Iterator;
+
+/**
+ * {@hide}
+ */
+public class SMSDispatcherTest extends AndroidTestCase {
+ @MediumTest
+ public void testCMT1() throws Exception {
+ SmsMessage sms;
+ SmsHeader header;
+ Iterator<SmsHeader.Element> elements;
+
+ String[] lines = new String[2];
+
+ lines[0] = "+CMT: ,158";
+ lines[1] = "07914140279510F6440A8111110301003BF56080426101748A8C0B05040B"
+ + "8423F000035502010106276170706C69636174696F6E2F766E642E776170"
+ + "2E6D6D732D6D65737361676500AF848D0185B4848C8298524F347839776F"
+ + "7547514D4141424C3641414141536741415A4B554141414141008D908918"
+ + "802B31363530323438363137392F545950453D504C4D4E008A808E028000"
+ + "88058103093A8083687474703A2F2F36";
+
+ sms = SmsMessage.newFromCMT(lines);
+ header = sms.getUserDataHeader();
+ assertNotNull(header);
+ assertNotNull(sms.getUserData());
+
+ elements = header.getElements().iterator();
+ assertNotNull(elements);
+ }
+
+ @MediumTest
+ public void testCMT2() throws Exception {
+ SmsMessage sms;
+ SmsHeader header;
+ Iterator<SmsHeader.Element> elements;
+
+ String[] lines = new String[2];
+
+
+ lines[0] = "+CMT: ,77";
+ lines[1] = "07914140279510F6440A8111110301003BF56080426101848A3B0B05040B8423F"
+ + "00003550202362E3130322E3137312E3135302F524F347839776F7547514D4141"
+ + "424C3641414141536741415A4B55414141414100";
+
+ sms = SmsMessage.newFromCMT(lines);
+ header = sms.getUserDataHeader();
+ System.out.println("header = " + header);
+ assertNotNull(header);
+ assertNotNull(sms.getUserData());
+
+ elements = header.getElements().iterator();
+ assertNotNull(elements);
+ }
+
+ @MediumTest
+ public void testEfRecord() throws Exception {
+ SmsMessage sms;
+
+ String s = "03029111000c9194981492631000f269206190022000a053e4534a05358bd3"
+ + "69f05804259da0219418a40641536a110a0aea408080604028180e888462c1"
+ + "50341c0f484432a1542c174c46b3e1743c9f9068442a994ea8946ac56ab95e"
+ + "b0986c46abd96eb89c6ec7ebf97ec0a070482c1a8fc8a472c96c3a9fd0a874"
+ + "4aad5aafd8ac76cbed7abfe0b0784c2e9bcfe8b47acd6ebbdff0b87c4eafdb"
+ + "eff8bc7ecfeffbffffffffffffffffffffffffffff";
+ byte[] data = SimUtils.hexStringToBytes(s);
+
+ sms = SmsMessage.createFromEfRecord(1, data);
+ assertNotNull(sms.getMessageBody());
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
new file mode 100644
index 0000000..db55bca
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimPhoneBookTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.ServiceManager;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+@Suppress
+public class SimPhoneBookTest extends TestCase {
+
+ public void testBasic() throws Exception {
+ ISimPhoneBook simPhoneBook =
+ ISimPhoneBook.Stub.asInterface(ServiceManager.getService("simphonebook"));
+ assertNotNull(simPhoneBook);
+
+ int size[] = simPhoneBook.getAdnRecordsSize(SimConstants.EF_ADN);
+ assertNotNull(size);
+ assertEquals(3, size.length);
+ assertEquals(size[0] * size[2], size[1]);
+ assertTrue(size[2] >= 100);
+
+ List<AdnRecord> adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ // do it twice cause the second time shall read from cache only
+ adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ assertNotNull(adnRecordList);
+
+ // Test for phone book update
+ int adnIndex, listIndex = 0;
+ AdnRecord originalAdn = null;
+ // We need to maintain the state of the SIM before and after the test.
+ // Since this test doesn't mock the SIM we try to get a valid ADN record,
+ // for 3 tries and if this fails, we bail out.
+ for (adnIndex = 3 ; adnIndex >= 1; adnIndex--) {
+ listIndex = adnIndex - 1; // listIndex is zero based.
+ originalAdn = adnRecordList.get(listIndex);
+ assertNotNull("Original Adn is Null.", originalAdn);
+ assertNotNull("Original Adn alpha tag is null.", originalAdn.getAlphaTag());
+ assertNotNull("Original Adn number is null.", originalAdn.getNumber());
+
+ if (originalAdn.getNumber().length() > 0 &&
+ originalAdn.getAlphaTag().length() > 0) {
+ break;
+ }
+ }
+ if (adnIndex == 0) return;
+
+ AdnRecord emptyAdn = new AdnRecord("", "");
+ AdnRecord firstAdn = new AdnRecord("John", "4085550101");
+ AdnRecord secondAdn = new AdnRecord("Andy", "6505550102");
+ String pin2 = null;
+
+ // udpate by index
+ boolean success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN,
+ firstAdn.getAlphaTag(), firstAdn.getNumber(), adnIndex, pin2);
+ adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ AdnRecord tmpAdn = adnRecordList.get(listIndex);
+ assertTrue(success);
+ assertTrue(firstAdn.isEqual(tmpAdn));
+
+ // replace by search
+ success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN,
+ firstAdn.getAlphaTag(), firstAdn.getNumber(),
+ secondAdn.getAlphaTag(), secondAdn.getNumber(), pin2);
+ adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ tmpAdn = adnRecordList.get(listIndex);
+ assertTrue(success);
+ assertFalse(firstAdn.isEqual(tmpAdn));
+ assertTrue(secondAdn.isEqual(tmpAdn));
+
+ // erase be search
+ success = simPhoneBook.updateAdnRecordsInEfBySearch(SimConstants.EF_ADN,
+ secondAdn.getAlphaTag(), secondAdn.getNumber(),
+ emptyAdn.getAlphaTag(), emptyAdn.getNumber(), pin2);
+ adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ tmpAdn = adnRecordList.get(listIndex);
+ assertTrue(success);
+ assertTrue(tmpAdn.isEmpty());
+
+ // restore the orginial adn
+ success = simPhoneBook.updateAdnRecordsInEfByIndex(SimConstants.EF_ADN,
+ originalAdn.getAlphaTag(), originalAdn.getNumber(), adnIndex,
+ pin2);
+ adnRecordList = simPhoneBook.getAdnRecordsInEf(SimConstants.EF_ADN);
+ tmpAdn = adnRecordList.get(listIndex);
+ assertTrue(success);
+ assertTrue(originalAdn.isEqual(tmpAdn));
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java
new file mode 100644
index 0000000..6ced23d
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimSmsTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import android.os.ServiceManager;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.Suppress;
+
+import java.util.List;
+
+import junit.framework.TestCase;
+
+public class SimSmsTest extends TestCase {
+
+ @MediumTest
+ @Suppress // TODO: suppress this test for now since it doesn't work on the emulator
+ public void testBasic() throws Exception {
+
+ ISms sms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+ assertNotNull(sms);
+
+ List<SmsRawData> records = sms.getAllMessagesFromSimEf();
+ assertNotNull(records);
+ assertTrue(records.size() >= 0);
+
+ int firstNullIndex = -1;
+ int firstValidIndex = -1;
+ byte[] pdu = null;
+ for (int i = 0; i < records.size(); i++) {
+ SmsRawData data = records.get(i);
+ if (data != null && firstValidIndex == -1) {
+ firstValidIndex = i;
+ pdu = data.getBytes();
+ }
+ if (data == null && firstNullIndex == -1) {
+ firstNullIndex = i;
+ }
+ if (firstNullIndex != -1 && firstValidIndex != -1) {
+ break;
+ }
+ }
+ if (firstNullIndex == -1 || firstValidIndex == -1)
+ return;
+ assertNotNull(pdu);
+ }
+}
diff --git a/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java
new file mode 100644
index 0000000..3fbc8f5
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/telephony/gsm/SimUtilsTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import com.android.internal.telephony.gsm.SimTlv;
+import com.android.internal.telephony.gsm.SimUtils;
+import junit.framework.TestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+
+public class SimUtilsTest extends TestCase {
+
+ @SmallTest
+ public void testBasic() throws Exception {
+ byte[] data, data2;
+
+ /*
+ * bcdToString()
+ */
+
+ // An EF[ICCID] record
+ data = SimUtils.hexStringToBytes("981062400510444868f2");
+ assertEquals("8901260450014484862", SimUtils.bcdToString(data, 0, data.length));
+
+ // skip the first and last bytes
+ assertEquals("0126045001448486", SimUtils.bcdToString(data, 1, data.length - 2));
+
+ // Stops on invalid BCD value
+ data = SimUtils.hexStringToBytes("98F062400510444868f2");
+ assertEquals("890", SimUtils.bcdToString(data, 0, data.length));
+
+ /*
+ * bcdByteToInt()
+ */
+
+ assertEquals(98, SimUtils.bcdByteToInt((byte) 0x89));
+
+ // Out of range is treated as 0
+ assertEquals(8, SimUtils.bcdByteToInt((byte) 0x8c));
+
+ /*
+ * adnStringFieldToString()
+ */
+
+
+ data = SimUtils.hexStringToBytes("00566f696365204d61696c07918150367742f3ffffffffffff");
+ // Again, skip prepended 0
+ // (this is an EF[ADN] record)
+ assertEquals("Voice Mail", SimUtils.adnStringFieldToString(data, 1, data.length - 15));
+
+ data = SimUtils.hexStringToBytes("809673539A5764002F004DFFFFFFFFFF");
+ // (this is from an EF[ADN] record)
+ assertEquals("\u9673\u539A\u5764/M", SimUtils.adnStringFieldToString(data, 0, data.length));
+
+ data = SimUtils.hexStringToBytes("810A01566fec6365204de0696cFFFFFF");
+ // (this is made up to test since I don't have a real one)
+ assertEquals("Vo\u00ECce M\u00E0il", SimUtils.adnStringFieldToString(data, 0, data.length));
+
+ data = SimUtils.hexStringToBytes("820505302D82d32d31");
+ // Example from 3GPP TS 11.11 V18.1.3.0 annex B
+ assertEquals("-\u0532\u0583-1", SimUtils.adnStringFieldToString(data, 0, data.length));
+ }
+
+}
+
diff --git a/tests/CoreTests/com/android/internal/util/PredicatesTest.java b/tests/CoreTests/com/android/internal/util/PredicatesTest.java
new file mode 100644
index 0000000..c46ff05
--- /dev/null
+++ b/tests/CoreTests/com/android/internal/util/PredicatesTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import junit.framework.TestCase;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+public class PredicatesTest extends TestCase {
+
+ private static final Predicate<Object> TRUE = new Predicate<Object>() {
+ public boolean apply(Object o) {
+ return true;
+ }
+ };
+
+ private static final Predicate<Object> FALSE = new Predicate<Object>() {
+ public boolean apply(Object o) {
+ return false;
+ }
+ };
+
+ public void testAndPredicate_AllConditionsTrue() throws Exception {
+ assertTrue(Predicates.and(newArrayList(TRUE)).apply(null));
+ assertTrue(Predicates.and(newArrayList(TRUE, TRUE)).apply(null));
+ }
+
+ public void testAndPredicate_AtLeastOneConditionIsFalse() throws Exception {
+ assertFalse(Predicates.and(newArrayList(FALSE, TRUE, TRUE)).apply(null));
+ assertFalse(Predicates.and(newArrayList(TRUE, FALSE, TRUE)).apply(null));
+ assertFalse(Predicates.and(newArrayList(TRUE, TRUE, FALSE)).apply(null));
+ }
+
+ public void testOrPredicate_AllConditionsTrue() throws Exception {
+ assertTrue(Predicates.or(newArrayList(TRUE, TRUE, TRUE)).apply(null));
+ }
+
+ public void testOrPredicate_AllConditionsFalse() throws Exception {
+ assertFalse(Predicates.or(newArrayList(FALSE, FALSE, FALSE)).apply(null));
+ }
+
+ public void testOrPredicate_AtLeastOneConditionIsTrue() throws Exception {
+ assertTrue(Predicates.or(newArrayList(TRUE, FALSE, FALSE)).apply(null));
+ assertTrue(Predicates.or(newArrayList(FALSE, TRUE, FALSE)).apply(null));
+ assertTrue(Predicates.or(newArrayList(FALSE, FALSE, TRUE)).apply(null));
+ }
+
+ public void testNotPredicate() throws Exception {
+ assertTrue(Predicates.not(FALSE).apply(null));
+ assertFalse(Predicates.not(TRUE).apply(null));
+ }
+
+ private static <E> ArrayList<E> newArrayList(E... elements) {
+ ArrayList<E> list = new ArrayList<E>();
+ Collections.addAll(list, elements);
+ return list;
+ }
+
+}
diff --git a/tests/CoreTests/run_core_test.sh b/tests/CoreTests/run_core_test.sh
new file mode 100755
index 0000000..ffa31ed
--- /dev/null
+++ b/tests/CoreTests/run_core_test.sh
@@ -0,0 +1,6 @@
+framework=/system/framework
+bpath=$framework/core.jar:$framework/ext.jar:$framework/framework.jar:$framework/android.test.runner.jar
+adb shell exec dalvikvm -Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=3001 \
+ -Xbootclasspath:$bpath -cp /data/app/android.core.apk \
+ -Djava.io.tmpdir=/sdcard/tmp \
+ com.android.internal.util.WithFramework junit.textui.TestRunner $*
diff --git a/tests/CoreTests/run_junit.sh b/tests/CoreTests/run_junit.sh
new file mode 100755
index 0000000..b77794d
--- /dev/null
+++ b/tests/CoreTests/run_junit.sh
@@ -0,0 +1,9 @@
+# runs unit tests over adb shell using dalvikvm. The value added is setting the classpath for you
+# and pointing to the junit textui test runner.
+#
+# the normal usage might be:
+# (make MoreJavaTests)
+# $ adb sync
+# $ java/tests/run_junit.sh android.util.MyTest
+
+adb shell exec dalvikvm -cp system/app/MoreTests.apk junit.textui.TestRunner $*
diff --git a/tests/DpiTest/Android.mk b/tests/DpiTest/Android.mk
new file mode 100644
index 0000000..3596c39
--- /dev/null
+++ b/tests/DpiTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := DensityTest
+
+LOCAL_MODULE_TAGS := tests
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DpiTest/AndroidManifest.xml b/tests/DpiTest/AndroidManifest.xml
new file mode 100644
index 0000000..f71cff2
--- /dev/null
+++ b/tests/DpiTest/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.google.android.test.dpi">
+ <application android:label="DpiTest">
+ <activity android:name="DpiTestActivity" android:label="DpiTest">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/DpiTest/res/drawable-120dpi/logo120dpi.png b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
new file mode 100644
index 0000000..46bbd5b
--- /dev/null
+++ b/tests/DpiTest/res/drawable-120dpi/logo120dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable-240dpi/logo240dpi.png b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
new file mode 100644
index 0000000..4d717a8
--- /dev/null
+++ b/tests/DpiTest/res/drawable-240dpi/logo240dpi.png
Binary files differ
diff --git a/tests/DpiTest/res/drawable/logo160dpi.png b/tests/DpiTest/res/drawable/logo160dpi.png
new file mode 100644
index 0000000..c23b2ce
--- /dev/null
+++ b/tests/DpiTest/res/drawable/logo160dpi.png
Binary files differ
diff --git a/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
new file mode 100644
index 0000000..3759622
--- /dev/null
+++ b/tests/DpiTest/src/com/google/android/test/dpi/DpiTestActivity.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.android.test.dpi;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.BitmapFactory;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.ScrollView;
+import android.view.View;
+import android.content.Context;
+
+public class DpiTestActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout root = new LinearLayout(this);
+ root.setOrientation(LinearLayout.VERTICAL);
+
+ LinearLayout layout = new LinearLayout(this);
+ addBitmapDrawable(layout, R.drawable.logo120dpi, true);
+ addBitmapDrawable(layout, R.drawable.logo160dpi, true);
+ addBitmapDrawable(layout, R.drawable.logo240dpi, true);
+ addLabelToRoot(root, "Prescaled bitmap in drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addBitmapDrawable(layout, R.drawable.logo120dpi, false);
+ addBitmapDrawable(layout, R.drawable.logo160dpi, false);
+ addBitmapDrawable(layout, R.drawable.logo240dpi, false);
+ addLabelToRoot(root, "Autoscaled bitmap in drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addResourceDrawable(layout, R.drawable.logo120dpi);
+ addResourceDrawable(layout, R.drawable.logo160dpi);
+ addResourceDrawable(layout, R.drawable.logo240dpi);
+ addLabelToRoot(root, "Prescaled resource drawable");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addCanvasBitmap(layout, R.drawable.logo120dpi, true);
+ addCanvasBitmap(layout, R.drawable.logo160dpi, true);
+ addCanvasBitmap(layout, R.drawable.logo240dpi, true);
+ addLabelToRoot(root, "Prescaled bitmap");
+ addChildToRoot(root, layout);
+
+ layout = new LinearLayout(this);
+ addCanvasBitmap(layout, R.drawable.logo120dpi, false);
+ addCanvasBitmap(layout, R.drawable.logo160dpi, false);
+ addCanvasBitmap(layout, R.drawable.logo240dpi, false);
+ addLabelToRoot(root, "Autoscaled bitmap");
+ addChildToRoot(root, layout);
+
+ setContentView(scrollWrap(root));
+ }
+
+ private View scrollWrap(View view) {
+ ScrollView scroller = new ScrollView(this);
+ scroller.addView(view, new ScrollView.LayoutParams(ScrollView.LayoutParams.FILL_PARENT,
+ ScrollView.LayoutParams.FILL_PARENT));
+ return scroller;
+ }
+
+ private void addLabelToRoot(LinearLayout root, String text) {
+ TextView label = new TextView(this);
+ label.setText(text);
+ root.addView(label, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ }
+
+ private void addChildToRoot(LinearLayout root, LinearLayout layout) {
+ root.addView(layout, new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ }
+
+ private void addBitmapDrawable(LinearLayout layout, int resource, boolean scale) {
+ Bitmap bitmap;
+ bitmap = loadAndPrintDpi(resource, scale);
+
+ View view = new View(this);
+
+ final BitmapDrawable d = new BitmapDrawable(bitmap);
+ if (!scale) d.setDensityScale(getResources().getDisplayMetrics());
+ view.setBackgroundDrawable(d);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+ d.getIntrinsicHeight()));
+ layout.addView(view);
+ }
+
+ private void addResourceDrawable(LinearLayout layout, int resource) {
+ View view = new View(this);
+
+ final Drawable d = getResources().getDrawable(resource);
+ view.setBackgroundDrawable(d);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(d.getIntrinsicWidth(),
+ d.getIntrinsicHeight()));
+ layout.addView(view);
+ }
+
+ private void addCanvasBitmap(LinearLayout layout, int resource, boolean scale) {
+ Bitmap bitmap;
+ bitmap = loadAndPrintDpi(resource, scale);
+
+ ScaledBitmapView view = new ScaledBitmapView(this, bitmap);
+
+ view.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT));
+ layout.addView(view);
+ }
+
+ private Bitmap loadAndPrintDpi(int id, boolean scale) {
+ Bitmap bitmap;
+ if (scale) {
+ bitmap = BitmapFactory.decodeResource(getResources(), id);
+ } else {
+ BitmapFactory.Options opts = new BitmapFactory.Options();
+ opts.inScaled = false;
+ bitmap = BitmapFactory.decodeResource(getResources(), id, opts);
+ }
+ return bitmap;
+ }
+
+ private class ScaledBitmapView extends View {
+ private Bitmap mBitmap;
+
+ public ScaledBitmapView(Context context, Bitmap bitmap) {
+ super(context);
+ mBitmap = bitmap;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ setMeasuredDimension(mBitmap.getScaledWidth(), mBitmap.getScaledHeight());
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ canvas.drawBitmap(mBitmap, 0.0f, 0.0f, null);
+ }
+ }
+}
diff --git a/tests/DumpRenderTree/Android.mk b/tests/DumpRenderTree/Android.mk
new file mode 100644
index 0000000..505a436
--- /dev/null
+++ b/tests/DumpRenderTree/Android.mk
@@ -0,0 +1,12 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := DumpRenderTree
+
+include $(BUILD_PACKAGE)
diff --git a/tests/DumpRenderTree/AndroidManifest.xml b/tests/DumpRenderTree/AndroidManifest.xml
new file mode 100644
index 0000000..8e06cc8
--- /dev/null
+++ b/tests/DumpRenderTree/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.dumprendertree">
+ <application android:name="HTMLHostApp">
+ <uses-library android:name="android.test.runner" />
+ <activity android:name="Menu" android:label="1 Dump Render Tree">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.TEST" />
+ </intent-filter>
+ </activity>
+ <activity android:name="HTMLHostActivity">
+ </activity>
+ </application>
+
+ <instrumentation android:name=".LayoutTestsAutoRunner"
+ android:targetPackage="com.android.dumprendertree"
+ android:label="Layout test automation runner"
+ />
+</manifest>
diff --git a/tests/DumpRenderTree/compare_layout_results.py b/tests/DumpRenderTree/compare_layout_results.py
new file mode 100644
index 0000000..c4285f1
--- /dev/null
+++ b/tests/DumpRenderTree/compare_layout_results.py
@@ -0,0 +1,93 @@
+#!/usr/bin/python
+"""
+Compares results of two webkit layout test runs and writes
+results to a file.
+"""
+
+import optparse
+import os
+import sys
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+ """ Given two result files, generate diff and
+ write to diff_results file. All arguments are absolute paths
+ to files.
+ """
+ old_file = open(old_results, "r")
+ new_file = open(new_results, "r")
+ diff_file = open(diff_results, "a")
+
+ # Read lines from each file
+ ndict = new_file.readlines()
+ cdict = old_file.readlines()
+
+ # Write marker to diff file
+ diff_file.writelines(marker + "\n")
+ diff_file.writelines("###############\n")
+
+ # Strip reason from result lines
+ if strip_reason is True:
+ for i in range(0, len(ndict)):
+ ndict[i] = ndict[i].split(' ')[0] + "\n"
+ for i in range(0, len(cdict)):
+ cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+ # Find results in new_results missing in old_results
+ new_count=0
+ for line in ndict:
+ if line not in cdict:
+ diff_file.writelines("+ " + line)
+ new_count += 1
+
+ # Find results in old_results missing in new_results
+ missing_count=0
+ for line in cdict:
+ if line not in ndict:
+ diff_file.writelines("- " + line)
+ missing_count += 1
+
+ print marker + " >>> added " + str(new_count) + " tests, removed " + str(missing_count) + " tests"
+
+ diff_file.writelines("\n\n")
+
+ old_file.close()
+ new_file.close()
+ diff_file.close()
+ return
+
+def main(options, args):
+ results_dir = os.path.abspath(options.results_directory)
+ ref_dir = options.ref_directory
+
+ # if ref_dir is null, cannonify ref_dir to the script dir.
+ if not ref_dir:
+ script_self = sys.argv[0]
+ script_dir = os.path.dirname(script_self)
+ ref_dir = os.path.join(script_dir, "results")
+
+ ref_dir = os.path.abspath(ref_dir)
+
+ diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
+ if os.path.exists(diff_result):
+ os.remove(diff_result)
+
+ files=["passed", "failed", "nontext", "crashed"]
+ for f in files:
+ result_file_name = "layout_tests_" + f + ".txt"
+ DiffResults(f, os.path.join(results_dir, result_file_name),
+ os.path.join(ref_dir, result_file_name), diff_result,
+ f == "failed")
+
+if '__main__' == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--ref-directory",
+ default=None,
+ dest="ref_directory",
+ help="directory name under which results are stored.")
+
+ option_parser.add_option("", "--results-directory",
+ default="layout-test-results/",
+ dest="results_directory",
+ help="directory name under which results are stored.")
+ options, args = option_parser.parse_args()
+ main(options, args)
diff --git a/tests/DumpRenderTree/results/layout_tests_crashed.txt b/tests/DumpRenderTree/results/layout_tests_crashed.txt
new file mode 100644
index 0000000..1859f07
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_crashed.txt
@@ -0,0 +1,2 @@
+/sdcard/android/layout_tests/fast/js/regexp-charclass-crash.html
+/sdcard/android/layout_tests/fast/canvas/gradient-add-second-start-end-stop.html
diff --git a/tests/DumpRenderTree/results/layout_tests_failed.txt b/tests/DumpRenderTree/results/layout_tests_failed.txt
new file mode 100644
index 0000000..5a20b52
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_failed.txt
@@ -0,0 +1,283 @@
+/sdcard/android/layout_tests/fast/text/zero-width-characters.html : different length
+/sdcard/android/layout_tests/fast/text/reset-drag-on-mouse-down.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/text/plain-text-line-breaks.html : different length
+/sdcard/android/layout_tests/fast/replaced/table-percent-height.html : different length
+/sdcard/android/layout_tests/fast/replaced/image-map.html : different length
+/sdcard/android/layout_tests/fast/replaced/image-map-bug16782.html : different length
+/sdcard/android/layout_tests/fast/parser/xml-declaration-missing-ending-mark.html : different length
+/sdcard/android/layout_tests/fast/parser/tabindex-parsing.html : different length
+/sdcard/android/layout_tests/fast/parser/script-tag-with-trailing-slash.html : different length
+/sdcard/android/layout_tests/fast/parser/external-entities.xml : different length
+/sdcard/android/layout_tests/fast/parser/entity-end-script-tag.html : different length
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-iframe.html : @offset: 0
+/sdcard/android/layout_tests/fast/parser/comment-in-iframe.html : @offset: 0
+/sdcard/android/layout_tests/fast/overflow/scroll-vertical-not-horizontal.html : different length
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-missing-file-exception.html : different length
+/sdcard/android/layout_tests/fast/loader/stop-provisional-loads.html : different length
+/sdcard/android/layout_tests/fast/loader/plain-text-document.html : different length
+/sdcard/android/layout_tests/fast/loader/opaque-base-url.html : @offset: 129
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash.html : different length
+/sdcard/android/layout_tests/fast/loader/onunload-form-submit-crash-2.html : different length
+/sdcard/android/layout_tests/fast/loader/local-JavaScript-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/local-image-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/local-iFrame-source-from-local.html : different length
+/sdcard/android/layout_tests/fast/loader/local-CSS-from-local.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-svg.html : different length
+/sdcard/android/layout_tests/fast/loader/cancel-load-during-port-block-timer.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-gc-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/try-catch-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/toString-and-valueOf-override.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/recursion-limit-equal.html : different length
+/sdcard/android/layout_tests/fast/js/navigator-mimeTypes-length.html : different length
+/sdcard/android/layout_tests/fast/js/math-transforms.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/global-recursion-on-full-stack.html : different length
+/sdcard/android/layout_tests/fast/js/global-constructors.html : different length
+/sdcard/android/layout_tests/fast/js/exceptions-thrown-in-callbacks.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops2.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-sequencing-binops.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/js/exception-codegen-crash.html : different length
+/sdcard/android/layout_tests/fast/js/duplicate-param-gc-crash.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/html/tab-order.html : @offset: 246
+/sdcard/android/layout_tests/fast/history/subframe-is-visited.html : different length
+/sdcard/android/layout_tests/fast/history/go-back-to-changed-name.html : different length
+/sdcard/android/layout_tests/fast/frames/viewsource-empty-attribute-value.html : different length
+/sdcard/android/layout_tests/fast/frames/removal-before-attach-crash.html : different length
+/sdcard/android/layout_tests/fast/frames/iframe-window-focus.html : different length
+/sdcard/android/layout_tests/fast/frames/frameElement-widthheight.html : different length
+/sdcard/android/layout_tests/fast/frames/frame-js-url-clientWidth.html : different length
+/sdcard/android/layout_tests/fast/frames/frame-base-url.html : different length
+/sdcard/android/layout_tests/fast/frames/empty-frame-src.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-text-plain-with-accept-charset.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-x-www-form-urlencoded.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-multiple-items-multipart-form-data.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/post-append-query.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-overwrite-query.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-text-plain-latin-1.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-non-ascii-always-utf-8.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-x-www-form-urlencoded.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/get-multiple-items-text-plain.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-put.html : different length
+/sdcard/android/layout_tests/fast/forms/mailto/advanced-get.html : different length
+/sdcard/android/layout_tests/fast/forms/textfield-to-password-on-focus.html : different length
+/sdcard/android/layout_tests/fast/forms/textfield-onchange-deletion.html : different length
+/sdcard/android/layout_tests/fast/forms/textfield-inside-anchor.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-type-spaces.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-scrolled-endline-caret.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-paste-newline.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-no-scroll-on-blur.html : @offset: 79
+/sdcard/android/layout_tests/fast/forms/textarea-initial-caret-position.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap.html : different length
+/sdcard/android/layout_tests/fast/forms/textarea-default-value-leading-newline.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/textarea-appearance-wrap.html : different length
+/sdcard/android/layout_tests/fast/forms/text-field-setvalue-crash.html : different length
+/sdcard/android/layout_tests/fast/forms/stuff-on-my-optgroup.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/slider-onchange-event.html : different length
+/sdcard/android/layout_tests/fast/forms/slider-mouse-events.html : different length
+/sdcard/android/layout_tests/fast/forms/selection-functions.html : @offset: 306
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-non-latin.html : different length
+/sdcard/android/layout_tests/fast/forms/select-enter-key.html : different length
+/sdcard/android/layout_tests/fast/forms/select-empty-list.html : different length
+/sdcard/android/layout_tests/fast/forms/select-double-onchange.html : different length
+/sdcard/android/layout_tests/fast/forms/select-accesskey.html : different length
+/sdcard/android/layout_tests/fast/forms/search-hidden-cancel-button.html : different length
+/sdcard/android/layout_tests/fast/forms/search-event-delay.html : different length
+/sdcard/android/layout_tests/fast/forms/search-click-in-placeholder.html : @offset: 1
+/sdcard/android/layout_tests/fast/forms/search-cancel-button-mouseup.html : different length
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-1.html : different length
+/sdcard/android/layout_tests/fast/forms/password-doubleclick-selection.html : different length
+/sdcard/android/layout_tests/fast/forms/onselect-textfield.html : different length
+/sdcard/android/layout_tests/fast/forms/onselect-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/onselect-selectall.html : different length
+/sdcard/android/layout_tests/fast/forms/onchange-enter-submit.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-scroll.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-selection.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-select-all.html : different length
+/sdcard/android/layout_tests/fast/forms/listbox-onchange.html : different length
+/sdcard/android/layout_tests/fast/forms/legend-access-key.html : different length
+/sdcard/android/layout_tests/fast/forms/input-select-on-click.html : different length
+/sdcard/android/layout_tests/fast/forms/input-radio-checked-tab.html : @offset: 115
+/sdcard/android/layout_tests/fast/forms/input-maxlength.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/input-implicit-length-limit.html : different length
+/sdcard/android/layout_tests/fast/forms/input-first-letter.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/input-delete.html : different length
+/sdcard/android/layout_tests/fast/forms/form-element-geometry.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/forms/form-collection-lookup.html : different length
+/sdcard/android/layout_tests/fast/forms/form-and-frame-interaction-retains-values.html : different length
+/sdcard/android/layout_tests/fast/forms/focus2.html : different length
+/sdcard/android/layout_tests/fast/forms/focus.html : different length
+/sdcard/android/layout_tests/fast/forms/focus-selection-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/focus-selection-input.html : different length
+/sdcard/android/layout_tests/fast/forms/focus-control-to-page.html : different length
+/sdcard/android/layout_tests/fast/forms/enter-clicks-buttons.html : different length
+/sdcard/android/layout_tests/fast/forms/drag-out-of-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/drag-into-textarea.html : different length
+/sdcard/android/layout_tests/fast/forms/check-box-enter-key.html : different length
+/sdcard/android/layout_tests/fast/forms/button-state-restore.html : different length
+/sdcard/android/layout_tests/fast/forms/button-spacebar-click.html : different length
+/sdcard/android/layout_tests/fast/forms/button-enter-click.html : different length
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-003.html : @offset: 51
+/sdcard/android/layout_tests/fast/forms/access-key.html : different length
+/sdcard/android/layout_tests/fast/events/window-events-capture.html : different length
+/sdcard/android/layout_tests/fast/events/window-events-bubble2.html : different length
+/sdcard/android/layout_tests/fast/events/window-events-bubble.html : different length
+/sdcard/android/layout_tests/fast/events/tabindex-focus-chain.html : @offset: 0
+/sdcard/android/layout_tests/fast/events/scrollbar-double-click.html : different length
+/sdcard/android/layout_tests/fast/events/scroll-to-anchor-in-overflow-hidden.html : different length
+/sdcard/android/layout_tests/fast/events/scroll-event-does-not-bubble.html : different length
+/sdcard/android/layout_tests/fast/events/related-target.html : different length
+/sdcard/android/layout_tests/fast/events/option-tab.html : different length
+/sdcard/android/layout_tests/fast/events/open-window-from-another-frame.html : different length
+/sdcard/android/layout_tests/fast/events/onunload.html : different length
+/sdcard/android/layout_tests/fast/events/onunload-window-property.html : different length
+/sdcard/android/layout_tests/fast/events/onunload-not-on-body.html : different length
+/sdcard/android/layout_tests/fast/events/onunload-clears-onbeforeunload.html : different length
+/sdcard/android/layout_tests/fast/events/onsearch-enter.html : different length
+/sdcard/android/layout_tests/fast/events/onload-webkit-before-webcore.html : @offset: 105
+/sdcard/android/layout_tests/fast/events/ondragenter.html : different length
+/sdcard/android/layout_tests/fast/events/onclick-list-marker.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-textfield.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-select-popup.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-searchfield.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-passwordfield.html : different length
+/sdcard/android/layout_tests/fast/events/onchange-click-hang.html : different length
+/sdcard/android/layout_tests/fast/events/mouseup-outside-document.html : different length
+/sdcard/android/layout_tests/fast/events/mouseup-from-button2.html : different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout2.html : different length
+/sdcard/android/layout_tests/fast/events/mouseover-mouseout.html : different length
+/sdcard/android/layout_tests/fast/events/mouseout-on-window.html : different length
+/sdcard/android/layout_tests/fast/events/mouseout-dead-subframe.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/mousemove-after-drag-over-scrollbar.html : different length
+/sdcard/android/layout_tests/fast/events/mouseclick-target-and-positioning.html : different length
+/sdcard/android/layout_tests/fast/events/mouse-click-events.html : different length
+/sdcard/android/layout_tests/fast/events/keypress-insert-tab.html : @offset: 85
+/sdcard/android/layout_tests/fast/events/keypress-focus-change.html : different length
+/sdcard/android/layout_tests/fast/events/keydown-keypress-preventDefault.html : @offset: 228
+/sdcard/android/layout_tests/fast/events/keydown-keypress-focus-change.html : @offset: 172
+/sdcard/android/layout_tests/fast/events/key-events-in-input-text.html : different length
+/sdcard/android/layout_tests/fast/events/key-events-in-input-button.html : different length
+/sdcard/android/layout_tests/fast/events/js-keyboard-event-creation.html : different length
+/sdcard/android/layout_tests/fast/events/input-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/iframe-object-onload.html : different length
+/sdcard/android/layout_tests/fast/events/frame-tab-focus.html : different length
+/sdcard/android/layout_tests/fast/events/frame-programmatic-focus.html : different length
+/sdcard/android/layout_tests/fast/events/frame-click-focus.html : different length
+/sdcard/android/layout_tests/fast/events/fire-scroll-event.html : different length
+/sdcard/android/layout_tests/fast/events/event-view-toString.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/drag-outside-window.html : @offset: 20
+/sdcard/android/layout_tests/fast/events/drag-in-frames.html : different length
+/sdcard/android/layout_tests/fast/events/dblclick-addEventListener.html : different length
+/sdcard/android/layout_tests/fast/events/contextmenu-scrolled-page-with-frame.html : different length
+/sdcard/android/layout_tests/fast/events/content-changed-during-drop.html : different length
+/sdcard/android/layout_tests/fast/events/click-count.html : different length
+/sdcard/android/layout_tests/fast/events/capture-on-target.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-with-non-scrollable-parent.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-nonscrollable-iframe-in-scrollable-div.html : different length
+/sdcard/android/layout_tests/fast/events/autoscroll-in-textfield.html : different length
+/sdcard/android/layout_tests/fast/events/arrow-navigation.html : different length
+/sdcard/android/layout_tests/fast/events/arrow-keys-on-body.html : different length
+/sdcard/android/layout_tests/fast/events/anchor-image-scrolled-x-y.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/events/access-key-self-destruct.html : different length
+/sdcard/android/layout_tests/fast/encoding/xml-utf-8-default.xml : different length
+/sdcard/android/layout_tests/fast/encoding/url-host-name-non-ascii.html : different length
+/sdcard/android/layout_tests/fast/encoding/percent-escaping.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/encoding/mailto-always-utf-8.html : different length
+/sdcard/android/layout_tests/fast/encoding/invalid-xml.html : different length
+/sdcard/android/layout_tests/fast/encoding/idn-security.html : different length
+/sdcard/android/layout_tests/fast/encoding/frame-default-enc.html : @offset: 0
+/sdcard/android/layout_tests/fast/encoding/charset-koi8-u.html : @offset: 147
+/sdcard/android/layout_tests/fast/encoding/char-encoding.html : different length
+/sdcard/android/layout_tests/fast/encoding/char-decoding.html : different length
+/sdcard/android/layout_tests/fast/dynamic/paused-event-dispatch.html : @offset: 117
+/sdcard/android/layout_tests/fast/dom/Window/window-xy-properties.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-scroll-arguments.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-screen-properties.html : @offset: 65
+/sdcard/android/layout_tests/fast/dom/Window/window-resize.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-arguments.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-property-clearing.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-properties.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/window-open-pending-url.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-onFocus.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-function-name-getter-precedence.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/window-early-properties.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/setting-properties-on-closed-window.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/redirect-with-timer.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/Plug-ins.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/orphaned-frame-access.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/new-window-opener.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/Window/get-set-properties.html : @offset: 0
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-window.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/dom-access-from-closure-iframe.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/console-functions.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-window.html : different length
+/sdcard/android/layout_tests/fast/dom/Window/clear-timeout.html : different length
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime-2.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/listbox-select-reset.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/object-as-frame.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/hasFocus.html : different length
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/activeElement.html : different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/011.xml : different length
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/010.xml : different length
+/sdcard/android/layout_tests/fast/dom/Element/offsetLeft-offsetTop-body-quirk.html : different length
+/sdcard/android/layout_tests/fast/dom/DOMException/XPathException.html : different length
+/sdcard/android/layout_tests/fast/dom/wrapper-classes.html : different length
+/sdcard/android/layout_tests/fast/dom/tabindex-clamp.html : different length
+/sdcard/android/layout_tests/fast/dom/simultaneouslyRegsiteredTimerFireOrder.html : different length
+/sdcard/android/layout_tests/fast/dom/set-frame-src-while-running-script-in-frame.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex.html : different length
+/sdcard/android/layout_tests/fast/dom/open-and-close-by-DOM.html : different length
+/sdcard/android/layout_tests/fast/dom/onerror-img.html : different length
+/sdcard/android/layout_tests/fast/dom/object-plugin-hides-properties.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/object-embed-plugin-scripting.html : different length
+/sdcard/android/layout_tests/fast/dom/null-document-window-open-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-replace-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-put-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-href-put-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/null-document-location-assign-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/null-chardata-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/noscript-style.html : different length
+/sdcard/android/layout_tests/fast/dom/noscript-canvas-in-created-html-document.html : different length
+/sdcard/android/layout_tests/fast/dom/non-numeric-values-numeric-parameters.html : different length
+/sdcard/android/layout_tests/fast/dom/node-item.html : different length
+/sdcard/android/layout_tests/fast/dom/node-filter-gc.html : @offset: 1
+/sdcard/android/layout_tests/fast/dom/no-elements.html : different length
+/sdcard/android/layout_tests/fast/dom/navigator-vendorSub.html : different length
+/sdcard/android/layout_tests/fast/dom/namespaces-1.html : different length
+/sdcard/android/layout_tests/fast/dom/NamedNodeMap-setNamedItem-crash.html : different length
+/sdcard/android/layout_tests/fast/dom/namednodemap-namelookup.html : different length
+/sdcard/android/layout_tests/fast/dom/mutation-event-remove-inserted-node.html : different length
+/sdcard/android/layout_tests/fast/dom/location-hash.html : different length
+/sdcard/android/layout_tests/fast/dom/length-attribute-mapping.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/javascript-url-crash-function.html : different length
+/sdcard/android/layout_tests/fast/dom/inner-text-001.html : different length
+/sdcard/android/layout_tests/fast/dom/global-constructors.html : different length
+/sdcard/android/layout_tests/fast/dom/gc-acid3.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/gc-9.html : different length
+/sdcard/android/layout_tests/fast/dom/gc-8.html : different length
+/sdcard/android/layout_tests/fast/dom/frame-loading-via-document-write.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/dom/documenturi-not-affected-by-base-tag.html : different length
+/sdcard/android/layout_tests/fast/dom/documenturi-can-hold-arbitrary-string.html : different length
+/sdcard/android/layout_tests/fast/dom/document-width-height-force-layout.html : @offset: 142
+/sdcard/android/layout_tests/fast/dom/constructors-cached.html : different length
+/sdcard/android/layout_tests/fast/dom/constructors-cached-navigate.html : different length
+/sdcard/android/layout_tests/fast/dom/client-width-height.html : @offset: 119
+/sdcard/android/layout_tests/fast/dom/client-width-height-quirks.html : @offset: 115
+/sdcard/android/layout_tests/fast/dom/assign-to-window-status.html : different length
+/sdcard/android/layout_tests/fast/css/variables/color-hex-test.html : different length
+/sdcard/android/layout_tests/fast/css/html-attr-case-sensitivity.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/css/hover-affects-child.html : different length
+/sdcard/android/layout_tests/fast/css/getComputedStyle-transform.html : different length
+/sdcard/android/layout_tests/fast/css/dashboard-region-parser.html : different length
+/sdcard/android/layout_tests/fast/css/computed-style.html : different length
+/sdcard/android/layout_tests/fast/css/computed-style-without-renderer.html : different length
+/sdcard/android/layout_tests/fast/canvas/toDataURL-supportedTypes.html : different length
+/sdcard/android/layout_tests/fast/canvas/canvas-save-restore-with-path.html : different length
+/sdcard/android/layout_tests/fast/canvas/canvas-longlived-context.html : TIMEDOUT
+/sdcard/android/layout_tests/fast/canvas/canvas-getImageData.html : different length
+/sdcard/android/layout_tests/fast/canvas/canvas-alphaImageData-behavior.html : different length
diff --git a/tests/DumpRenderTree/results/layout_tests_nontext.txt b/tests/DumpRenderTree/results/layout_tests_nontext.txt
new file mode 100644
index 0000000..0355cb72
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_nontext.txt
@@ -0,0 +1,1658 @@
+/sdcard/android/layout_tests/fast/transforms/transforms-with-opacity.html
+/sdcard/android/layout_tests/fast/transforms/transform-positioned-ancestor.html
+/sdcard/android/layout_tests/fast/transforms/transform-overflow.html
+/sdcard/android/layout_tests/fast/transforms/skew-with-unitless-zero.html
+/sdcard/android/layout_tests/fast/transforms/shadows.html
+/sdcard/android/layout_tests/fast/transforms/overflow-with-transform.html
+/sdcard/android/layout_tests/fast/transforms/matrix-02.html
+/sdcard/android/layout_tests/fast/transforms/matrix-01.html
+/sdcard/android/layout_tests/fast/transforms/identity-matrix.html
+/sdcard/android/layout_tests/fast/transforms/diamond.html
+/sdcard/android/layout_tests/fast/tokenizer/script_extra_close.html
+/sdcard/android/layout_tests/fast/tokenizer/script-after-frameset.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-title-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-2.html
+/sdcard/android/layout_tests/fast/tokenizer/missing-style-end-tag-1.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write_2.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-write.html
+/sdcard/android/layout_tests/fast/tokenizer/003.html
+/sdcard/android/layout_tests/fast/tokenizer/002.html
+/sdcard/android/layout_tests/fast/tokenizer/001.html
+/sdcard/android/layout_tests/fast/text/whitespace/tab-character-basics.html
+/sdcard/android/layout_tests/fast/text/whitespace/span-in-word-space-causes-overflow.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-spaces-after-newline.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-overflow-selection.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-line-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-wrap-last-char.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-newline-box-test.html
+/sdcard/android/layout_tests/fast/text/whitespace/pre-break-word.html
+/sdcard/android/layout_tests/fast/text/whitespace/nowrap-clear-float.html
+/sdcard/android/layout_tests/fast/text/whitespace/normal-after-nowrap-breaking.html
+/sdcard/android/layout_tests/fast/text/whitespace/nbsp-mode-and-linewraps.html
+/sdcard/android/layout_tests/fast/text/whitespace/030.html
+/sdcard/android/layout_tests/fast/text/whitespace/029.html
+/sdcard/android/layout_tests/fast/text/whitespace/028.html
+/sdcard/android/layout_tests/fast/text/whitespace/027.html
+/sdcard/android/layout_tests/fast/text/whitespace/026.html
+/sdcard/android/layout_tests/fast/text/whitespace/025.html
+/sdcard/android/layout_tests/fast/text/whitespace/024.html
+/sdcard/android/layout_tests/fast/text/whitespace/023.html
+/sdcard/android/layout_tests/fast/text/whitespace/022.html
+/sdcard/android/layout_tests/fast/text/whitespace/021.html
+/sdcard/android/layout_tests/fast/text/whitespace/020.html
+/sdcard/android/layout_tests/fast/text/whitespace/019.html
+/sdcard/android/layout_tests/fast/text/whitespace/018.html
+/sdcard/android/layout_tests/fast/text/whitespace/017.html
+/sdcard/android/layout_tests/fast/text/whitespace/016.html
+/sdcard/android/layout_tests/fast/text/whitespace/015.html
+/sdcard/android/layout_tests/fast/text/whitespace/014.html
+/sdcard/android/layout_tests/fast/text/whitespace/013.html
+/sdcard/android/layout_tests/fast/text/whitespace/012.html
+/sdcard/android/layout_tests/fast/text/whitespace/011.html
+/sdcard/android/layout_tests/fast/text/whitespace/010.html
+/sdcard/android/layout_tests/fast/text/whitespace/009.html
+/sdcard/android/layout_tests/fast/text/whitespace/008.html
+/sdcard/android/layout_tests/fast/text/whitespace/007.html
+/sdcard/android/layout_tests/fast/text/whitespace/006.html
+/sdcard/android/layout_tests/fast/text/whitespace/005.html
+/sdcard/android/layout_tests/fast/text/whitespace/004.html
+/sdcard/android/layout_tests/fast/text/whitespace/003.html
+/sdcard/android/layout_tests/fast/text/whitespace/002.html
+/sdcard/android/layout_tests/fast/text/whitespace/001.html
+/sdcard/android/layout_tests/fast/text/international/wrap-CJK-001.html
+/sdcard/android/layout_tests/fast/text/international/thai-line-breaks.html
+/sdcard/android/layout_tests/fast/text/international/rtl-white-space-pre-wrap.html
+/sdcard/android/layout_tests/fast/text/international/rtl-caret.html
+/sdcard/android/layout_tests/fast/text/international/hindi-spacing.html
+/sdcard/android/layout_tests/fast/text/international/complex-character-based-fallback.html
+/sdcard/android/layout_tests/fast/text/international/bidi-override.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-run.html
+/sdcard/android/layout_tests/fast/text/international/bidi-neutral-directionality-paragraph-start.html
+/sdcard/android/layout_tests/fast/text/international/bidi-menulist.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox.html
+/sdcard/android/layout_tests/fast/text/international/bidi-listbox-atsui.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-HTML.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-formatting-characters.html
+/sdcard/android/layout_tests/fast/text/international/bidi-LDB-2-CSS.html
+/sdcard/android/layout_tests/fast/text/international/bidi-layout-across-linebreak.html
+/sdcard/android/layout_tests/fast/text/international/bidi-L2-run-reordering.html
+/sdcard/android/layout_tests/fast/text/international/bidi-innertext.html
+/sdcard/android/layout_tests/fast/text/international/bidi-ignored-for-first-child-inline.html
+/sdcard/android/layout_tests/fast/text/international/bidi-explicit-embedding.html
+/sdcard/android/layout_tests/fast/text/international/bidi-european-terminators.html
+/sdcard/android/layout_tests/fast/text/international/bidi-CS-after-AN.html
+/sdcard/android/layout_tests/fast/text/international/bidi-control-chars-treated-as-ZWS.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-L.html
+/sdcard/android/layout_tests/fast/text/international/bidi-AN-after-empty-run.html
+/sdcard/android/layout_tests/fast/text/international/003.html
+/sdcard/android/layout_tests/fast/text/international/002.html
+/sdcard/android/layout_tests/fast/text/international/001.html
+/sdcard/android/layout_tests/fast/text/firstline/003.html
+/sdcard/android/layout_tests/fast/text/firstline/002.html
+/sdcard/android/layout_tests/fast/text/firstline/001.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-reset.html
+/sdcard/android/layout_tests/fast/text/basic/generic-family-changes.html
+/sdcard/android/layout_tests/fast/text/basic/015.html
+/sdcard/android/layout_tests/fast/text/basic/014.html
+/sdcard/android/layout_tests/fast/text/basic/013.html
+/sdcard/android/layout_tests/fast/text/basic/012.html
+/sdcard/android/layout_tests/fast/text/basic/011.html
+/sdcard/android/layout_tests/fast/text/basic/009.html
+/sdcard/android/layout_tests/fast/text/basic/008.html
+/sdcard/android/layout_tests/fast/text/basic/007.html
+/sdcard/android/layout_tests/fast/text/basic/006.html
+/sdcard/android/layout_tests/fast/text/basic/005.html
+/sdcard/android/layout_tests/fast/text/basic/004.html
+/sdcard/android/layout_tests/fast/text/basic/003.html
+/sdcard/android/layout_tests/fast/text/basic/002.html
+/sdcard/android/layout_tests/fast/text/basic/001.html
+/sdcard/android/layout_tests/fast/text/word-space.html
+/sdcard/android/layout_tests/fast/text/word-break.html
+/sdcard/android/layout_tests/fast/text/word-break-soft-hyphen.html
+/sdcard/android/layout_tests/fast/text/word-break-run-rounding.html
+/sdcard/android/layout_tests/fast/text/wide-zero-width-space.html
+/sdcard/android/layout_tests/fast/text/wbr.html
+/sdcard/android/layout_tests/fast/text/wbr-styled.html
+/sdcard/android/layout_tests/fast/text/wbr-pre.html
+/sdcard/android/layout_tests/fast/text/wbr-in-pre-crash.html
+/sdcard/android/layout_tests/fast/text/updateNewFont.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space.html
+/sdcard/android/layout_tests/fast/text/trailing-white-space-2.html
+/sdcard/android/layout_tests/fast/text/textIteratorNilRenderer.html
+/sdcard/android/layout_tests/fast/text/stroking.html
+/sdcard/android/layout_tests/fast/text/stroking-decorations.html
+/sdcard/android/layout_tests/fast/text/stripNullFromText.html
+/sdcard/android/layout_tests/fast/text/softHyphen.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-3.html
+/sdcard/android/layout_tests/fast/text/soft-hyphen-2.html
+/sdcard/android/layout_tests/fast/text/should-use-atsui.html
+/sdcard/android/layout_tests/fast/text/shadow-no-blur.html
+/sdcard/android/layout_tests/fast/text/selection-painted-separately.html
+/sdcard/android/layout_tests/fast/text/selection-hard-linebreak.html
+/sdcard/android/layout_tests/fast/text/reset-emptyRun.html
+/sdcard/android/layout_tests/fast/text/monospace-width-cache.html
+/sdcard/android/layout_tests/fast/text/midword-break-hang.html
+/sdcard/android/layout_tests/fast/text/midword-break-after-breakable-char.html
+/sdcard/android/layout_tests/fast/text/line-breaks.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-white-space.html
+/sdcard/android/layout_tests/fast/text/letter-spacing-negative-opacity.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char.html
+/sdcard/android/layout_tests/fast/text/justified-selection.html
+/sdcard/android/layout_tests/fast/text/justified-selection-at-edge.html
+/sdcard/android/layout_tests/fast/text/in-rendered-text-rtl.html
+/sdcard/android/layout_tests/fast/text/font-initial.html
+/sdcard/android/layout_tests/fast/text/fixed-pitch-control-characters.html
+/sdcard/android/layout_tests/fast/text/embed-at-end-of-pre-wrap-line.html
+/sdcard/android/layout_tests/fast/text/drawBidiText.html
+/sdcard/android/layout_tests/fast/text/delete-hard-break-character.html
+/sdcard/android/layout_tests/fast/text/cg-vs-atsui.html
+/sdcard/android/layout_tests/fast/text/cg-fallback-bolding.html
+/sdcard/android/layout_tests/fast/text/capitalize-preserve-nbsp.html
+/sdcard/android/layout_tests/fast/text/capitalize-empty-generated-string.html
+/sdcard/android/layout_tests/fast/text/capitalize-boundaries.html
+/sdcard/android/layout_tests/fast/text/break-word.html
+/sdcard/android/layout_tests/fast/text/bidi-embedding-pop-and-push-same.html
+/sdcard/android/layout_tests/fast/text/atsui-spacing-features.html
+/sdcard/android/layout_tests/fast/text/atsui-small-caps-punctuation-size.html
+/sdcard/android/layout_tests/fast/text/atsui-rtl-override-selection.html
+/sdcard/android/layout_tests/fast/text/atsui-pointtooffset-calls-cg.html
+/sdcard/android/layout_tests/fast/text/atsui-partial-selection.html
+/sdcard/android/layout_tests/fast/text/atsui-multiple-renderers.html
+/sdcard/android/layout_tests/fast/text/atsui-kerning-and-ligatures.html
+/sdcard/android/layout_tests/fast/text/apply-start-width-after-skipped-text.html
+/sdcard/android/layout_tests/fast/text/align-center-rtl-spill.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/rtl-border-collapsing.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/equal-precedence-resolution.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/border-collapsing-head-foot.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/004.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/003.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/002.html
+/sdcard/android/layout_tests/fast/table/border-collapsing/001.html
+/sdcard/android/layout_tests/fast/table/wide-column.html
+/sdcard/android/layout_tests/fast/table/wide-colspan.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline.html
+/sdcard/android/layout_tests/fast/table/vertical-align-baseline-readjust.html
+/sdcard/android/layout_tests/fast/table/unused-percent-heights.html
+/sdcard/android/layout_tests/fast/table/unbreakable-images-quirk.html
+/sdcard/android/layout_tests/fast/table/text-field-baseline.html
+/sdcard/android/layout_tests/fast/table/tableInsideCaption.html
+/sdcard/android/layout_tests/fast/table/table-hspace-align-center.html
+/sdcard/android/layout_tests/fast/table/table-display-types.html
+/sdcard/android/layout_tests/fast/table/table-display-types-strict.html
+/sdcard/android/layout_tests/fast/table/stale-grid-crash.html
+/sdcard/android/layout_tests/fast/table/spanOverlapRepaint.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange2.html
+/sdcard/android/layout_tests/fast/table/rules-attr-dynchange1.html
+/sdcard/android/layout_tests/fast/table/rtl-cell-display-none-assert.html
+/sdcard/android/layout_tests/fast/table/rowspan-paint-order.html
+/sdcard/android/layout_tests/fast/table/rowindex.html
+/sdcard/android/layout_tests/fast/table/row-height-recalc.html
+/sdcard/android/layout_tests/fast/table/replaced-percent-height.html
+/sdcard/android/layout_tests/fast/table/remove-td-display-none.html
+/sdcard/android/layout_tests/fast/table/prepend-in-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/percent-widths-stretch.html
+/sdcard/android/layout_tests/fast/table/percent-heights.html
+/sdcard/android/layout_tests/fast/table/overflowHidden.html
+/sdcard/android/layout_tests/fast/table/nobr.html
+/sdcard/android/layout_tests/fast/table/nested-percent-height-table.html
+/sdcard/android/layout_tests/fast/table/multiple-percent-height-rows.html
+/sdcard/android/layout_tests/fast/table/max-width-integer-overflow.html
+/sdcard/android/layout_tests/fast/table/large-width.html
+/sdcard/android/layout_tests/fast/table/invisible-cell-background.html
+/sdcard/android/layout_tests/fast/table/insert-row-before-form.html
+/sdcard/android/layout_tests/fast/table/insert-cell-before-form.html
+/sdcard/android/layout_tests/fast/table/insert-before-anonymous-ancestors.html
+/sdcard/android/layout_tests/fast/table/inline-form-assert.html
+/sdcard/android/layout_tests/fast/table/height-percent-test.html
+/sdcard/android/layout_tests/fast/table/growCellForImageQuirk.html
+/sdcard/android/layout_tests/fast/table/giantRowspan2.html
+/sdcard/android/layout_tests/fast/table/giantRowspan.html
+/sdcard/android/layout_tests/fast/table/giantCellspacing.html
+/sdcard/android/layout_tests/fast/table/generated-caption.html
+/sdcard/android/layout_tests/fast/table/frame-and-rules.html
+/sdcard/android/layout_tests/fast/table/form-with-table-style.html
+/sdcard/android/layout_tests/fast/table/floating-th.html
+/sdcard/android/layout_tests/fast/table/fixed-with-auto-with-colspan.html
+/sdcard/android/layout_tests/fast/table/fixed-table-non-cell-in-row.html
+/sdcard/android/layout_tests/fast/table/fixed-nested.html
+/sdcard/android/layout_tests/fast/table/empty-table-percent-height.html
+/sdcard/android/layout_tests/fast/table/empty-section-crash.html
+/sdcard/android/layout_tests/fast/table/empty-row-crash.html
+/sdcard/android/layout_tests/fast/table/empty-cells.html
+/sdcard/android/layout_tests/fast/table/edge-offsets.html
+/sdcard/android/layout_tests/fast/table/dynamic-cellpadding.html
+/sdcard/android/layout_tests/fast/table/div-as-col-span.html
+/sdcard/android/layout_tests/fast/table/colgroup-spanning-groups-rules.html
+/sdcard/android/layout_tests/fast/table/colgroup-preceded-by-caption.html
+/sdcard/android/layout_tests/fast/table/click-near-anonymous-table.html
+/sdcard/android/layout_tests/fast/table/cellindex.html
+/sdcard/android/layout_tests/fast/table/cell-pref-width-invalidation.html
+/sdcard/android/layout_tests/fast/table/cell-width-auto.html
+/sdcard/android/layout_tests/fast/table/cell-absolute-child.html
+/sdcard/android/layout_tests/fast/table/caption-relayout.html
+/sdcard/android/layout_tests/fast/table/auto-with-percent-height.html
+/sdcard/android/layout_tests/fast/table/append-cells2.html
+/sdcard/android/layout_tests/fast/table/append-cells.html
+/sdcard/android/layout_tests/fast/table/add-before-anonymous-child.html
+/sdcard/android/layout_tests/fast/table/absolute-table-at-bottom.html
+/sdcard/android/layout_tests/fast/table/100-percent-cell-width.html
+/sdcard/android/layout_tests/fast/table/041.html
+/sdcard/android/layout_tests/fast/table/040.html
+/sdcard/android/layout_tests/fast/table/039.html
+/sdcard/android/layout_tests/fast/table/038.html
+/sdcard/android/layout_tests/fast/table/037.xml
+/sdcard/android/layout_tests/fast/table/036.html
+/sdcard/android/layout_tests/fast/table/035.html
+/sdcard/android/layout_tests/fast/table/034.html
+/sdcard/android/layout_tests/fast/table/033.html
+/sdcard/android/layout_tests/fast/table/032.html
+/sdcard/android/layout_tests/fast/table/031.html
+/sdcard/android/layout_tests/fast/table/030.html
+/sdcard/android/layout_tests/fast/table/029.html
+/sdcard/android/layout_tests/fast/table/028.html
+/sdcard/android/layout_tests/fast/table/027.html
+/sdcard/android/layout_tests/fast/table/026.html
+/sdcard/android/layout_tests/fast/table/025.html
+/sdcard/android/layout_tests/fast/table/024.html
+/sdcard/android/layout_tests/fast/table/023.html
+/sdcard/android/layout_tests/fast/table/022.html
+/sdcard/android/layout_tests/fast/table/021.html
+/sdcard/android/layout_tests/fast/table/020.html
+/sdcard/android/layout_tests/fast/table/018.html
+/sdcard/android/layout_tests/fast/table/017.html
+/sdcard/android/layout_tests/fast/table/016.html
+/sdcard/android/layout_tests/fast/table/015.html
+/sdcard/android/layout_tests/fast/table/014.html
+/sdcard/android/layout_tests/fast/table/013.html
+/sdcard/android/layout_tests/fast/table/012.html
+/sdcard/android/layout_tests/fast/table/011.html
+/sdcard/android/layout_tests/fast/table/010.html
+/sdcard/android/layout_tests/fast/table/009.html
+/sdcard/android/layout_tests/fast/table/008.html
+/sdcard/android/layout_tests/fast/table/007.html
+/sdcard/android/layout_tests/fast/table/006.html
+/sdcard/android/layout_tests/fast/table/005.html
+/sdcard/android/layout_tests/fast/table/004.html
+/sdcard/android/layout_tests/fast/table/003.html
+/sdcard/android/layout_tests/fast/table/002.html
+/sdcard/android/layout_tests/fast/table/001.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-strict.html
+/sdcard/android/layout_tests/fast/selectors/unqualified-hover-quirks.html
+/sdcard/android/layout_tests/fast/selectors/nondeterministic-combinators.html
+/sdcard/android/layout_tests/fast/selectors/lang-vs-xml-lang.html
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance2.html
+/sdcard/android/layout_tests/fast/selectors/lang-inheritance.html
+/sdcard/android/layout_tests/fast/selectors/177b.html
+/sdcard/android/layout_tests/fast/selectors/177a.html
+/sdcard/android/layout_tests/fast/selectors/175c.html
+/sdcard/android/layout_tests/fast/selectors/175b.html
+/sdcard/android/layout_tests/fast/selectors/175a.html
+/sdcard/android/layout_tests/fast/selectors/170d.html
+/sdcard/android/layout_tests/fast/selectors/170c.html
+/sdcard/android/layout_tests/fast/selectors/170b.html
+/sdcard/android/layout_tests/fast/selectors/170a.html
+/sdcard/android/layout_tests/fast/selectors/170.html
+/sdcard/android/layout_tests/fast/selectors/169a.html
+/sdcard/android/layout_tests/fast/selectors/169.html
+/sdcard/android/layout_tests/fast/selectors/168a.html
+/sdcard/android/layout_tests/fast/selectors/168.html
+/sdcard/android/layout_tests/fast/selectors/167a.html
+/sdcard/android/layout_tests/fast/selectors/167.html
+/sdcard/android/layout_tests/fast/selectors/166a.html
+/sdcard/android/layout_tests/fast/selectors/166.html
+/sdcard/android/layout_tests/fast/selectors/160.html
+/sdcard/android/layout_tests/fast/selectors/159.html
+/sdcard/android/layout_tests/fast/selectors/158.html
+/sdcard/android/layout_tests/fast/selectors/157.html
+/sdcard/android/layout_tests/fast/selectors/156b.html
+/sdcard/android/layout_tests/fast/selectors/155d.html
+/sdcard/android/layout_tests/fast/selectors/155c.html
+/sdcard/android/layout_tests/fast/selectors/155b.html
+/sdcard/android/layout_tests/fast/selectors/155a.html
+/sdcard/android/layout_tests/fast/selectors/155.html
+/sdcard/android/layout_tests/fast/selectors/154.html
+/sdcard/android/layout_tests/fast/selectors/090b.html
+/sdcard/android/layout_tests/fast/selectors/089.html
+/sdcard/android/layout_tests/fast/selectors/088b.html
+/sdcard/android/layout_tests/fast/selectors/087b.html
+/sdcard/android/layout_tests/fast/selectors/083.html
+/sdcard/android/layout_tests/fast/selectors/078b.html
+/sdcard/android/layout_tests/fast/selectors/077b.html
+/sdcard/android/layout_tests/fast/selectors/077.html
+/sdcard/android/layout_tests/fast/selectors/072b.html
+/sdcard/android/layout_tests/fast/selectors/072.html
+/sdcard/android/layout_tests/fast/selectors/066b.html
+/sdcard/android/layout_tests/fast/selectors/066.html
+/sdcard/android/layout_tests/fast/selectors/065.html
+/sdcard/android/layout_tests/fast/selectors/064.html
+/sdcard/android/layout_tests/fast/selectors/063.html
+/sdcard/android/layout_tests/fast/selectors/062.html
+/sdcard/android/layout_tests/fast/selectors/061.html
+/sdcard/android/layout_tests/fast/selectors/060.html
+/sdcard/android/layout_tests/fast/selectors/059.html
+/sdcard/android/layout_tests/fast/selectors/058.html
+/sdcard/android/layout_tests/fast/selectors/056.html
+/sdcard/android/layout_tests/fast/selectors/054.html
+/sdcard/android/layout_tests/fast/selectors/046.html
+/sdcard/android/layout_tests/fast/selectors/045c.html
+/sdcard/android/layout_tests/fast/selectors/045b.html
+/sdcard/android/layout_tests/fast/selectors/045.html
+/sdcard/android/layout_tests/fast/selectors/044d.html
+/sdcard/android/layout_tests/fast/selectors/044c.html
+/sdcard/android/layout_tests/fast/selectors/044b.html
+/sdcard/android/layout_tests/fast/selectors/044.html
+/sdcard/android/layout_tests/fast/selectors/043b.html
+/sdcard/android/layout_tests/fast/selectors/043.html
+/sdcard/android/layout_tests/fast/selectors/042.html
+/sdcard/android/layout_tests/fast/selectors/041.html
+/sdcard/android/layout_tests/fast/selectors/040.html
+/sdcard/android/layout_tests/fast/selectors/039b.html
+/sdcard/android/layout_tests/fast/selectors/039.html
+/sdcard/android/layout_tests/fast/selectors/038.html
+/sdcard/android/layout_tests/fast/selectors/034.html
+/sdcard/android/layout_tests/fast/selectors/032.html
+/sdcard/android/layout_tests/fast/selectors/027.html
+/sdcard/android/layout_tests/fast/selectors/021b.html
+/sdcard/android/layout_tests/fast/selectors/021.html
+/sdcard/android/layout_tests/fast/selectors/020.html
+/sdcard/android/layout_tests/fast/selectors/019.html
+/sdcard/android/layout_tests/fast/selectors/018b.html
+/sdcard/android/layout_tests/fast/selectors/018.html
+/sdcard/android/layout_tests/fast/selectors/017.html
+/sdcard/android/layout_tests/fast/selectors/016.html
+/sdcard/android/layout_tests/fast/selectors/015.html
+/sdcard/android/layout_tests/fast/selectors/014.html
+/sdcard/android/layout_tests/fast/selectors/013.html
+/sdcard/android/layout_tests/fast/selectors/012.html
+/sdcard/android/layout_tests/fast/selectors/011.html
+/sdcard/android/layout_tests/fast/selectors/010.html
+/sdcard/android/layout_tests/fast/selectors/009.html
+/sdcard/android/layout_tests/fast/selectors/008.html
+/sdcard/android/layout_tests/fast/selectors/007b.html
+/sdcard/android/layout_tests/fast/selectors/007a.html
+/sdcard/android/layout_tests/fast/selectors/006.html
+/sdcard/android/layout_tests/fast/selectors/005.html
+/sdcard/android/layout_tests/fast/selectors/004.html
+/sdcard/android/layout_tests/fast/selectors/003.html
+/sdcard/android/layout_tests/fast/selectors/002.html
+/sdcard/android/layout_tests/fast/selectors/001.html
+/sdcard/android/layout_tests/fast/runin/001.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textfield.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-textarea.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-searchfield.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-radio.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-menulist.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-image.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-checkbox.html
+/sdcard/android/layout_tests/fast/replaced/width100percent-button.html
+/sdcard/android/layout_tests/fast/replaced/three-selects-break.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect.html
+/sdcard/android/layout_tests/fast/replaced/selection-rect-in-table-cell.html
+/sdcard/android/layout_tests/fast/replaced/replaced-child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking.html
+/sdcard/android/layout_tests/fast/replaced/replaced-breaking-mixture.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block.html
+/sdcard/android/layout_tests/fast/replaced/percent-height-in-anonymous-block-widget.html
+/sdcard/android/layout_tests/fast/replaced/pdf-as-image.html
+/sdcard/android/layout_tests/fast/replaced/object-align-hspace-vspace.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/minwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/minheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/minheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-pxs.html
+/sdcard/android/layout_tests/fast/replaced/maxwidth-percent.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-pxs.html
+/sdcard/android/layout_tests/fast/replaced/maxheight-percent.html
+/sdcard/android/layout_tests/fast/replaced/max-width-percent.html
+/sdcard/android/layout_tests/fast/replaced/inline-box-wrapper-handover.html
+/sdcard/android/layout_tests/fast/replaced/image-tag.html
+/sdcard/android/layout_tests/fast/replaced/image-solid-color-with-alpha.html
+/sdcard/android/layout_tests/fast/replaced/image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/image-resize-width.html
+/sdcard/android/layout_tests/fast/replaced/image-onload.html
+/sdcard/android/layout_tests/fast/replaced/applet-rendering-java-disabled.html
+/sdcard/android/layout_tests/fast/replaced/applet-disabled-positioned.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-width-and-left-and-right.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-with-auto-height-and-top-and-bottom.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-width.html
+/sdcard/android/layout_tests/fast/replaced/absolute-position-percentage-height.html
+/sdcard/android/layout_tests/fast/replaced/absolute-image-sizing.html
+/sdcard/android/layout_tests/fast/replaced/008.html
+/sdcard/android/layout_tests/fast/replaced/007.html
+/sdcard/android/layout_tests/fast/replaced/006.html
+/sdcard/android/layout_tests/fast/replaced/005.html
+/sdcard/android/layout_tests/fast/replaced/004.html
+/sdcard/android/layout_tests/fast/replaced/003.html
+/sdcard/android/layout_tests/fast/replaced/002.html
+/sdcard/android/layout_tests/fast/replaced/001.html
+/sdcard/android/layout_tests/fast/repaint/transform-translate.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow.html
+/sdcard/android/layout_tests/fast/repaint/text-shadow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow.html
+/sdcard/android/layout_tests/fast/repaint/text-selection-rect-in-overflow-2.html
+/sdcard/android/layout_tests/fast/repaint/table-two-pass-layout-overpaint.html
+/sdcard/android/layout_tests/fast/repaint/table-section-repaint.html
+/sdcard/android/layout_tests/fast/repaint/table-section-overflow.html
+/sdcard/android/layout_tests/fast/repaint/table-row.html
+/sdcard/android/layout_tests/fast/repaint/table-outer-border.html
+/sdcard/android/layout_tests/fast/repaint/table-extra-bottom-grow.html
+/sdcard/android/layout_tests/fast/repaint/table-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/table-col-background.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-vertical-overflow.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-move.html
+/sdcard/android/layout_tests/fast/repaint/table-cell-collapsed-border.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-skipped.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-3.html
+/sdcard/android/layout_tests/fast/repaint/subtree-root-clip-2.html
+/sdcard/android/layout_tests/fast/repaint/static-to-positioned.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-vertical.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-vertical.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-strict-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/shadow-multiple-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/selection-gap-overflow-scroll.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-remove.html
+/sdcard/android/layout_tests/fast/repaint/selection-after-delete.html
+/sdcard/android/layout_tests/fast/repaint/repaint-resized-overflow.html
+/sdcard/android/layout_tests/fast/repaint/renderer-destruction-by-invalidateSelection-crash.html
+/sdcard/android/layout_tests/fast/repaint/overflow-scroll-delete.html
+/sdcard/android/layout_tests/fast/repaint/overflow-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/overflow-into-content.html
+/sdcard/android/layout_tests/fast/repaint/overflow-delete-line.html
+/sdcard/android/layout_tests/fast/repaint/overflow-clip-subtree-layout.html
+/sdcard/android/layout_tests/fast/repaint/outline-shrinking.html
+/sdcard/android/layout_tests/fast/repaint/outline-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/outline-inset.html
+/sdcard/android/layout_tests/fast/repaint/make-children-non-inline.html
+/sdcard/android/layout_tests/fast/repaint/list-marker.html
+/sdcard/android/layout_tests/fast/repaint/list-marker-2.html
+/sdcard/android/layout_tests/fast/repaint/lines-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/line-overflow.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-9.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-8.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-7.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-6.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-5.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-4.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-3.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-2.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-10.html
+/sdcard/android/layout_tests/fast/repaint/line-flow-with-floats-1.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-relative.html
+/sdcard/android/layout_tests/fast/repaint/layout-state-only-positioned.html
+/sdcard/android/layout_tests/fast/repaint/layer-visibility.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline.html
+/sdcard/android/layout_tests/fast/repaint/layer-outline-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/layer-hide-when-needs-layout.html
+/sdcard/android/layout_tests/fast/repaint/layer-full-repaint.html
+/sdcard/android/layout_tests/fast/repaint/layer-child-outline.html
+/sdcard/android/layout_tests/fast/repaint/invisible-objects.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position.html
+/sdcard/android/layout_tests/fast/repaint/intermediate-layout-position-clip.html
+/sdcard/android/layout_tests/fast/repaint/inline-outline-repaint.html
+/sdcard/android/layout_tests/fast/repaint/inline-block-overflow.html
+/sdcard/android/layout_tests/fast/repaint/focus-ring.html
+/sdcard/android/layout_tests/fast/repaint/focus-layers.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow.html
+/sdcard/android/layout_tests/fast/repaint/float-overflow-right.html
+/sdcard/android/layout_tests/fast/repaint/float-move-during-layout.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow.html
+/sdcard/android/layout_tests/fast/repaint/flexible-box-overflow-horizontal.html
+/sdcard/android/layout_tests/fast/repaint/fixed.html
+/sdcard/android/layout_tests/fast/repaint/erase-overflow.html
+/sdcard/android/layout_tests/fast/repaint/delete-into-nested-block.html
+/sdcard/android/layout_tests/fast/repaint/control-clip.html
+/sdcard/android/layout_tests/fast/repaint/continuation-after-outline.html
+/sdcard/android/layout_tests/fast/repaint/content-into-overflow.html
+/sdcard/android/layout_tests/fast/repaint/containing-block-position-change.html
+/sdcard/android/layout_tests/fast/repaint/clipped-relative.html
+/sdcard/android/layout_tests/fast/repaint/clip-with-layout-delta.html
+/sdcard/android/layout_tests/fast/repaint/caret-outside-block.html
+/sdcard/android/layout_tests/fast/repaint/button-spurious-layout-hint.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-7235.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6473.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6388.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-6278.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-5699.html
+/sdcard/android/layout_tests/fast/repaint/bugzilla-3509.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-v.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-h.html
+/sdcard/android/layout_tests/fast/repaint/box-shadow-dynamic.html
+/sdcard/android/layout_tests/fast/repaint/border-repaint-glitch.html
+/sdcard/android/layout_tests/fast/repaint/border-radius-repaint.html
+/sdcard/android/layout_tests/fast/repaint/border-fit-lines.html
+/sdcard/android/layout_tests/fast/repaint/body-background-image.html
+/sdcard/android/layout_tests/fast/repaint/backgroundSizeRepaint.html
+/sdcard/android/layout_tests/fast/repaint/4776765.html
+/sdcard/android/layout_tests/fast/repaint/4774354.html
+/sdcard/android/layout_tests/fast/reflections/table-cell.html
+/sdcard/android/layout_tests/fast/reflections/reflection-nesting.html
+/sdcard/android/layout_tests/fast/reflections/reflection-direction.html
+/sdcard/android/layout_tests/fast/reflections/inline-crash.html
+/sdcard/android/layout_tests/fast/parser/title-error-test.html
+/sdcard/android/layout_tests/fast/parser/style-script-head-test.html
+/sdcard/android/layout_tests/fast/parser/parseCommentsInTitles.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/fonts.html
+/sdcard/android/layout_tests/fast/parser/external-entities-in-xslt.xml
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-textarea.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/document-write-option.html
+/sdcard/android/layout_tests/fast/parser/comments.html
+/sdcard/android/layout_tests/fast/parser/comment-in-style.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script.html
+/sdcard/android/layout_tests/fast/parser/broken-comments-vs-parsing-mode.html
+/sdcard/android/layout_tests/fast/parser/bad-xml-slash.html
+/sdcard/android/layout_tests/fast/parser/001.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-overflow-rtl-bug.html
+/sdcard/android/layout_tests/fast/overflow/unreachable-content-test.html
+/sdcard/android/layout_tests/fast/overflow/table-overflow-float.html
+/sdcard/android/layout_tests/fast/overflow/scrollRevealButton.html
+/sdcard/android/layout_tests/fast/overflow/scrollbar-position-update.html
+/sdcard/android/layout_tests/fast/overflow/scroll-nested-positioned-layer-in-overflow.html
+/sdcard/android/layout_tests/fast/overflow/position-relative.html
+/sdcard/android/layout_tests/fast/overflow/overflow_hidden.html
+/sdcard/android/layout_tests/fast/overflow/overflow-x-y.html
+/sdcard/android/layout_tests/fast/overflow/overflow-text-hit-testing.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl.html
+/sdcard/android/layout_tests/fast/overflow/overflow-rtl-inline-scrollbar.html
+/sdcard/android/layout_tests/fast/overflow/overflow-focus-ring.html
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-table.html
+/sdcard/android/layout_tests/fast/overflow/overflow-auto-position-absolute.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursionGuard.html
+/sdcard/android/layout_tests/fast/overflow/infiniteRecursion.html
+/sdcard/android/layout_tests/fast/overflow/image-selection-highlight.html
+/sdcard/android/layout_tests/fast/overflow/hit-test-overflow-controls.html
+/sdcard/android/layout_tests/fast/overflow/hidden-scrollbar-resize.html
+/sdcard/android/layout_tests/fast/overflow/float-in-relpositioned.html
+/sdcard/android/layout_tests/fast/overflow/dynamic-hidden.html
+/sdcard/android/layout_tests/fast/overflow/clip-rects-fixed-ancestor.html
+/sdcard/android/layout_tests/fast/overflow/childFocusRingClip.html
+/sdcard/android/layout_tests/fast/overflow/008.html
+/sdcard/android/layout_tests/fast/overflow/007.html
+/sdcard/android/layout_tests/fast/overflow/006.html
+/sdcard/android/layout_tests/fast/overflow/005.html
+/sdcard/android/layout_tests/fast/overflow/004.html
+/sdcard/android/layout_tests/fast/overflow/003.xml
+/sdcard/android/layout_tests/fast/overflow/002.html
+/sdcard/android/layout_tests/fast/overflow/001.html
+/sdcard/android/layout_tests/fast/multicol/zeroColumnCount.html
+/sdcard/android/layout_tests/fast/multicol/negativeColumnWidth.html
+/sdcard/android/layout_tests/fast/multicol/float-multicol.html
+/sdcard/android/layout_tests/fast/multicol/float-avoidance.html
+/sdcard/android/layout_tests/fast/multicol/columns-shorthand-parsing.html
+/sdcard/android/layout_tests/fast/multicol/column-rules.html
+/sdcard/android/layout_tests/fast/media/viewport-media-query.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-04.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-03.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-02.html
+/sdcard/android/layout_tests/fast/media/mq-width-absolute-01.html
+/sdcard/android/layout_tests/fast/media/mq-valueless.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-simple-neg-query-01.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-09.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-08.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-07.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-06.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-05.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-04.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-03.html
+/sdcard/android/layout_tests/fast/media/mq-relative-constraints-02.html
+/sdcard/android/layout_tests/fast/media/mq-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-min-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-min-constraint.html
+/sdcard/android/layout_tests/fast/media/mq-max-pixel-ratio.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-04.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-stylesheet-media-01.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-forward-syntax.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-03.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-02.html
+/sdcard/android/layout_tests/fast/media/mq-js-media-except-01.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-05.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-04.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-syntax-01.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-04.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-03.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-02.html
+/sdcard/android/layout_tests/fast/media/mq-invalid-media-feature-01.html
+/sdcard/android/layout_tests/fast/media/mq-grid-02.html
+/sdcard/android/layout_tests/fast/media/mq-grid-01.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-05.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-04.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-03.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-02.html
+/sdcard/android/layout_tests/fast/media/mq-compound-query-01.html
+/sdcard/android/layout_tests/fast/media/monochrome.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-02.html
+/sdcard/android/layout_tests/fast/media/media-type-syntax-01.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-06.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-05.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-04.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-03.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-02.html
+/sdcard/android/layout_tests/fast/media/media-descriptor-syntax-01.html
+/sdcard/android/layout_tests/fast/media/implicit-media-all.html
+/sdcard/android/layout_tests/fast/loader/text-document-wrapping.html
+/sdcard/android/layout_tests/fast/loader/start-load-in-unload.html
+/sdcard/android/layout_tests/fast/lists/w3-list-styles.html
+/sdcard/android/layout_tests/fast/lists/scrolled-marker-paint.html
+/sdcard/android/layout_tests/fast/lists/ordered-list-with-no-ol-tag.html
+/sdcard/android/layout_tests/fast/lists/olstart.html
+/sdcard/android/layout_tests/fast/lists/ol-start-dynamic.html
+/sdcard/android/layout_tests/fast/lists/ol-display-types.html
+/sdcard/android/layout_tests/fast/lists/numeric-markers-outside-list.html
+/sdcard/android/layout_tests/fast/lists/markers-in-selection.html
+/sdcard/android/layout_tests/fast/lists/marker-image-error.html
+/sdcard/android/layout_tests/fast/lists/marker-before-empty-inline.html
+/sdcard/android/layout_tests/fast/lists/list-style-type-dynamic-change.html
+/sdcard/android/layout_tests/fast/lists/list-style-none-crash.html
+/sdcard/android/layout_tests/fast/lists/list-item-line-height.html
+/sdcard/android/layout_tests/fast/lists/li-values.html
+/sdcard/android/layout_tests/fast/lists/li-style-alpha-huge-value-crash.html
+/sdcard/android/layout_tests/fast/lists/li-br.html
+/sdcard/android/layout_tests/fast/lists/item-not-in-list-line-wrapping.html
+/sdcard/android/layout_tests/fast/lists/inlineBoxWrapperNullCheck.html
+/sdcard/android/layout_tests/fast/lists/dynamic-marker-crash.html
+/sdcard/android/layout_tests/fast/lists/drag-into-marker.html
+/sdcard/android/layout_tests/fast/lists/decimal-leading-zero.html
+/sdcard/android/layout_tests/fast/lists/big-list-marker.html
+/sdcard/android/layout_tests/fast/lists/alpha-list-wrap.html
+/sdcard/android/layout_tests/fast/lists/009.html
+/sdcard/android/layout_tests/fast/lists/008.html
+/sdcard/android/layout_tests/fast/lists/007.html
+/sdcard/android/layout_tests/fast/lists/006.html
+/sdcard/android/layout_tests/fast/lists/005.html
+/sdcard/android/layout_tests/fast/lists/004.html
+/sdcard/android/layout_tests/fast/lists/003.html
+/sdcard/android/layout_tests/fast/lists/002.html
+/sdcard/android/layout_tests/fast/lists/001.html
+/sdcard/android/layout_tests/fast/layers/zindex-ridonkulous.html
+/sdcard/android/layout_tests/fast/layers/zindex-inherit.html
+/sdcard/android/layout_tests/fast/layers/scroll-rect-to-visible.html
+/sdcard/android/layout_tests/fast/layers/remove-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/layers/positioned-inside-root-with-margins.html
+/sdcard/android/layout_tests/fast/layers/overflow-scroll-auto-switch.html
+/sdcard/android/layout_tests/fast/layers/opacity-stacking.html
+/sdcard/android/layout_tests/fast/layers/opacity-outline.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility.html
+/sdcard/android/layout_tests/fast/layers/layer-visibility-sublayer.html
+/sdcard/android/layout_tests/fast/layers/layer-content-visibility-change.html
+/sdcard/android/layout_tests/fast/layers/add-layer-with-nested-stacking.html
+/sdcard/android/layout_tests/fast/js/missing-style-end-tag-js.html
+/sdcard/android/layout_tests/fast/invalid/td-inside-object.html
+/sdcard/android/layout_tests/fast/invalid/table-residual-style-crash.html
+/sdcard/android/layout_tests/fast/invalid/table-inside-stray-table-content.html
+/sdcard/android/layout_tests/fast/invalid/residual-style.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s.html
+/sdcard/android/layout_tests/fast/invalid/missing-font-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-dt-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-dl-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/missing-address-end-tag.html
+/sdcard/android/layout_tests/fast/invalid/junk-data.xml
+/sdcard/android/layout_tests/fast/invalid/021.html
+/sdcard/android/layout_tests/fast/invalid/020.xml
+/sdcard/android/layout_tests/fast/invalid/019.html
+/sdcard/android/layout_tests/fast/invalid/018.html
+/sdcard/android/layout_tests/fast/invalid/017.html
+/sdcard/android/layout_tests/fast/invalid/016.html
+/sdcard/android/layout_tests/fast/invalid/015.html
+/sdcard/android/layout_tests/fast/invalid/014.html
+/sdcard/android/layout_tests/fast/invalid/013.html
+/sdcard/android/layout_tests/fast/invalid/012.html
+/sdcard/android/layout_tests/fast/invalid/011.html
+/sdcard/android/layout_tests/fast/invalid/010.html
+/sdcard/android/layout_tests/fast/invalid/009.html
+/sdcard/android/layout_tests/fast/invalid/008.html
+/sdcard/android/layout_tests/fast/invalid/007.html
+/sdcard/android/layout_tests/fast/invalid/006.html
+/sdcard/android/layout_tests/fast/invalid/005.html
+/sdcard/android/layout_tests/fast/invalid/004.html
+/sdcard/android/layout_tests/fast/invalid/003.html
+/sdcard/android/layout_tests/fast/invalid/002.html
+/sdcard/android/layout_tests/fast/invalid/001.html
+/sdcard/android/layout_tests/fast/inspector/style.html
+/sdcard/android/layout_tests/fast/inspector/matchedrules.html
+/sdcard/android/layout_tests/fast/innerHTML/006.html
+/sdcard/android/layout_tests/fast/innerHTML/003.html
+/sdcard/android/layout_tests/fast/innerHTML/002.html
+/sdcard/android/layout_tests/fast/innerHTML/001.html
+/sdcard/android/layout_tests/fast/inline-block/tricky-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/overflow-clip.html
+/sdcard/android/layout_tests/fast/inline-block/inline-block-vertical-align.html
+/sdcard/android/layout_tests/fast/inline-block/contenteditable-baseline.html
+/sdcard/android/layout_tests/fast/inline-block/14498-positionForCoordinates.html
+/sdcard/android/layout_tests/fast/inline-block/006.html
+/sdcard/android/layout_tests/fast/inline-block/005.html
+/sdcard/android/layout_tests/fast/inline-block/004.html
+/sdcard/android/layout_tests/fast/inline-block/003.html
+/sdcard/android/layout_tests/fast/inline-block/002.html
+/sdcard/android/layout_tests/fast/inline-block/001.html
+/sdcard/android/layout_tests/fast/inline/styledEmptyInlinesWithBRs.html
+/sdcard/android/layout_tests/fast/inline/positionedLifetime.html
+/sdcard/android/layout_tests/fast/inline/percentage-margins.html
+/sdcard/android/layout_tests/fast/inline/outline-continuations.html
+/sdcard/android/layout_tests/fast/inline/inline-text-quirk-bpm.html
+/sdcard/android/layout_tests/fast/inline/inline-padding-disables-text-quirk.html
+/sdcard/android/layout_tests/fast/inline/inline-borders-with-bidi-override.html
+/sdcard/android/layout_tests/fast/inline/emptyInlinesWithinLists.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlinesWithWS.html
+/sdcard/android/layout_tests/fast/inline/drawStyledEmptyInlines.html
+/sdcard/android/layout_tests/fast/inline/dirtyLinesForInline.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines.html
+/sdcard/android/layout_tests/fast/inline/continuation-outlines-with-layers.html
+/sdcard/android/layout_tests/fast/inline/002.html
+/sdcard/android/layout_tests/fast/inline/001.html
+/sdcard/android/layout_tests/fast/images/svg-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/svg-as-relative-image.html
+/sdcard/android/layout_tests/fast/images/svg-as-image.html
+/sdcard/android/layout_tests/fast/images/svg-as-background.html
+/sdcard/android/layout_tests/fast/images/pdf-as-tiled-background.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image.html
+/sdcard/android/layout_tests/fast/images/pdf-as-image-landscape.html
+/sdcard/android/layout_tests/fast/images/pdf-as-background.html
+/sdcard/android/layout_tests/fast/images/object-image.html
+/sdcard/android/layout_tests/fast/images/image-map-anchor-children.html
+/sdcard/android/layout_tests/fast/images/image-in-map.html
+/sdcard/android/layout_tests/fast/images/favicon-as-image.html
+/sdcard/android/layout_tests/fast/images/embed-image.html
+/sdcard/android/layout_tests/fast/images/animated-gif-with-offsets.html
+/sdcard/android/layout_tests/fast/html/marquee-scroll.html
+/sdcard/android/layout_tests/fast/html/listing.html
+/sdcard/android/layout_tests/fast/html/link-rel-stylesheet.html
+/sdcard/android/layout_tests/fast/html/keygen.html
+/sdcard/android/layout_tests/fast/history/history_reload.html
+/sdcard/android/layout_tests/fast/history/clicked-link-is-visited.html
+/sdcard/android/layout_tests/fast/frames/viewsource-attribute.html
+/sdcard/android/layout_tests/fast/frames/valid.html
+/sdcard/android/layout_tests/fast/frames/onlyCommentInIFrame.html
+/sdcard/android/layout_tests/fast/frames/no-frame-borders.html
+/sdcard/android/layout_tests/fast/frames/invalid.html
+/sdcard/android/layout_tests/fast/frames/inline-object-inside-frameset.html
+/sdcard/android/layout_tests/fast/frames/iframe-with-frameborder.html
+/sdcard/android/layout_tests/fast/frames/iframe-text-contents.html
+/sdcard/android/layout_tests/fast/frames/iframe-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/frameset-style-recalc.html
+/sdcard/android/layout_tests/fast/frames/frameElement-iframe.html
+/sdcard/android/layout_tests/fast/frames/frameElement-frame.html
+/sdcard/android/layout_tests/fast/frames/frame-src-attribute.html
+/sdcard/android/layout_tests/fast/frames/frame-set-whitespace-attributes.html
+/sdcard/android/layout_tests/fast/frames/frame-scrolling-attribute.html
+/sdcard/android/layout_tests/fast/frames/frame-navigation.html
+/sdcard/android/layout_tests/fast/frames/frame-length-fractional.html
+/sdcard/android/layout_tests/fast/frames/frame-element-name.html
+/sdcard/android/layout_tests/fast/frames/empty-cols-attribute.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_iFrame.html
+/sdcard/android/layout_tests/fast/frames/contentWindow_Frame.html
+/sdcard/android/layout_tests/fast/frames/calculate-round.html
+/sdcard/android/layout_tests/fast/frames/calculate-relative.html
+/sdcard/android/layout_tests/fast/frames/calculate-percentage.html
+/sdcard/android/layout_tests/fast/frames/calculate-order.html
+/sdcard/android/layout_tests/fast/frames/calculate-fixed.html
+/sdcard/android/layout_tests/fast/frames/002.html
+/sdcard/android/layout_tests/fast/frames/001.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-no-parent-slider.html
+/sdcard/android/layout_tests/fast/forms/thumbslider-crash.html
+/sdcard/android/layout_tests/fast/forms/textfield-outline.html
+/sdcard/android/layout_tests/fast/forms/textfield-drag-into-disabled.html
+/sdcard/android/layout_tests/fast/forms/textAreaLineHeight.html
+/sdcard/android/layout_tests/fast/forms/textarea-width.html
+/sdcard/android/layout_tests/fast/forms/textarea-setinnerhtml.html
+/sdcard/android/layout_tests/fast/forms/textarea-scrolled-type.html
+/sdcard/android/layout_tests/fast/forms/textarea-rows-cols.html
+/sdcard/android/layout_tests/fast/forms/slider-thumb-shared-style.html
+/sdcard/android/layout_tests/fast/forms/slider-padding.html
+/sdcard/android/layout_tests/fast/forms/select-writing-direction-natural.html
+/sdcard/android/layout_tests/fast/forms/select-size.html
+/sdcard/android/layout_tests/fast/forms/select-selected.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-with-height.html
+/sdcard/android/layout_tests/fast/forms/select-initial-position.html
+/sdcard/android/layout_tests/fast/forms/select-display-none-style-resolve.html
+/sdcard/android/layout_tests/fast/forms/select-disabled-appearance.html
+/sdcard/android/layout_tests/fast/forms/select-change-popup-to-listbox.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-to-popup.html
+/sdcard/android/layout_tests/fast/forms/select-change-listbox-size.html
+/sdcard/android/layout_tests/fast/forms/select-block-background.html
+/sdcard/android/layout_tests/fast/forms/select-baseline.html
+/sdcard/android/layout_tests/fast/forms/select-align.html
+/sdcard/android/layout_tests/fast/forms/search-placeholder-value-changed.html
+/sdcard/android/layout_tests/fast/forms/search-display-none-cancel-button.html
+/sdcard/android/layout_tests/fast/forms/radio_checked_dynamic.html
+/sdcard/android/layout_tests/fast/forms/radio_checked.html
+/sdcard/android/layout_tests/fast/forms/radio-nested-labels.html
+/sdcard/android/layout_tests/fast/forms/radio-attr-order.html
+/sdcard/android/layout_tests/fast/forms/preserveFormDuringResidualStyle.html
+/sdcard/android/layout_tests/fast/forms/plaintext-mode-2.html
+/sdcard/android/layout_tests/fast/forms/placeholder-set-attribute.html
+/sdcard/android/layout_tests/fast/forms/placeholder-pseudo-style.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder.html
+/sdcard/android/layout_tests/fast/forms/password-placeholder-text-security.html
+/sdcard/android/layout_tests/fast/forms/option-text-clip.html
+/sdcard/android/layout_tests/fast/forms/option-strip-whitespace.html
+/sdcard/android/layout_tests/fast/forms/option-script.html
+/sdcard/android/layout_tests/fast/forms/option-index.html
+/sdcard/android/layout_tests/fast/forms/negativeLineHeight.html
+/sdcard/android/layout_tests/fast/forms/minWidthPercent.html
+/sdcard/android/layout_tests/fast/forms/menulist-width-change.html
+/sdcard/android/layout_tests/fast/forms/menulist-separator-painting.html
+/sdcard/android/layout_tests/fast/forms/menulist-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/menulist-option-wrap.html
+/sdcard/android/layout_tests/fast/forms/menulist-no-overflow.html
+/sdcard/android/layout_tests/fast/forms/menulist-narrow-width.html
+/sdcard/android/layout_tests/fast/forms/menulist-deselect-update.html
+/sdcard/android/layout_tests/fast/forms/menulist-clip.html
+/sdcard/android/layout_tests/fast/forms/listbox-width-change.html
+/sdcard/android/layout_tests/fast/forms/listbox-selection-2.html
+/sdcard/android/layout_tests/fast/forms/listbox-scrollbar-incremental-load.html
+/sdcard/android/layout_tests/fast/forms/listbox-deselect-scroll.html
+/sdcard/android/layout_tests/fast/forms/listbox-clip.html
+/sdcard/android/layout_tests/fast/forms/input-width.html
+/sdcard/android/layout_tests/fast/forms/input-value.html
+/sdcard/android/layout_tests/fast/forms/input-type-text-min-width.html
+/sdcard/android/layout_tests/fast/forms/input-type-change2.html
+/sdcard/android/layout_tests/fast/forms/input-type-change.html
+/sdcard/android/layout_tests/fast/forms/input-text-word-wrap.html
+/sdcard/android/layout_tests/fast/forms/input-text-self-emptying-click.html
+/sdcard/android/layout_tests/fast/forms/input-text-scroll-left-on-blur.html
+/sdcard/android/layout_tests/fast/forms/input-text-paste-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-text-option-delete.html
+/sdcard/android/layout_tests/fast/forms/input-text-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-text-drag-down.html
+/sdcard/android/layout_tests/fast/forms/input-text-double-click.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-outside.html
+/sdcard/android/layout_tests/fast/forms/input-text-click-inside.html
+/sdcard/android/layout_tests/fast/forms/input-table.html
+/sdcard/android/layout_tests/fast/forms/input-spaces.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-empty.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-dimmed.html
+/sdcard/android/layout_tests/fast/forms/input-readonly-autoscroll.html
+/sdcard/android/layout_tests/fast/forms/input-paste-undo.html
+/sdcard/android/layout_tests/fast/forms/input-no-renderer.html
+/sdcard/android/layout_tests/fast/forms/input-field-text-truncated.html
+/sdcard/android/layout_tests/fast/forms/input-double-click-selection-gap-bug.html
+/sdcard/android/layout_tests/fast/forms/input-disabled-color.html
+/sdcard/android/layout_tests/fast/forms/input-baseline.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-width.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-visibility.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-selection.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-readonly.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-preventDefault.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-height.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-focus.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-default-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-bkcolor.html
+/sdcard/android/layout_tests/fast/forms/input-align.html
+/sdcard/android/layout_tests/fast/forms/input-align-image.html
+/sdcard/android/layout_tests/fast/forms/indeterminate.html
+/sdcard/android/layout_tests/fast/forms/image-border.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label07.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label06.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label05.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label04.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label03.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label02.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_label01.html
+/sdcard/android/layout_tests/fast/forms/hidden-listbox.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-file.html
+/sdcard/android/layout_tests/fast/forms/formmove3.html
+/sdcard/android/layout_tests/fast/forms/formmove2.html
+/sdcard/android/layout_tests/fast/forms/formmove.html
+/sdcard/android/layout_tests/fast/forms/form-hides-table.html
+/sdcard/android/layout_tests/fast/forms/float-before-fieldset.html
+/sdcard/android/layout_tests/fast/forms/file-input-disabled.html
+/sdcard/android/layout_tests/fast/forms/file-input-direction.html
+/sdcard/android/layout_tests/fast/forms/fieldset-with-float.html
+/sdcard/android/layout_tests/fast/forms/fieldset-align.html
+/sdcard/android/layout_tests/fast/forms/dragging-to-file-input.html
+/sdcard/android/layout_tests/fast/forms/dragging-to-disabled-file-input.html
+/sdcard/android/layout_tests/fast/forms/disabled-select-change-index.html
+/sdcard/android/layout_tests/fast/forms/control-restrict-line-height.html
+/sdcard/android/layout_tests/fast/forms/control-clip.html
+/sdcard/android/layout_tests/fast/forms/control-clip-overflow.html
+/sdcard/android/layout_tests/fast/forms/checkbox-radio-onchange.html
+/sdcard/android/layout_tests/fast/forms/button-white-space.html
+/sdcard/android/layout_tests/fast/forms/button-text-transform.html
+/sdcard/android/layout_tests/fast/forms/button-table-styles.html
+/sdcard/android/layout_tests/fast/forms/button-submit.html
+/sdcard/android/layout_tests/fast/forms/button-sizes.html
+/sdcard/android/layout_tests/fast/forms/button-positioned.html
+/sdcard/android/layout_tests/fast/forms/button-inner-block-reuse.html
+/sdcard/android/layout_tests/fast/forms/button-generated-content.html
+/sdcard/android/layout_tests/fast/forms/button-default-title.html
+/sdcard/android/layout_tests/fast/forms/button-cannot-be-nested.html
+/sdcard/android/layout_tests/fast/forms/button-align.html
+/sdcard/android/layout_tests/fast/forms/box-shadow-override.html
+/sdcard/android/layout_tests/fast/forms/blankbuttons.html
+/sdcard/android/layout_tests/fast/forms/006.html
+/sdcard/android/layout_tests/fast/forms/005.html
+/sdcard/android/layout_tests/fast/forms/004.html
+/sdcard/android/layout_tests/fast/forms/003.html
+/sdcard/android/layout_tests/fast/forms/002.html
+/sdcard/android/layout_tests/fast/forms/001.html
+/sdcard/android/layout_tests/fast/flexbox/flex-hang.html
+/sdcard/android/layout_tests/fast/flexbox/026.html
+/sdcard/android/layout_tests/fast/flexbox/025.html
+/sdcard/android/layout_tests/fast/flexbox/024.html
+/sdcard/android/layout_tests/fast/flexbox/023.html
+/sdcard/android/layout_tests/fast/flexbox/022.html
+/sdcard/android/layout_tests/fast/flexbox/021.html
+/sdcard/android/layout_tests/fast/flexbox/020.html
+/sdcard/android/layout_tests/fast/flexbox/019.html
+/sdcard/android/layout_tests/fast/flexbox/018.html
+/sdcard/android/layout_tests/fast/flexbox/017.html
+/sdcard/android/layout_tests/fast/flexbox/016.html
+/sdcard/android/layout_tests/fast/flexbox/015.html
+/sdcard/android/layout_tests/fast/flexbox/014.html
+/sdcard/android/layout_tests/fast/flexbox/013.html
+/sdcard/android/layout_tests/fast/flexbox/012.html
+/sdcard/android/layout_tests/fast/flexbox/011.html
+/sdcard/android/layout_tests/fast/flexbox/010.html
+/sdcard/android/layout_tests/fast/flexbox/009.html
+/sdcard/android/layout_tests/fast/flexbox/008.html
+/sdcard/android/layout_tests/fast/flexbox/007.html
+/sdcard/android/layout_tests/fast/flexbox/006.html
+/sdcard/android/layout_tests/fast/flexbox/005.html
+/sdcard/android/layout_tests/fast/flexbox/004.html
+/sdcard/android/layout_tests/fast/flexbox/003.html
+/sdcard/android/layout_tests/fast/flexbox/002.html
+/sdcard/android/layout_tests/fast/flexbox/001.html
+/sdcard/android/layout_tests/fast/events/updateLayoutForHitTest.html
+/sdcard/android/layout_tests/fast/events/standalone-image-drag-to-editable.html
+/sdcard/android/layout_tests/fast/events/reveal-link-when-focused.html
+/sdcard/android/layout_tests/fast/events/onloadFrameCrash.html
+/sdcard/android/layout_tests/fast/events/onload-re-entry.html
+/sdcard/android/layout_tests/fast/events/mouseout-dead-node.html
+/sdcard/android/layout_tests/fast/events/label-focus.html
+/sdcard/android/layout_tests/fast/events/keydown-1.html
+/sdcard/android/layout_tests/fast/events/focusingUnloadedFrame.html
+/sdcard/android/layout_tests/fast/events/event-sender-mouse-moved.html
+/sdcard/android/layout_tests/fast/events/event-listener-on-link.html
+/sdcard/android/layout_tests/fast/events/context-onmousedown-event.html
+/sdcard/android/layout_tests/fast/events/autoscroll.html
+/sdcard/android/layout_tests/fast/events/attempt-scroll-with-no-scrollbars.html
+/sdcard/android/layout_tests/fast/events/5056619.html
+/sdcard/android/layout_tests/fast/encoding/xmacroman-encoding-test.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-no-bom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-16-little-endian.html
+/sdcard/android/layout_tests/fast/encoding/utf-16-big-endian.html
+/sdcard/android/layout_tests/fast/encoding/invalid-UTF-8.html
+/sdcard/android/layout_tests/fast/encoding/denormalised-voiced-japanese-chars.html
+/sdcard/android/layout_tests/fast/dynamic/view-overflow.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-table-cell-height.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-parent-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-no-common-root-static-y.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-boundary-percent-height.html
+/sdcard/android/layout_tests/fast/dynamic/staticY.html
+/sdcard/android/layout_tests/fast/dynamic/staticY-marking-parents-regression.html
+/sdcard/android/layout_tests/fast/dynamic/selection-highlight-adjust.html
+/sdcard/android/layout_tests/fast/dynamic/positioned-movement-with-positioned-children.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-img.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-doc.html
+/sdcard/android/layout_tests/fast/dynamic/noninlinebadness.html
+/sdcard/android/layout_tests/fast/dynamic/move-node-with-selection.html
+/sdcard/android/layout_tests/fast/dynamic/link-href-change.html
+/sdcard/android/layout_tests/fast/dynamic/layer-hit-test-crash.html
+/sdcard/android/layout_tests/fast/dynamic/insert-before-table-part-in-continuation.html
+/sdcard/android/layout_tests/fast/dynamic/genContentDestroyChildren.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned.html
+/sdcard/android/layout_tests/fast/dynamic/floating-to-positioned-2.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal.html
+/sdcard/android/layout_tests/fast/dynamic/float-withdrawal-2.html
+/sdcard/android/layout_tests/fast/dynamic/float-no-longer-overhanging.html
+/sdcard/android/layout_tests/fast/dynamic/float-in-trailing-whitespace-after-last-line-break.html
+/sdcard/android/layout_tests/fast/dynamic/flash-replacement-test.html
+/sdcard/android/layout_tests/fast/dynamic/create-renderer-for-whitespace-only-text.html
+/sdcard/android/layout_tests/fast/dynamic/containing-block-change.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-orphaned-lines.html
+/sdcard/android/layout_tests/fast/dynamic/anonymous-block-layer-lost.html
+/sdcard/android/layout_tests/fast/dynamic/015.html
+/sdcard/android/layout_tests/fast/dynamic/014.html
+/sdcard/android/layout_tests/fast/dynamic/013.html
+/sdcard/android/layout_tests/fast/dynamic/012.html
+/sdcard/android/layout_tests/fast/dynamic/011.html
+/sdcard/android/layout_tests/fast/dynamic/010.html
+/sdcard/android/layout_tests/fast/dynamic/009.html
+/sdcard/android/layout_tests/fast/dynamic/008.html
+/sdcard/android/layout_tests/fast/dynamic/007.html
+/sdcard/android/layout_tests/fast/dynamic/006.html
+/sdcard/android/layout_tests/fast/dynamic/005.html
+/sdcard/android/layout_tests/fast/dynamic/004.html
+/sdcard/android/layout_tests/fast/dynamic/002.html
+/sdcard/android/layout_tests/fast/dynamic/001.html
+/sdcard/android/layout_tests/fast/dom/Window/open-existing-pop-up-blocking.html
+/sdcard/android/layout_tests/fast/dom/Window/btoa-pnglet.html
+/sdcard/android/layout_tests/fast/dom/Range/surroundContents-1.html
+/sdcard/android/layout_tests/fast/dom/Range/create-contextual-fragment.html
+/sdcard/android/layout_tests/fast/dom/HTMLTextAreaElement/reset-textarea.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/createCaption.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/colSpan.html
+/sdcard/android/layout_tests/fast/dom/HTMLStyleElement/insert-parser-generated.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/vspace-hspace-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead5.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead4.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead3.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead2.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/textInHead1.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-link-style-href-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/bdo.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/frameless-location-bugzilla10837.html
+/sdcard/android/layout_tests/fast/dom/Element/null-offset-parent.html
+/sdcard/android/layout_tests/fast/dom/Document/early-document-access.html
+/sdcard/android/layout_tests/fast/dom/row-inner-text.html
+/sdcard/android/layout_tests/fast/dom/replaceChild.html
+/sdcard/android/layout_tests/fast/dom/outerText.html
+/sdcard/android/layout_tests/fast/dom/isindex-002.html
+/sdcard/android/layout_tests/fast/dom/isindex-001.html
+/sdcard/android/layout_tests/fast/dom/focus-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/dom-parse-serialize-display.html
+/sdcard/android/layout_tests/fast/dom/delete-contents.html
+/sdcard/android/layout_tests/fast/dom/css-rule-functions.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-insertRule-update.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-deleteRule-update.html
+/sdcard/android/layout_tests/fast/dom/css-inline-style-important.html
+/sdcard/android/layout_tests/fast/dom/css-cached-import-rule.html
+/sdcard/android/layout_tests/fast/dom/clone-node-dynamic-style.html
+/sdcard/android/layout_tests/fast/dom/clone-contents-0-end-offset.html
+/sdcard/android/layout_tests/fast/dom/clientWidthAfterDocumentIsRemoved.html
+/sdcard/android/layout_tests/fast/dom/children-nodes.html
+/sdcard/android/layout_tests/fast/dom/blur-contenteditable.html
+/sdcard/android/layout_tests/fast/dom/attr_dead_doc.html
+/sdcard/android/layout_tests/fast/doctypes/004.html
+/sdcard/android/layout_tests/fast/doctypes/003.html
+/sdcard/android/layout_tests/fast/doctypes/002.html
+/sdcard/android/layout_tests/fast/doctypes/001.html
+/sdcard/android/layout_tests/fast/css-generated-content/wbr-with-before-content.html
+/sdcard/android/layout_tests/fast/css-generated-content/visibleContentHiddenParent.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-with-before.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-row-group-to-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/table-cell-before-content.html
+/sdcard/android/layout_tests/fast/css-generated-content/spellingToolTip-assert.html
+/sdcard/android/layout_tests/fast/css-generated-content/positioned-background-hit-test-crash.html
+/sdcard/android/layout_tests/fast/css-generated-content/no-openclose-quote.html
+/sdcard/android/layout_tests/fast/css-generated-content/inline-display-types.html
+/sdcard/android/layout_tests/fast/css-generated-content/hover-style-change.html
+/sdcard/android/layout_tests/fast/css-generated-content/before-with-first-letter.html
+/sdcard/android/layout_tests/fast/css-generated-content/after-order.html
+/sdcard/android/layout_tests/fast/css-generated-content/absolute-position-inside-inline.html
+/sdcard/android/layout_tests/fast/css-generated-content/016.html
+/sdcard/android/layout_tests/fast/css-generated-content/015.html
+/sdcard/android/layout_tests/fast/css-generated-content/014.html
+/sdcard/android/layout_tests/fast/css-generated-content/013.html
+/sdcard/android/layout_tests/fast/css-generated-content/012.html
+/sdcard/android/layout_tests/fast/css-generated-content/011.html
+/sdcard/android/layout_tests/fast/css-generated-content/010.html
+/sdcard/android/layout_tests/fast/css-generated-content/009.html
+/sdcard/android/layout_tests/fast/css-generated-content/008.html
+/sdcard/android/layout_tests/fast/css-generated-content/007.html
+/sdcard/android/layout_tests/fast/css-generated-content/005.html
+/sdcard/android/layout_tests/fast/css-generated-content/004.html
+/sdcard/android/layout_tests/fast/css-generated-content/003.html
+/sdcard/android/layout_tests/fast/css-generated-content/002.html
+/sdcard/android/layout_tests/fast/css-generated-content/001.html
+/sdcard/android/layout_tests/fast/css/variables/variable-iteration-test.html
+/sdcard/android/layout_tests/fast/css/variables/shorthand-test.html
+/sdcard/android/layout_tests/fast/css/variables/set-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/remove-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/print-test.html
+/sdcard/android/layout_tests/fast/css/variables/override-test.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-term-test.html
+/sdcard/android/layout_tests/fast/css/variables/multiple-blocks-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-variables-test.html
+/sdcard/android/layout_tests/fast/css/variables/misplaced-import-test.html
+/sdcard/android/layout_tests/fast/css/variables/margin-test.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-variable-test.html
+/sdcard/android/layout_tests/fast/css/variables/inline-style-test.html
+/sdcard/android/layout_tests/fast/css/variables/import-test.html
+/sdcard/android/layout_tests/fast/css/variables/image-test.html
+/sdcard/android/layout_tests/fast/css/variables/font-test.html
+/sdcard/android/layout_tests/fast/css/variables/declaration-block-test.html
+/sdcard/android/layout_tests/fast/css/variables/colors-test.html
+/sdcard/android/layout_tests/fast/css/variables/block-cycle-test.html
+/sdcard/android/layout_tests/fast/css/namespaces/007.xml
+/sdcard/android/layout_tests/fast/css/namespaces/006.xml
+/sdcard/android/layout_tests/fast/css/namespaces/005.xml
+/sdcard/android/layout_tests/fast/css/namespaces/004.xml
+/sdcard/android/layout_tests/fast/css/namespaces/003.xml
+/sdcard/android/layout_tests/fast/css/namespaces/002.xml
+/sdcard/android/layout_tests/fast/css/namespaces/001.xml
+/sdcard/android/layout_tests/fast/css/counters/invalidate-cached-counter-node.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-transform.html
+/sdcard/android/layout_tests/fast/css/counters/counter-text-security.html
+/sdcard/android/layout_tests/fast/css/zoom-property-parsing.html
+/sdcard/android/layout_tests/fast/css/zoom-font-size.html
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers2.html
+/sdcard/android/layout_tests/fast/css/ZeroOpacityLayers.html
+/sdcard/android/layout_tests/fast/css/xml-stylesheet-pi-not-in-prolog.xml
+/sdcard/android/layout_tests/fast/css/word-space-extra.html
+/sdcard/android/layout_tests/fast/css/visibility-hit-test.html
+/sdcard/android/layout_tests/fast/css/vertical-align-lengths.html
+/sdcard/android/layout_tests/fast/css/value-list-out-of-bounds-crash.html
+/sdcard/android/layout_tests/fast/css/universal-hover-quirk.html
+/sdcard/android/layout_tests/fast/css/transition-color-unspecified.html
+/sdcard/android/layout_tests/fast/css/transform-default-parameter.html
+/sdcard/android/layout_tests/fast/css/textCapitalizeEdgeCases.html
+/sdcard/android/layout_tests/fast/css/text-security.html
+/sdcard/android/layout_tests/fast/css/text-align.html
+/sdcard/android/layout_tests/fast/css/target-fragment-match.html
+/sdcard/android/layout_tests/fast/css/table-text-align-strict.html
+/sdcard/android/layout_tests/fast/css/table-text-align-quirk.html
+/sdcard/android/layout_tests/fast/css/style-parsed-outside-head.html
+/sdcard/android/layout_tests/fast/css/style-outside-head.html
+/sdcard/android/layout_tests/fast/css/simple-selector-chain-parsing.html
+/sdcard/android/layout_tests/fast/css/shadow-multiple.html
+/sdcard/android/layout_tests/fast/css/selector-set-attribute.html
+/sdcard/android/layout_tests/fast/css/rtl-ordering.html
+/sdcard/android/layout_tests/fast/css/rgb-float.html
+/sdcard/android/layout_tests/fast/css/resize-corner-tracking.html
+/sdcard/android/layout_tests/fast/css/quirk-orphaned-units.html
+/sdcard/android/layout_tests/fast/css/position-negative-top-margin.html
+/sdcard/android/layout_tests/fast/css/percentage-non-integer.html
+/sdcard/android/layout_tests/fast/css/pendingStylesheetFontSize.html
+/sdcard/android/layout_tests/fast/css/outline-auto-location.html
+/sdcard/android/layout_tests/fast/css/outline-auto-empty-rects.html
+/sdcard/android/layout_tests/fast/css/only-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/only-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/negative-nth-child.html
+/sdcard/android/layout_tests/fast/css/max-height-none.html
+/sdcard/android/layout_tests/fast/css/MarqueeLayoutTest.html
+/sdcard/android/layout_tests/fast/css/marginComputedStyle.html
+/sdcard/android/layout_tests/fast/css/margin-top-bottom-dynamic.html
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-strict.html
+/sdcard/android/layout_tests/fast/css/margin-bottom-form-element-quirk.html
+/sdcard/android/layout_tests/fast/css/live-cssrules.html
+/sdcard/android/layout_tests/fast/css/list-outline.html
+/sdcard/android/layout_tests/fast/css/link-outside-head.html
+/sdcard/android/layout_tests/fast/css/line-height.html
+/sdcard/android/layout_tests/fast/css/line-height-overflow.html
+/sdcard/android/layout_tests/fast/css/line-height-negative.html
+/sdcard/android/layout_tests/fast/css/line-height-font-order.html
+/sdcard/android/layout_tests/fast/css/layerZOrderCrash.html
+/sdcard/android/layout_tests/fast/css/last-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/last-child-style-sharing.html
+/sdcard/android/layout_tests/fast/css/last-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-3.html
+/sdcard/android/layout_tests/fast/css/invalidation-errors-2.html
+/sdcard/android/layout_tests/fast/css/invalid-pseudo-classes.html
+/sdcard/android/layout_tests/fast/css/invalid-percentage-property.html
+/sdcard/android/layout_tests/fast/css/inline-properties-important.html
+/sdcard/android/layout_tests/fast/css/import_with_baseurl.html
+/sdcard/android/layout_tests/fast/css/import-rule-regression-11590.html
+/sdcard/android/layout_tests/fast/css/imageTileOpacity.html
+/sdcard/android/layout_tests/fast/css/ignore-text-zoom.html
+/sdcard/android/layout_tests/fast/css/hsla-color.html
+/sdcard/android/layout_tests/fast/css/hsl-color.html
+/sdcard/android/layout_tests/fast/css/hover-subselector.html
+/sdcard/android/layout_tests/fast/css/font_property_normal.html
+/sdcard/android/layout_tests/fast/css/font-weight-1.html
+/sdcard/android/layout_tests/fast/css/font-size-negative.html
+/sdcard/android/layout_tests/fast/css/font-shorthand-weight-only.html
+/sdcard/android/layout_tests/fast/css/font-face-unicode-range.html
+/sdcard/android/layout_tests/fast/css/font-face-remote.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-remote-sources.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-faces.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values.html
+/sdcard/android/layout_tests/fast/css/font-face-in-media-rule.html
+/sdcard/android/layout_tests/fast/css/font-face-default-font.html
+/sdcard/android/layout_tests/fast/css/first-of-type-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/first-letter-visibility.html
+/sdcard/android/layout_tests/fast/css/first-letter-skip-out-of-flow.html
+/sdcard/android/layout_tests/fast/css/first-letter-recalculation.html
+/sdcard/android/layout_tests/fast/css/first-letter-hover.html
+/sdcard/android/layout_tests/fast/css/first-letter-float.html
+/sdcard/android/layout_tests/fast/css/first-letter-float-after-float.html
+/sdcard/android/layout_tests/fast/css/first-letter-detach.html
+/sdcard/android/layout_tests/fast/css/first-letter-capitalized.html
+/sdcard/android/layout_tests/fast/css/first-child-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/find-next-layer.html
+/sdcard/android/layout_tests/fast/css/fieldset-display-row.html
+/sdcard/android/layout_tests/fast/css/ex-after-font-variant.html
+/sdcard/android/layout_tests/fast/css/error-in-last-decl.html
+/sdcard/android/layout_tests/fast/css/empty-pseudo-class.html
+/sdcard/android/layout_tests/fast/css/empty-generated-content.html
+/sdcard/android/layout_tests/fast/css/empty-body-test.html
+/sdcard/android/layout_tests/fast/css/dynamic-sibling-selector.html
+/sdcard/android/layout_tests/fast/css/disabled-author-styles.html
+/sdcard/android/layout_tests/fast/css/css3-nth-child.html
+/sdcard/android/layout_tests/fast/css/css3-modsel-22.html
+/sdcard/android/layout_tests/fast/css/css2-system-fonts.html
+/sdcard/android/layout_tests/fast/css/css-imports.html
+/sdcard/android/layout_tests/fast/css/continuationCrash.html
+/sdcard/android/layout_tests/fast/css/contentImage.html
+/sdcard/android/layout_tests/fast/css/contentDivWithChildren.html
+/sdcard/android/layout_tests/fast/css/contentDiv.html
+/sdcard/android/layout_tests/fast/css/content-dynamic.html
+/sdcard/android/layout_tests/fast/css/color-quirk.html
+/sdcard/android/layout_tests/fast/css/border-height.html
+/sdcard/android/layout_tests/fast/css/begin-end-contain-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/background-shorthand-invalid-url.html
+/sdcard/android/layout_tests/fast/css/background-image-with-baseurl.html
+/sdcard/android/layout_tests/fast/css/attribute-selector-empty-value.html
+/sdcard/android/layout_tests/fast/css/apple-prefix.html
+/sdcard/android/layout_tests/fast/css/affected-by-hover-after-style-change.html
+/sdcard/android/layout_tests/fast/css/acid2.html
+/sdcard/android/layout_tests/fast/css/acid2-pixel.html
+/sdcard/android/layout_tests/fast/css/absolute-poition-in-rtl-parent.html
+/sdcard/android/layout_tests/fast/css/008.html
+/sdcard/android/layout_tests/fast/css/007.html
+/sdcard/android/layout_tests/fast/css/006.html
+/sdcard/android/layout_tests/fast/css/005.html
+/sdcard/android/layout_tests/fast/css/004.html
+/sdcard/android/layout_tests/fast/css/003.html
+/sdcard/android/layout_tests/fast/css/002.html
+/sdcard/android/layout_tests/fast/css/001.html
+/sdcard/android/layout_tests/fast/compact/003.html
+/sdcard/android/layout_tests/fast/compact/002.html
+/sdcard/android/layout_tests/fast/compact/001.html
+/sdcard/android/layout_tests/fast/clip/outline-overflowClip.html
+/sdcard/android/layout_tests/fast/clip/nestedTransparencyClip.html
+/sdcard/android/layout_tests/fast/clip/017.html
+/sdcard/android/layout_tests/fast/clip/016.html
+/sdcard/android/layout_tests/fast/clip/015.html
+/sdcard/android/layout_tests/fast/clip/014.html
+/sdcard/android/layout_tests/fast/clip/013.html
+/sdcard/android/layout_tests/fast/clip/012.html
+/sdcard/android/layout_tests/fast/clip/011.html
+/sdcard/android/layout_tests/fast/clip/010.html
+/sdcard/android/layout_tests/fast/clip/009.html
+/sdcard/android/layout_tests/fast/clip/008.html
+/sdcard/android/layout_tests/fast/clip/007.html
+/sdcard/android/layout_tests/fast/clip/006.html
+/sdcard/android/layout_tests/fast/clip/005.html
+/sdcard/android/layout_tests/fast/clip/004.html
+/sdcard/android/layout_tests/fast/clip/003.html
+/sdcard/android/layout_tests/fast/clip/002.html
+/sdcard/android/layout_tests/fast/clip/001.html
+/sdcard/android/layout_tests/fast/canvas/zero-size-fill-rect.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-7.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-6.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-5.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-4.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-3.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-2.html
+/sdcard/android/layout_tests/fast/canvas/shadow-offset-1.html
+/sdcard/android/layout_tests/fast/canvas/quadraticCurveTo.xml
+/sdcard/android/layout_tests/fast/canvas/patternfill-repeat.html
+/sdcard/android/layout_tests/fast/canvas/image-object-in-canvas.html
+/sdcard/android/layout_tests/fast/canvas/gradient-empty-path.html
+/sdcard/android/layout_tests/fast/canvas/fillrect_gradient.html
+/sdcard/android/layout_tests/fast/canvas/fillrect-gradient-zero-stops.html
+/sdcard/android/layout_tests/fast/canvas/fill-stroke-clip-reset-path.html
+/sdcard/android/layout_tests/fast/canvas/drawImage.html
+/sdcard/android/layout_tests/fast/canvas/canvasDrawingIntoSelf.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transforms-during-path.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-skewed.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-non-invertible.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-nan.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-multiply.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-infinity.html
+/sdcard/android/layout_tests/fast/canvas/canvas-transform-identity.html
+/sdcard/android/layout_tests/fast/canvas/canvas-text-baseline.html
+/sdcard/android/layout_tests/fast/canvas/canvas-text-alignment.html
+/sdcard/android/layout_tests/fast/canvas/canvas-size-change-after-layout.html
+/sdcard/android/layout_tests/fast/canvas/canvas-resize-reset.html
+/sdcard/android/layout_tests/fast/canvas/canvas-bg.html
+/sdcard/android/layout_tests/fast/canvas/canvas-before-css.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-two.html
+/sdcard/android/layout_tests/fast/box-sizing/panels-one.html
+/sdcard/android/layout_tests/fast/box-sizing/box-sizing.html
+/sdcard/android/layout_tests/fast/box-shadow/border-radius-big.html
+/sdcard/android/layout_tests/fast/box-shadow/basic-shadows.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image.html
+/sdcard/android/layout_tests/fast/borders/svg-as-border-image-2.html
+/sdcard/android/layout_tests/fast/borders/outline-offset-min-assert.html
+/sdcard/android/layout_tests/fast/borders/inline-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/borders/fieldsetBorderRadius.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid04.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusSolid01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusRidge01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusOutset01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInvalidColor.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusInset01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusGroove01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDouble01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDotted01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed03.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed02.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusDashed01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusArcs01.html
+/sdcard/android/layout_tests/fast/borders/borderRadiusAllStylesAllCorners.html
+/sdcard/android/layout_tests/fast/borders/border-radius-huge-assert.html
+/sdcard/android/layout_tests/fast/borders/border-image-scale-transform.html
+/sdcard/android/layout_tests/fast/borders/border-image-rotate-transform.html
+/sdcard/android/layout_tests/fast/borders/border-image-omit-right-slice.html
+/sdcard/android/layout_tests/fast/borders/border-image-01.html
+/sdcard/android/layout_tests/fast/borders/border-fit.html
+/sdcard/android/layout_tests/fast/borders/border-color-inherit.html
+/sdcard/android/layout_tests/fast/borders/block-mask-overlay-image.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/007.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/006.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/005.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/004.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/003.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/002.html
+/sdcard/android/layout_tests/fast/body-propagation/overflow/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/010.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/009.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/008.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-image/001.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/008.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/007.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/006.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/005.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/004.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/003.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/002.html
+/sdcard/android/layout_tests/fast/body-propagation/background-color/001.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/007.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/006.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/005.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/004.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/003.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/002.html
+/sdcard/android/layout_tests/fast/block/positioning/auto/001.html
+/sdcard/android/layout_tests/fast/block/positioning/window-height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/replaced-inside-fixed-top-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/relayout-on-position-change.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-replaced-float.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overflow-block.html
+/sdcard/android/layout_tests/fast/block/positioning/relative-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/pref-width-change.html
+/sdcard/android/layout_tests/fast/block/positioning/padding-percent.html
+/sdcard/android/layout_tests/fast/block/positioning/offsetLeft-offsetTop-borders.html
+/sdcard/android/layout_tests/fast/block/positioning/negative-right-pos.html
+/sdcard/android/layout_tests/fast/block/positioning/move-with-auto-width.html
+/sdcard/android/layout_tests/fast/block/positioning/leftmargin-topmargin.html
+/sdcard/android/layout_tests/fast/block/positioning/inline-block-relposition.html
+/sdcard/android/layout_tests/fast/block/positioning/height-change.html
+/sdcard/android/layout_tests/fast/block/positioning/complex-percentage-height.html
+/sdcard/android/layout_tests/fast/block/positioning/child-of-absolute-with-auto-height.html
+/sdcard/android/layout_tests/fast/block/positioning/auto-height-with-top-and-bottom.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-with-html-border-quirks.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-positioned-overconstrained.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-strict.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-position-direction-quirk.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-length-of-neg-666666.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-short-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-rtl-2.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-3.html
+/sdcard/android/layout_tests/fast/block/positioning/absolute-in-inline-ltr-2.html
+/sdcard/android/layout_tests/fast/block/positioning/abs-inside-inline-rel.html
+/sdcard/android/layout_tests/fast/block/positioning/062.html
+/sdcard/android/layout_tests/fast/block/positioning/061.html
+/sdcard/android/layout_tests/fast/block/positioning/060.html
+/sdcard/android/layout_tests/fast/block/positioning/059.html
+/sdcard/android/layout_tests/fast/block/positioning/058.html
+/sdcard/android/layout_tests/fast/block/positioning/057.html
+/sdcard/android/layout_tests/fast/block/positioning/056.html
+/sdcard/android/layout_tests/fast/block/positioning/055.html
+/sdcard/android/layout_tests/fast/block/positioning/054.html
+/sdcard/android/layout_tests/fast/block/positioning/053.html
+/sdcard/android/layout_tests/fast/block/positioning/052.html
+/sdcard/android/layout_tests/fast/block/positioning/051.html
+/sdcard/android/layout_tests/fast/block/positioning/050.html
+/sdcard/android/layout_tests/fast/block/positioning/049.html
+/sdcard/android/layout_tests/fast/block/positioning/048.html
+/sdcard/android/layout_tests/fast/block/positioning/047.html
+/sdcard/android/layout_tests/fast/block/positioning/046.html
+/sdcard/android/layout_tests/fast/block/positioning/045.html
+/sdcard/android/layout_tests/fast/block/positioning/044.html
+/sdcard/android/layout_tests/fast/block/positioning/043.html
+/sdcard/android/layout_tests/fast/block/positioning/042.html
+/sdcard/android/layout_tests/fast/block/positioning/041.html
+/sdcard/android/layout_tests/fast/block/positioning/040.html
+/sdcard/android/layout_tests/fast/block/positioning/039.html
+/sdcard/android/layout_tests/fast/block/positioning/038.html
+/sdcard/android/layout_tests/fast/block/positioning/037.html
+/sdcard/android/layout_tests/fast/block/positioning/036.html
+/sdcard/android/layout_tests/fast/block/positioning/035.html
+/sdcard/android/layout_tests/fast/block/positioning/034.html
+/sdcard/android/layout_tests/fast/block/positioning/033.html
+/sdcard/android/layout_tests/fast/block/positioning/032.html
+/sdcard/android/layout_tests/fast/block/positioning/031.html
+/sdcard/android/layout_tests/fast/block/positioning/030.html
+/sdcard/android/layout_tests/fast/block/positioning/029.html
+/sdcard/android/layout_tests/fast/block/positioning/028.html
+/sdcard/android/layout_tests/fast/block/positioning/027.html
+/sdcard/android/layout_tests/fast/block/positioning/026.html
+/sdcard/android/layout_tests/fast/block/positioning/025.html
+/sdcard/android/layout_tests/fast/block/positioning/024.html
+/sdcard/android/layout_tests/fast/block/positioning/023.html
+/sdcard/android/layout_tests/fast/block/positioning/022.html
+/sdcard/android/layout_tests/fast/block/positioning/021.html
+/sdcard/android/layout_tests/fast/block/positioning/020.html
+/sdcard/android/layout_tests/fast/block/positioning/019.html
+/sdcard/android/layout_tests/fast/block/positioning/018.html
+/sdcard/android/layout_tests/fast/block/positioning/017.html
+/sdcard/android/layout_tests/fast/block/positioning/016.html
+/sdcard/android/layout_tests/fast/block/positioning/015.html
+/sdcard/android/layout_tests/fast/block/positioning/014.html
+/sdcard/android/layout_tests/fast/block/positioning/013.html
+/sdcard/android/layout_tests/fast/block/positioning/012.html
+/sdcard/android/layout_tests/fast/block/positioning/011.html
+/sdcard/android/layout_tests/fast/block/positioning/010.html
+/sdcard/android/layout_tests/fast/block/positioning/009.html
+/sdcard/android/layout_tests/fast/block/positioning/008.html
+/sdcard/android/layout_tests/fast/block/positioning/007.html
+/sdcard/android/layout_tests/fast/block/positioning/006.html
+/sdcard/android/layout_tests/fast/block/positioning/005.html
+/sdcard/android/layout_tests/fast/block/positioning/004.html
+/sdcard/android/layout_tests/fast/block/positioning/003.html
+/sdcard/android/layout_tests/fast/block/positioning/002.html
+/sdcard/android/layout_tests/fast/block/positioning/001.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/negative-margins.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/empty-clear-blocks.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/104.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/103.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/102.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/101.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/100.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/063.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/062.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/059.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/058.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/057.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/056.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/055.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/045.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/044.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/043.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/042.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/041.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/040.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/039.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/038.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/037.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/035.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/034.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/033.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/032.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/031.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/030.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/029.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/028.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/027.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/026.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/025.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/022.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/021.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/020.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/019.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/018.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/017.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/016.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/015.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/012.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/011.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/010.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/006.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/005.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/004.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/003.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/002.html
+/sdcard/android/layout_tests/fast/block/margin-collapse/001.html
+/sdcard/android/layout_tests/fast/block/float/width-update-after-clear.html
+/sdcard/android/layout_tests/fast/block/float/vertical-move-relayout.html
+/sdcard/android/layout_tests/fast/block/float/tableshifting.html
+/sdcard/android/layout_tests/fast/block/float/table-relayout.html
+/sdcard/android/layout_tests/fast/block/float/shrink-to-fit-width.html
+/sdcard/android/layout_tests/fast/block/float/relative-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease.html
+/sdcard/android/layout_tests/fast/block/float/overhanging-after-height-decrease-offsets.html
+/sdcard/android/layout_tests/fast/block/float/nowrap-clear-min-width.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction2.html
+/sdcard/android/layout_tests/fast/block/float/nopaint-after-layer-destruction.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks2.html
+/sdcard/android/layout_tests/fast/block/float/nestedAnonymousBlocks.html
+/sdcard/android/layout_tests/fast/block/float/negative-margin-clear.html
+/sdcard/android/layout_tests/fast/block/float/narrow-after-wide.html
+/sdcard/android/layout_tests/fast/block/float/multiple-float-positioning.html
+/sdcard/android/layout_tests/fast/block/float/marquee-shrink-to-avoid-floats.html
+/sdcard/android/layout_tests/fast/block/float/intruding-painted-twice.html
+/sdcard/android/layout_tests/fast/block/float/independent-align-positioning.html
+/sdcard/android/layout_tests/fast/block/float/float-on-zero-height-line.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-painting.html
+/sdcard/android/layout_tests/fast/block/float/float-in-float-hit-testing.html
+/sdcard/android/layout_tests/fast/block/float/float-avoidance.html
+/sdcard/android/layout_tests/fast/block/float/editable-text-overlapping-float.html
+/sdcard/android/layout_tests/fast/block/float/dynamic-unfloat-pref-width.html
+/sdcard/android/layout_tests/fast/block/float/clamped-right-float.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear.html
+/sdcard/android/layout_tests/fast/block/float/br-with-clear-2.html
+/sdcard/android/layout_tests/fast/block/float/4145535Crash.html
+/sdcard/android/layout_tests/fast/block/float/035.html
+/sdcard/android/layout_tests/fast/block/float/034.html
+/sdcard/android/layout_tests/fast/block/float/033.html
+/sdcard/android/layout_tests/fast/block/float/032.html
+/sdcard/android/layout_tests/fast/block/float/031.html
+/sdcard/android/layout_tests/fast/block/float/030.html
+/sdcard/android/layout_tests/fast/block/float/029.html
+/sdcard/android/layout_tests/fast/block/float/028.html
+/sdcard/android/layout_tests/fast/block/float/027.html
+/sdcard/android/layout_tests/fast/block/float/026.html
+/sdcard/android/layout_tests/fast/block/float/025.html
+/sdcard/android/layout_tests/fast/block/float/024.html
+/sdcard/android/layout_tests/fast/block/float/023.html
+/sdcard/android/layout_tests/fast/block/float/022.html
+/sdcard/android/layout_tests/fast/block/float/021.html
+/sdcard/android/layout_tests/fast/block/float/020.html
+/sdcard/android/layout_tests/fast/block/float/019.html
+/sdcard/android/layout_tests/fast/block/float/018.html
+/sdcard/android/layout_tests/fast/block/float/017.html
+/sdcard/android/layout_tests/fast/block/float/016.html
+/sdcard/android/layout_tests/fast/block/float/015.html
+/sdcard/android/layout_tests/fast/block/float/014.html
+/sdcard/android/layout_tests/fast/block/float/013.html
+/sdcard/android/layout_tests/fast/block/float/012.html
+/sdcard/android/layout_tests/fast/block/float/011.html
+/sdcard/android/layout_tests/fast/block/float/010.html
+/sdcard/android/layout_tests/fast/block/float/009.html
+/sdcard/android/layout_tests/fast/block/float/008.html
+/sdcard/android/layout_tests/fast/block/float/007.html
+/sdcard/android/layout_tests/fast/block/float/006.html
+/sdcard/android/layout_tests/fast/block/float/005.html
+/sdcard/android/layout_tests/fast/block/float/004.html
+/sdcard/android/layout_tests/fast/block/float/003.html
+/sdcard/android/layout_tests/fast/block/float/002.html
+/sdcard/android/layout_tests/fast/block/float/001.html
+/sdcard/android/layout_tests/fast/block/basic/white-space-pre-wraps.html
+/sdcard/android/layout_tests/fast/block/basic/text-indent-rtl.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-percent-height-grandchild.html
+/sdcard/android/layout_tests/fast/block/basic/quirk-height.html
+/sdcard/android/layout_tests/fast/block/basic/minheight.html
+/sdcard/android/layout_tests/fast/block/basic/min-pref-width-nowrap-floats.html
+/sdcard/android/layout_tests/fast/block/basic/fieldset-stretch-to-legend.html
+/sdcard/android/layout_tests/fast/block/basic/adding-near-anonymous-block.html
+/sdcard/android/layout_tests/fast/block/basic/021.html
+/sdcard/android/layout_tests/fast/block/basic/020.html
+/sdcard/android/layout_tests/fast/block/basic/019.html
+/sdcard/android/layout_tests/fast/block/basic/018.html
+/sdcard/android/layout_tests/fast/block/basic/016.html
+/sdcard/android/layout_tests/fast/block/basic/015.html
+/sdcard/android/layout_tests/fast/block/basic/014.html
+/sdcard/android/layout_tests/fast/block/basic/013.html
+/sdcard/android/layout_tests/fast/block/basic/012.html
+/sdcard/android/layout_tests/fast/block/basic/011.html
+/sdcard/android/layout_tests/fast/block/basic/010.html
+/sdcard/android/layout_tests/fast/block/basic/009.html
+/sdcard/android/layout_tests/fast/block/basic/008.html
+/sdcard/android/layout_tests/fast/block/basic/007.html
+/sdcard/android/layout_tests/fast/block/basic/006.html
+/sdcard/android/layout_tests/fast/block/basic/005.html
+/sdcard/android/layout_tests/fast/block/basic/004.html
+/sdcard/android/layout_tests/fast/block/basic/003.html
+/sdcard/android/layout_tests/fast/block/basic/002.html
+/sdcard/android/layout_tests/fast/block/basic/001.html
+/sdcard/android/layout_tests/fast/backgrounds/size/zero.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize19.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize18.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize17.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize16.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize15.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize14.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize13.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize12.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize11.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize10.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize09.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize08.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize07.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize06.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize05.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize04.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize03.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize02.html
+/sdcard/android/layout_tests/fast/backgrounds/size/backgroundSize01.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/noRepeatCorrectClip.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/negative-offset-repeat-transformed.html
+/sdcard/android/layout_tests/fast/backgrounds/repeat/mask-negative-offset-repeat.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-mask.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-6.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-5.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-4.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-3.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-2.html
+/sdcard/android/layout_tests/fast/backgrounds/svg-as-background-1.html
+/sdcard/android/layout_tests/fast/backgrounds/solid-color-context-restore.html
+/sdcard/android/layout_tests/fast/backgrounds/mask-composite.html
+/sdcard/android/layout_tests/fast/backgrounds/bgCompositeCopy.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-rounding.html
+/sdcard/android/layout_tests/fast/backgrounds/background-position-1.html
+/sdcard/android/layout_tests/fast/backgrounds/background-origin-root-element.html
+/sdcard/android/layout_tests/fast/backgrounds/background-inherit-color-bug.html
+/sdcard/android/layout_tests/fast/backgrounds/001.html
diff --git a/tests/DumpRenderTree/results/layout_tests_passed.txt b/tests/DumpRenderTree/results/layout_tests_passed.txt
new file mode 100644
index 0000000..03e920e
--- /dev/null
+++ b/tests/DumpRenderTree/results/layout_tests_passed.txt
@@ -0,0 +1,990 @@
+/sdcard/android/layout_tests/fast/transforms/container-transform-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/write-unclosed-script.html
+/sdcard/android/layout_tests/fast/tokenizer/write-partial-entity.html
+/sdcard/android/layout_tests/fast/tokenizer/write-inline-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/write-external-script-open.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-multiple-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/nested-cached-scripts.html
+/sdcard/android/layout_tests/fast/tokenizer/lessthan-terminates-tags-and-attrs.html
+/sdcard/android/layout_tests/fast/tokenizer/image-empty-crash.html
+/sdcard/android/layout_tests/fast/tokenizer/ignore-tags-in-iframe.html
+/sdcard/android/layout_tests/fast/tokenizer/external-script-document-open.html
+/sdcard/android/layout_tests/fast/tokenizer/doctype-search-reset.html
+/sdcard/android/layout_tests/fast/tokenizer/badscript.html
+/sdcard/android/layout_tests/fast/tokenizer/ampersand-in-special-tag.html
+/sdcard/android/layout_tests/fast/tokenizer/004.html
+/sdcard/android/layout_tests/fast/text/line-breaks-after-ideographic-comma-or-full-stop.html
+/sdcard/android/layout_tests/fast/text/large-text-composed-char-dos.html
+/sdcard/android/layout_tests/fast/text/find-case-folding.html
+/sdcard/android/layout_tests/fast/table/td-display-nowrap.html
+/sdcard/android/layout_tests/fast/table/section-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/rowindex-comment-nodes.html
+/sdcard/android/layout_tests/fast/table/row-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/large-rowspan-crash.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-hang.html
+/sdcard/android/layout_tests/fast/table/incomplete-table-in-fragment-2.html
+/sdcard/android/layout_tests/fast/table/form-in-tbody-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/form-in-table-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/form-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/empty-auto-column-zero-divide.html
+/sdcard/android/layout_tests/fast/table/destroy-cell-with-selection-crash.html
+/sdcard/android/layout_tests/fast/table/colgroup-relative.html
+/sdcard/android/layout_tests/fast/table/cell-in-row-before-misnested-text-crash-css.html
+/sdcard/android/layout_tests/fast/table/border-changes.html
+/sdcard/android/layout_tests/fast/replaced/object-param-no-name.html
+/sdcard/android/layout_tests/fast/regex/test4.html
+/sdcard/android/layout_tests/fast/regex/test1.html
+/sdcard/android/layout_tests/fast/regex/slow.html
+/sdcard/android/layout_tests/fast/regex/early-acid3-86.html
+/sdcard/android/layout_tests/fast/reflections/teardown-crash.html
+/sdcard/android/layout_tests/fast/reflections/reflection-computed-style.html
+/sdcard/android/layout_tests/fast/parser/test-unicode-characters-in-attribute-name.html
+/sdcard/android/layout_tests/fast/parser/tag-with-exclamation-point.html
+/sdcard/android/layout_tests/fast/parser/strict-img-in-map.html
+/sdcard/android/layout_tests/fast/parser/script-after-frameset-assert.html
+/sdcard/android/layout_tests/fast/parser/rewrite-map.html
+/sdcard/android/layout_tests/fast/parser/rewrite-form.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-removed-block.html
+/sdcard/android/layout_tests/fast/parser/residual-style-close-across-n-blocks.html
+/sdcard/android/layout_tests/fast/parser/remove-parser-current-node.html
+/sdcard/android/layout_tests/fast/parser/remove-node-stack.html
+/sdcard/android/layout_tests/fast/parser/remove-current-node-parent.html
+/sdcard/android/layout_tests/fast/parser/pre-first-line-break.html
+/sdcard/android/layout_tests/fast/parser/parse-wbr.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope.html
+/sdcard/android/layout_tests/fast/parser/p-in-scope-strict.html
+/sdcard/android/layout_tests/fast/parser/open-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/number-sign-in-map-name.html
+/sdcard/android/layout_tests/fast/parser/nsup-entity.html
+/sdcard/android/layout_tests/fast/parser/input-textarea-inside-select-element.html
+/sdcard/android/layout_tests/fast/parser/html-whitespace.html
+/sdcard/android/layout_tests/fast/parser/hex-entities-length.html
+/sdcard/android/layout_tests/fast/parser/head-comment.html
+/sdcard/android/layout_tests/fast/parser/entity-surrogate-pairs.html
+/sdcard/android/layout_tests/fast/parser/entity-end-xmp-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-title-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-textarea-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-style-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-end-iframe-tag.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/entity-comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/entities-in-html.html
+/sdcard/android/layout_tests/fast/parser/duplicate-html-body-element-IDs.html
+/sdcard/android/layout_tests/fast/parser/comment-in-title.html
+/sdcard/android/layout_tests/fast/parser/comment-in-script-tricky.html
+/sdcard/android/layout_tests/fast/parser/assertion-empty-attribute.html
+/sdcard/android/layout_tests/fast/parser/area-in-div.html
+/sdcard/android/layout_tests/fast/overflow/onscroll-layer-self-destruct.html
+/sdcard/android/layout_tests/fast/overflow/generated-content-crash.html
+/sdcard/android/layout_tests/fast/multicol/gap-non-negative.html
+/sdcard/android/layout_tests/fast/multicol/content-height-zero-crash.html
+/sdcard/android/layout_tests/fast/loader/xmlhttprequest-bad-mimetype.html
+/sdcard/android/layout_tests/fast/loader/window-clearing.html
+/sdcard/android/layout_tests/fast/loader/user-style-sheet-resource-load-callbacks.html
+/sdcard/android/layout_tests/fast/loader/url-strip-cr-lf-tab.html
+/sdcard/android/layout_tests/fast/loader/url-parse-1.html
+/sdcard/android/layout_tests/fast/loader/url-data-replace-backslash.html
+/sdcard/android/layout_tests/fast/loader/unloadable-script.html
+/sdcard/android/layout_tests/fast/loader/simultaneous-reloads-assert.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe.html
+/sdcard/android/layout_tests/fast/loader/redirect-with-open-subframe-2.html
+/sdcard/android/layout_tests/fast/loader/meta-refresh-vs-open.html
+/sdcard/android/layout_tests/fast/loader/local-css-allowed-in-strict-mode.html
+/sdcard/android/layout_tests/fast/loader/loadInProgress.html
+/sdcard/android/layout_tests/fast/loader/link-no-URL.html
+/sdcard/android/layout_tests/fast/loader/javascript-url-encoding.html
+/sdcard/android/layout_tests/fast/loader/invalid-charset-on-script-crashes-loader.html
+/sdcard/android/layout_tests/fast/loader/inherit-charset-to-empty-frame.html
+/sdcard/android/layout_tests/fast/loader/iframe-recursive-synchronous-load.html
+/sdcard/android/layout_tests/fast/loader/font-face-empty.html
+/sdcard/android/layout_tests/fast/loader/file-URL-with-port-number.html
+/sdcard/android/layout_tests/fast/loader/external-script-URL-location.html
+/sdcard/android/layout_tests/fast/loader/empty-ref-versus-no-ref.html
+/sdcard/android/layout_tests/fast/loader/early-load-cancel.html
+/sdcard/android/layout_tests/fast/loader/data-url-encoding-html.html
+/sdcard/android/layout_tests/fast/loader/charset-parse.html
+/sdcard/android/layout_tests/fast/leaks/002.html
+/sdcard/android/layout_tests/fast/leaks/001.html
+/sdcard/android/layout_tests/fast/layers/resize-layer-deletion-crash.html
+/sdcard/android/layout_tests/fast/layers/removed-by-scroll-handler.html
+/sdcard/android/layout_tests/fast/layers/generated-layer-scrollbar-crash.html
+/sdcard/android/layout_tests/fast/js/pic/rehash-poisons-structure.html
+/sdcard/android/layout_tests/fast/js/pic/get-set-proxy-object.html
+/sdcard/android/layout_tests/fast/js/pic/get-empty-string.html
+/sdcard/android/layout_tests/fast/js/pic/dictionary-prototype.html
+/sdcard/android/layout_tests/fast/js/pic/cached-single-entry-transition.html
+/sdcard/android/layout_tests/fast/js/pic/cached-prototype-setter.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-setter.html
+/sdcard/android/layout_tests/fast/js/pic/cached-getter-dictionary-and-proto.html
+/sdcard/android/layout_tests/fast/js/pic/cached-deleted-properties.html
+/sdcard/android/layout_tests/fast/js/window-location-href-file-urls.html
+/sdcard/android/layout_tests/fast/js/while-expression-value.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-vardecl.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-parameters.html
+/sdcard/android/layout_tests/fast/js/vardecl-preserve-arguments.html
+/sdcard/android/layout_tests/fast/js/vardecl-blocks-init.html
+/sdcard/android/layout_tests/fast/js/var-shadows-arg-crash.html
+/sdcard/android/layout_tests/fast/js/var-declarations.html
+/sdcard/android/layout_tests/fast/js/var-declarations-shadowing.html
+/sdcard/android/layout_tests/fast/js/unmatching-argument-count.html
+/sdcard/android/layout_tests/fast/js/unexpected-constant-crash.html
+/sdcard/android/layout_tests/fast/js/typeof-syntax.html
+/sdcard/android/layout_tests/fast/js/typeof-codegen-crash.html
+/sdcard/android/layout_tests/fast/js/toString-try-else.html
+/sdcard/android/layout_tests/fast/js/toString-prefix-postfix-preserve-parens.html
+/sdcard/android/layout_tests/fast/js/toString-overrides.html
+/sdcard/android/layout_tests/fast/js/toString-number-dot-expr.html
+/sdcard/android/layout_tests/fast/js/toString-for-var-decl.html
+/sdcard/android/layout_tests/fast/js/toString-exception.html
+/sdcard/android/layout_tests/fast/js/tostring-exception-in-property-access.html
+/sdcard/android/layout_tests/fast/js/toString-elision-trailing-comma.html
+/sdcard/android/layout_tests/fast/js/toString-dontEnum.html
+/sdcard/android/layout_tests/fast/js/throw-from-array-sort.html
+/sdcard/android/layout_tests/fast/js/this-non-object-proto.html
+/sdcard/android/layout_tests/fast/js/switch-behaviour.html
+/sdcard/android/layout_tests/fast/js/string_replace.html
+/sdcard/android/layout_tests/fast/js/string-substr.html
+/sdcard/android/layout_tests/fast/js/string-split-ignore-case.html
+/sdcard/android/layout_tests/fast/js/string-sort.html
+/sdcard/android/layout_tests/fast/js/string-slice-abnormal-values.html
+/sdcard/android/layout_tests/fast/js/string-replace-exception-crash.html
+/sdcard/android/layout_tests/fast/js/string-replace-3.html
+/sdcard/android/layout_tests/fast/js/string-replace-2.html
+/sdcard/android/layout_tests/fast/js/string-property-iteration.html
+/sdcard/android/layout_tests/fast/js/string-index-overflow.html
+/sdcard/android/layout_tests/fast/js/string-from-char-code.html
+/sdcard/android/layout_tests/fast/js/string-capitalization.html
+/sdcard/android/layout_tests/fast/js/static-scope-object.html
+/sdcard/android/layout_tests/fast/js/statement-list-register-crash.html
+/sdcard/android/layout_tests/fast/js/stack-unwinding.html
+/sdcard/android/layout_tests/fast/js/sparse-array.html
+/sdcard/android/layout_tests/fast/js/sort-stability.html
+/sdcard/android/layout_tests/fast/js/sort-randomly.html
+/sdcard/android/layout_tests/fast/js/sort-large-array.html
+/sdcard/android/layout_tests/fast/js/slash-lineterminator-parse.html
+/sdcard/android/layout_tests/fast/js/select-options-remove.html
+/sdcard/android/layout_tests/fast/js/select-options-remove-gc.html
+/sdcard/android/layout_tests/fast/js/select-options-add.html
+/sdcard/android/layout_tests/fast/js/resize-array-assign.html
+/sdcard/android/layout_tests/fast/js/reserved-words.html
+/sdcard/android/layout_tests/fast/js/removing-Cf-characters.html
+/sdcard/android/layout_tests/fast/js/rehash-assign.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-unicode-handling.html
+/sdcard/android/layout_tests/fast/js/regexp-stack-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-ranges-and-escaped-hyphens.html
+/sdcard/android/layout_tests/fast/js/regexp-range-out-of-order.html
+/sdcard/android/layout_tests/fast/js/regexp-overflow.html
+/sdcard/android/layout_tests/fast/js/regexp-non-character.html
+/sdcard/android/layout_tests/fast/js/regexp-non-capturing-groups.html
+/sdcard/android/layout_tests/fast/js/regexp-non-bmp.html
+/sdcard/android/layout_tests/fast/js/regexp-no-extensions.html
+/sdcard/android/layout_tests/fast/js/regexp-negative-special-characters.html
+/sdcard/android/layout_tests/fast/js/regexp-many-brackets.html
+/sdcard/android/layout_tests/fast/js/regexp-lastindex.html
+/sdcard/android/layout_tests/fast/js/regexp-find-first-asserted.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-more.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-match.html
+/sdcard/android/layout_tests/fast/js/regexp-extended-characters-crash.html
+/sdcard/android/layout_tests/fast/js/regexp-divequal.html
+/sdcard/android/layout_tests/fast/js/regexp-compile.html
+/sdcard/android/layout_tests/fast/js/regexp-compile-crash.html
+/sdcard/android/layout_tests/fast/js/regexp-char-insensitive.html
+/sdcard/android/layout_tests/fast/js/regexp-caching.html
+/sdcard/android/layout_tests/fast/js/reentrant-call-unwind.html
+/sdcard/android/layout_tests/fast/js/read-modify-eval.html
+/sdcard/android/layout_tests/fast/js/propertyIsEnumerable.html
+/sdcard/android/layout_tests/fast/js/property-getters-and-setters.html
+/sdcard/android/layout_tests/fast/js/primitive-method-this.html
+/sdcard/android/layout_tests/fast/js/pretty-print.html
+/sdcard/android/layout_tests/fast/js/prefix-syntax.html
+/sdcard/android/layout_tests/fast/js/postfix-syntax.html
+/sdcard/android/layout_tests/fast/js/parse-backslash-before-newline.html
+/sdcard/android/layout_tests/fast/js/order-of-operations.html
+/sdcard/android/layout_tests/fast/js/object-prototype-toLocaleString.html
+/sdcard/android/layout_tests/fast/js/object-prototype-constructor.html
+/sdcard/android/layout_tests/fast/js/object-extra-comma.html
+/sdcard/android/layout_tests/fast/js/numeric-conversion.html
+/sdcard/android/layout_tests/fast/js/number-toString.html
+/sdcard/android/layout_tests/fast/js/number-toprecision.html
+/sdcard/android/layout_tests/fast/js/number-tofixed.html
+/sdcard/android/layout_tests/fast/js/number-toExponential.html
+/sdcard/android/layout_tests/fast/js/null-char-in-string.html
+/sdcard/android/layout_tests/fast/js/non-object-proto.html
+/sdcard/android/layout_tests/fast/js/nested-function-scope.html
+/sdcard/android/layout_tests/fast/js/navigator-plugins-crash.html
+/sdcard/android/layout_tests/fast/js/named-function-expression.html
+/sdcard/android/layout_tests/fast/js/modify-non-references.html
+/sdcard/android/layout_tests/fast/js/mod-crash.html
+/sdcard/android/layout_tests/fast/js/missing-title-end-tag-js.html
+/sdcard/android/layout_tests/fast/js/math.html
+/sdcard/android/layout_tests/fast/js/logical-or-jless.html
+/sdcard/android/layout_tests/fast/js/lexical-lookup-in-function-constructor.html
+/sdcard/android/layout_tests/fast/js/lastModified.html
+/sdcard/android/layout_tests/fast/js/isPrototypeOf.html
+/sdcard/android/layout_tests/fast/js/invalid-syntax-for-function.html
+/sdcard/android/layout_tests/fast/js/integer-extremes.html
+/sdcard/android/layout_tests/fast/js/implicit-global-to-global-reentry.html
+/sdcard/android/layout_tests/fast/js/implicit-call-with-global-reentry.html
+/sdcard/android/layout_tests/fast/js/has-own-property.html
+/sdcard/android/layout_tests/fast/js/gmail-re-re.html
+/sdcard/android/layout_tests/fast/js/global-var-limit.html
+/sdcard/android/layout_tests/fast/js/getter-setter-gc.html
+/sdcard/android/layout_tests/fast/js/function-toString-parentheses.html
+/sdcard/android/layout_tests/fast/js/function-toString-object-literals.html
+/sdcard/android/layout_tests/fast/js/function-redefinition.html
+/sdcard/android/layout_tests/fast/js/function-prototype.html
+/sdcard/android/layout_tests/fast/js/function-names.html
+/sdcard/android/layout_tests/fast/js/function-name.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments.html
+/sdcard/android/layout_tests/fast/js/function-dot-arguments-and-caller.html
+/sdcard/android/layout_tests/fast/js/function-decompilation-operators.html
+/sdcard/android/layout_tests/fast/js/function-declarations.html
+/sdcard/android/layout_tests/fast/js/function-declarations-in-switch-statement.html
+/sdcard/android/layout_tests/fast/js/function-call-register-allocation.html
+/sdcard/android/layout_tests/fast/js/function-argument-evaluation-before-exception.html
+/sdcard/android/layout_tests/fast/js/function-apply.html
+/sdcard/android/layout_tests/fast/js/for-in-var-scope.html
+/sdcard/android/layout_tests/fast/js/for-in-to-text.html
+/sdcard/android/layout_tests/fast/js/for-in-exeception.html
+/sdcard/android/layout_tests/fast/js/for-in-avoid-duplicates.html
+/sdcard/android/layout_tests/fast/js/finally-codegen-failure.html
+/sdcard/android/layout_tests/fast/js/exec-state-marking.html
+/sdcard/android/layout_tests/fast/js/exception-try-finally-scope-error.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-new.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-function-with-lazy-activation.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-eval-inside-closure.html
+/sdcard/android/layout_tests/fast/js/exception-thrown-from-equal.html
+/sdcard/android/layout_tests/fast/js/exception-linenums.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-2.html
+/sdcard/android/layout_tests/fast/js/exception-linenums-in-html-1.html
+/sdcard/android/layout_tests/fast/js/exception-expression-offset.html
+/sdcard/android/layout_tests/fast/js/eval-var-decl.html
+/sdcard/android/layout_tests/fast/js/eval-overriding.html
+/sdcard/android/layout_tests/fast/js/eval-keyword-vs-function.html
+/sdcard/android/layout_tests/fast/js/eval-cross-window.html
+/sdcard/android/layout_tests/fast/js/eval-cache-crash.html
+/sdcard/android/layout_tests/fast/js/equality.html
+/sdcard/android/layout_tests/fast/js/encode-URI-test.html
+/sdcard/android/layout_tests/fast/js/duplicate-param-crash.html
+/sdcard/android/layout_tests/fast/js/dot-node-base-exception.html
+/sdcard/android/layout_tests/fast/js/do-while-without-semicolon.html
+/sdcard/android/layout_tests/fast/js/do-while-semicolon.html
+/sdcard/android/layout_tests/fast/js/do-while-expression-value.html
+/sdcard/android/layout_tests/fast/js/direct-entry-to-function-code.html
+/sdcard/android/layout_tests/fast/js/delete-then-put.html
+/sdcard/android/layout_tests/fast/js/delete-syntax.html
+/sdcard/android/layout_tests/fast/js/delete-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/delete-getters-setters.html
+/sdcard/android/layout_tests/fast/js/delete-function-parameter.html
+/sdcard/android/layout_tests/fast/js/deep-recursion-test.html
+/sdcard/android/layout_tests/fast/js/declaration-in-block.html
+/sdcard/android/layout_tests/fast/js/debugger.html
+/sdcard/android/layout_tests/fast/js/date-set-to-nan.html
+/sdcard/android/layout_tests/fast/js/date-proto-generic-invocation.html
+/sdcard/android/layout_tests/fast/js/date-preserve-milliseconds.html
+/sdcard/android/layout_tests/fast/js/date-parse-test.html
+/sdcard/android/layout_tests/fast/js/date-parse-comments-test.html
+/sdcard/android/layout_tests/fast/js/date-negative-setmonth.html
+/sdcard/android/layout_tests/fast/js/date-DST-time-cusps.html
+/sdcard/android/layout_tests/fast/js/date-DST-pre-1970.html
+/sdcard/android/layout_tests/fast/js/date-constructor.html
+/sdcard/android/layout_tests/fast/js/date-big-setmonth.html
+/sdcard/android/layout_tests/fast/js/date-big-setdate.html
+/sdcard/android/layout_tests/fast/js/date-big-constructor.html
+/sdcard/android/layout_tests/fast/js/cyclic-ref-toString.html
+/sdcard/android/layout_tests/fast/js/cyclic-prototypes.html
+/sdcard/android/layout_tests/fast/js/cyclic-proto.html
+/sdcard/android/layout_tests/fast/js/convert-nan-to-bool.html
+/sdcard/android/layout_tests/fast/js/continue-break-multiple-labels.html
+/sdcard/android/layout_tests/fast/js/constructor.html
+/sdcard/android/layout_tests/fast/js/constructor-attributes.html
+/sdcard/android/layout_tests/fast/js/construct-global-object.html
+/sdcard/android/layout_tests/fast/js/constant-folding.html
+/sdcard/android/layout_tests/fast/js/constant-count.html
+/sdcard/android/layout_tests/fast/js/const.html
+/sdcard/android/layout_tests/fast/js/const-without-initializer.html
+/sdcard/android/layout_tests/fast/js/comparefn-sort-stability.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries.html
+/sdcard/android/layout_tests/fast/js/codegen-temporaries-multiple-global-blocks.html
+/sdcard/android/layout_tests/fast/js/codegen-peephole-locals.html
+/sdcard/android/layout_tests/fast/js/codegen-loops-logical-nodes.html
+/sdcard/android/layout_tests/fast/js/code-serialize-paren.html
+/sdcard/android/layout_tests/fast/js/closure-inside-extra-arg-call.html
+/sdcard/android/layout_tests/fast/js/char-at.html
+/sdcard/android/layout_tests/fast/js/caller-property.html
+/sdcard/android/layout_tests/fast/js/bitwise-and-on-undefined.html
+/sdcard/android/layout_tests/fast/js/avl-crash.html
+/sdcard/android/layout_tests/fast/js/assign.html
+/sdcard/android/layout_tests/fast/js/ascii-regexp-subject.html
+/sdcard/android/layout_tests/fast/js/array-tostring-ignore-separator.html
+/sdcard/android/layout_tests/fast/js/array-tostring-and-join.html
+/sdcard/android/layout_tests/fast/js/array-splice.html
+/sdcard/android/layout_tests/fast/js/array-sort-reentrance.html
+/sdcard/android/layout_tests/fast/js/array-some.html
+/sdcard/android/layout_tests/fast/js/array-reset-large-index.html
+/sdcard/android/layout_tests/fast/js/array-map.html
+/sdcard/android/layout_tests/fast/js/array-lastIndexOf.html
+/sdcard/android/layout_tests/fast/js/array-join-bug-11524.html
+/sdcard/android/layout_tests/fast/js/array-iterate-backwards.html
+/sdcard/android/layout_tests/fast/js/array-indexof.html
+/sdcard/android/layout_tests/fast/js/array-indexing.html
+/sdcard/android/layout_tests/fast/js/array-index-immediate-types.html
+/sdcard/android/layout_tests/fast/js/array-holes.html
+/sdcard/android/layout_tests/fast/js/array-functions-non-arrays.html
+/sdcard/android/layout_tests/fast/js/array-foreach.html
+/sdcard/android/layout_tests/fast/js/array-float-delete.html
+/sdcard/android/layout_tests/fast/js/array-filter.html
+/sdcard/android/layout_tests/fast/js/array-every.html
+/sdcard/android/layout_tests/fast/js/arguments.html
+/sdcard/android/layout_tests/fast/js/arguments-bad-index.html
+/sdcard/android/layout_tests/fast/js/activation-proto.html
+/sdcard/android/layout_tests/fast/js/activation-object-function-lifetime.html
+/sdcard/android/layout_tests/fast/invalid/test-case-tr-th-td-should-not-close-dl-list.html
+/sdcard/android/layout_tests/fast/invalid/nestedh3s-rapidweaver.html
+/sdcard/android/layout_tests/fast/inspector/cssURLQuotes.html
+/sdcard/android/layout_tests/fast/innerHTML/javascript-url.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-custom-tag.html
+/sdcard/android/layout_tests/fast/innerHTML/innerHTML-case.html
+/sdcard/android/layout_tests/fast/innerHTML/additional-inline-style.html
+/sdcard/android/layout_tests/fast/innerHTML/005.html
+/sdcard/android/layout_tests/fast/inline/clean-after-removing-temp-boxes.html
+/sdcard/android/layout_tests/fast/images/text-content-crash.html
+/sdcard/android/layout_tests/fast/images/text-content-crash-2.html
+/sdcard/android/layout_tests/fast/images/load-img-with-empty-src.html
+/sdcard/android/layout_tests/fast/images/border.html
+/sdcard/android/layout_tests/fast/images/animated-background-image-crash.html
+/sdcard/android/layout_tests/fast/html/xhtml-serialize.html
+/sdcard/android/layout_tests/fast/html/script-allowed-types-languages.html
+/sdcard/android/layout_tests/fast/html/empty-fragment-id-goto-top.html
+/sdcard/android/layout_tests/fast/html/body-offset-properties.html
+/sdcard/android/layout_tests/fast/frames/viewsource-plain-text-tags.html
+/sdcard/android/layout_tests/fast/frames/set-unloaded-frame-location.html
+/sdcard/android/layout_tests/fast/frames/repaint-display-none-crash.html
+/sdcard/android/layout_tests/fast/frames/remove-frame-with-scrollbars-crash.html
+/sdcard/android/layout_tests/fast/frames/onload-remove-iframe-crash.html
+/sdcard/android/layout_tests/fast/frames/negative-remaining-length-crash.html
+/sdcard/android/layout_tests/fast/frames/location-put-after-removal.html
+/sdcard/android/layout_tests/fast/frames/location-change.html
+/sdcard/android/layout_tests/fast/frames/iframe-target.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/iframe-set-inner-html.html
+/sdcard/android/layout_tests/fast/frames/iframe-remove-after-id-change.html
+/sdcard/android/layout_tests/fast/frames/iframe-name-and-id.html
+/sdcard/android/layout_tests/fast/frames/iframe-js-url-clientWidth.html
+/sdcard/android/layout_tests/fast/frames/iframe-double-attach.html
+/sdcard/android/layout_tests/fast/frames/iframe-display-none.html
+/sdcard/android/layout_tests/fast/frames/hover-timer-crash.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-src.html
+/sdcard/android/layout_tests/fast/frames/frame-set-same-location.html
+/sdcard/android/layout_tests/fast/frames/frame-name-reset.html
+/sdcard/android/layout_tests/fast/frames/frame-display-none-focus.html
+/sdcard/android/layout_tests/fast/frames/empty-frame-document.html
+/sdcard/android/layout_tests/fast/frames/cross-site-this.html
+/sdcard/android/layout_tests/fast/frames/crash-removed-iframe.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-009.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-008.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-007.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-006.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-005.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-004.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-003.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-002.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-001.html
+/sdcard/android/layout_tests/fast/forms/willvalidate-000.html
+/sdcard/android/layout_tests/fast/forms/textfield-focus-out.html
+/sdcard/android/layout_tests/fast/forms/textarea-trailing-newline.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-without-renderer.html
+/sdcard/android/layout_tests/fast/forms/textarea-setvalue-submit.html
+/sdcard/android/layout_tests/fast/forms/textarea-scrollbar-height.html
+/sdcard/android/layout_tests/fast/forms/textarea-linewrap-dynamic.html
+/sdcard/android/layout_tests/fast/forms/textarea-hard-linewrap-empty.html
+/sdcard/android/layout_tests/fast/forms/textarea-crlf.html
+/sdcard/android/layout_tests/fast/forms/text-set-value-crash.html
+/sdcard/android/layout_tests/fast/forms/tabs-with-modifiers.html
+/sdcard/android/layout_tests/fast/forms/tab-in-input.html
+/sdcard/android/layout_tests/fast/forms/submit-with-base.html
+/sdcard/android/layout_tests/fast/forms/submit-to-url-fragment.html
+/sdcard/android/layout_tests/fast/forms/submit-nil-value-field-assert.html
+/sdcard/android/layout_tests/fast/forms/slow-click.html
+/sdcard/android/layout_tests/fast/forms/selected-index-assert.html
+/sdcard/android/layout_tests/fast/forms/select-width-font-change.html
+/sdcard/android/layout_tests/fast/forms/select-type-ahead-list-box-no-selection.html
+/sdcard/android/layout_tests/fast/forms/select-set-inner.html
+/sdcard/android/layout_tests/fast/forms/select-reset.html
+/sdcard/android/layout_tests/fast/forms/select-replace-option.html
+/sdcard/android/layout_tests/fast/forms/select-remove-option.html
+/sdcard/android/layout_tests/fast/forms/select-out-of-bounds-index.html
+/sdcard/android/layout_tests/fast/forms/select-namedItem.html
+/sdcard/android/layout_tests/fast/forms/select-list-box-mouse-focus.html
+/sdcard/android/layout_tests/fast/forms/select-index-setter.html
+/sdcard/android/layout_tests/fast/forms/saved-state-adoptNode-crash.html
+/sdcard/android/layout_tests/fast/forms/remove-radio-button-assert.html
+/sdcard/android/layout_tests/fast/forms/range-reset.html
+/sdcard/android/layout_tests/fast/forms/range-default-value.html
+/sdcard/android/layout_tests/fast/forms/radio_checked_name.html
+/sdcard/android/layout_tests/fast/forms/radio-no-theme-padding.html
+/sdcard/android/layout_tests/fast/forms/radio-check-click-and-drag.html
+/sdcard/android/layout_tests/fast/forms/radio-button-no-change-event.html
+/sdcard/android/layout_tests/fast/forms/paste-multiline-text-input.html
+/sdcard/android/layout_tests/fast/forms/paste-into-textarea.html
+/sdcard/android/layout_tests/fast/forms/option-in-optgroup-removal.html
+/sdcard/android/layout_tests/fast/forms/option-constructor-selected.html
+/sdcard/android/layout_tests/fast/forms/option-change-single-selected.html
+/sdcard/android/layout_tests/fast/forms/old-names.html
+/sdcard/android/layout_tests/fast/forms/missing-action.html
+/sdcard/android/layout_tests/fast/forms/menulist-selection-reset.html
+/sdcard/android/layout_tests/fast/forms/menulist-no-renderer-onmousedown.html
+/sdcard/android/layout_tests/fast/forms/listbox-typeahead-empty.html
+/sdcard/android/layout_tests/fast/forms/listbox-scroll-after-options-removed.html
+/sdcard/android/layout_tests/fast/forms/input-zero-height-focus.html
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-mouse.html
+/sdcard/android/layout_tests/fast/forms/input-type-change-in-onfocus-keyboard.html
+/sdcard/android/layout_tests/fast/forms/input-setvalue-selection.html
+/sdcard/android/layout_tests/fast/forms/input-selection-hidden.html
+/sdcard/android/layout_tests/fast/forms/input-named-action-overrides-action-attribute.html
+/sdcard/android/layout_tests/fast/forms/input-changing-value.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-maxlength.html
+/sdcard/android/layout_tests/fast/forms/input-appearance-elementFromPoint.html
+/sdcard/android/layout_tests/fast/forms/HTMLOptionElement_selected.html
+/sdcard/android/layout_tests/fast/forms/hidden-input-not-enabled.html
+/sdcard/android/layout_tests/fast/forms/form-post-urlencoded.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart3.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart2.html
+/sdcard/android/layout_tests/fast/forms/form-get-multipart.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-normalization-overrun.html
+/sdcard/android/layout_tests/fast/forms/form-data-encoding-2.html
+/sdcard/android/layout_tests/fast/forms/focus-style-pending.html
+/sdcard/android/layout_tests/fast/forms/empty-get.html
+/sdcard/android/layout_tests/fast/forms/element-order.html
+/sdcard/android/layout_tests/fast/forms/element-by-name.html
+/sdcard/android/layout_tests/fast/forms/double-focus.html
+/sdcard/android/layout_tests/fast/forms/domstring-replace-crash.html
+/sdcard/android/layout_tests/fast/forms/document-write.html
+/sdcard/android/layout_tests/fast/forms/display-none-in-onchange-keyboard.html
+/sdcard/android/layout_tests/fast/forms/cursor-position.html
+/sdcard/android/layout_tests/fast/forms/button-in-forms-collection.html
+/sdcard/android/layout_tests/fast/forms/button-click-DOM.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-008.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-007.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-006.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-005.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-004.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-002.html
+/sdcard/android/layout_tests/fast/forms/autofocus-opera-001.html
+/sdcard/android/layout_tests/fast/forms/autofocus-attribute.html
+/sdcard/android/layout_tests/fast/forms/add-remove-form-elements-stress-test.html
+/sdcard/android/layout_tests/fast/forms/activate-and-disabled-elements.html
+/sdcard/android/layout_tests/fast/forms/8250.html
+/sdcard/android/layout_tests/fast/forms/4628409.html
+/sdcard/android/layout_tests/fast/forms/11423.html
+/sdcard/android/layout_tests/fast/flexbox/inline-children-crash.html
+/sdcard/android/layout_tests/fast/events/window-load-capture.html
+/sdcard/android/layout_tests/fast/events/submit-reset-nested-bubble.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-submit.html
+/sdcard/android/layout_tests/fast/events/stopPropagation-checkbox.html
+/sdcard/android/layout_tests/fast/events/space-scroll-event.html
+/sdcard/android/layout_tests/fast/events/simulated-key-state.html
+/sdcard/android/layout_tests/fast/events/shadow-boundary-crossing.html
+/sdcard/android/layout_tests/fast/events/selectstart-during-autoscroll.html
+/sdcard/android/layout_tests/fast/events/resize-subframe.html
+/sdcard/android/layout_tests/fast/events/remove-event-listener.html
+/sdcard/android/layout_tests/fast/events/programmatic-check-no-change-event.html
+/sdcard/android/layout_tests/fast/events/overflow-events.html
+/sdcard/android/layout_tests/fast/events/onunload-body-property.html
+/sdcard/android/layout_tests/fast/events/onsubmit-bubbling.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-with-subresource.html
+/sdcard/android/layout_tests/fast/events/onload-after-document-close-no-subresource.html
+/sdcard/android/layout_tests/fast/events/onerror-bubbling.html
+/sdcard/android/layout_tests/fast/events/no-window-load.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-page-leave.html
+/sdcard/android/layout_tests/fast/events/no-blur-on-enter-button.html
+/sdcard/android/layout_tests/fast/events/nested-window-event.html
+/sdcard/android/layout_tests/fast/events/nested-event-remove-node-crash.html
+/sdcard/android/layout_tests/fast/events/mouseup-outside-button.html
+/sdcard/android/layout_tests/fast/events/mousedown_in_scrollbar.html
+/sdcard/android/layout_tests/fast/events/message-port.html
+/sdcard/android/layout_tests/fast/events/message-port-inactive-document.html
+/sdcard/android/layout_tests/fast/events/message-port-deleted-frame.html
+/sdcard/android/layout_tests/fast/events/message-port-deleted-document.html
+/sdcard/android/layout_tests/fast/events/message-port-constructor-for-deleted-document.html
+/sdcard/android/layout_tests/fast/events/message-channel-listener-circular-ownership.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc-3.html
+/sdcard/android/layout_tests/fast/events/message-channel-gc-2.html
+/sdcard/android/layout_tests/fast/events/keypress-removed-node.html
+/sdcard/android/layout_tests/fast/events/keydown-remove-frame.html
+/sdcard/android/layout_tests/fast/events/init-event-null-view.html
+/sdcard/android/layout_tests/fast/events/init-event-after-dispatch.html
+/sdcard/android/layout_tests/fast/events/event-targets.html
+/sdcard/android/layout_tests/fast/events/event-listener-html-non-html-confusion.html
+/sdcard/android/layout_tests/fast/events/event-instanceof.html
+/sdcard/android/layout_tests/fast/events/event-creation.html
+/sdcard/android/layout_tests/fast/events/div-focus.html
+/sdcard/android/layout_tests/fast/events/dispatch-to-handle-event.html
+/sdcard/android/layout_tests/fast/events/delayed-style-mutation-event-crash.html
+/sdcard/android/layout_tests/fast/events/caller-access-from-event-listener.html
+/sdcard/android/layout_tests/fast/events/anchor-empty-focus.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/logical.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/iso-ir-138.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/hebrew.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/csISO88598I.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-i.html
+/sdcard/android/layout_tests/fast/encoding/hebrew/8859-8-e.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/x-euc-cn.html
+/sdcard/android/layout_tests/fast/encoding/gbk/iso-ir-58.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb_2312-80.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gbk.html
+/sdcard/android/layout_tests/fast/encoding/gbk/gb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/EUC-CN.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb231280.html
+/sdcard/android/layout_tests/fast/encoding/gbk/csgb2312.html
+/sdcard/android/layout_tests/fast/encoding/gbk/cn-gb.html
+/sdcard/android/layout_tests/fast/encoding/gbk/close-gbk-converter.html
+/sdcard/android/layout_tests/fast/encoding/gbk/chinese.html
+/sdcard/android/layout_tests/fast/encoding/yahoo-mail.html
+/sdcard/android/layout_tests/fast/encoding/xml-charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-32-little-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-nobom.xml
+/sdcard/android/layout_tests/fast/encoding/utf-32-big-endian-bom.html
+/sdcard/android/layout_tests/fast/encoding/tag-in-title.html
+/sdcard/android/layout_tests/fast/encoding/script-in-head.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-4.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-3.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-xml-2.html
+/sdcard/android/layout_tests/fast/encoding/pseudo-tags-in-attributes.html
+/sdcard/android/layout_tests/fast/encoding/preload-encoding.html
+/sdcard/android/layout_tests/fast/encoding/noscript-in-head.html
+/sdcard/android/layout_tests/fast/encoding/no-charset-on-dynamic-script-load.html
+/sdcard/android/layout_tests/fast/encoding/namespace-tolerance.html
+/sdcard/android/layout_tests/fast/encoding/mispositioned-meta.html
+/sdcard/android/layout_tests/fast/encoding/misplaced-xml-declaration.html
+/sdcard/android/layout_tests/fast/encoding/meta-charset.html
+/sdcard/android/layout_tests/fast/encoding/latin1-winlatin.html
+/sdcard/android/layout_tests/fast/encoding/high-bit-latin1.html
+/sdcard/android/layout_tests/fast/encoding/hanarei-blog32-fc2-com.html
+/sdcard/android/layout_tests/fast/encoding/floraexpress-ru.html
+/sdcard/android/layout_tests/fast/encoding/decoder-allow-null-chars.html
+/sdcard/android/layout_tests/fast/encoding/css-link-charset.html
+/sdcard/android/layout_tests/fast/encoding/css-charset.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-evil.html
+/sdcard/android/layout_tests/fast/encoding/css-charset-dom.html
+/sdcard/android/layout_tests/fast/encoding/charset-xuser-defined.html
+/sdcard/android/layout_tests/fast/encoding/charset-utf16.html
+/sdcard/android/layout_tests/fast/encoding/charset-unicode.html
+/sdcard/android/layout_tests/fast/encoding/charset-invalid.html
+/sdcard/android/layout_tests/fast/encoding/charset-cp1251.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content.html
+/sdcard/android/layout_tests/fast/encoding/bom-in-content-utf16.html
+/sdcard/android/layout_tests/fast/encoding/bandai-co-jp-releases.html
+/sdcard/android/layout_tests/fast/encoding/ahram-org-eg.html
+/sdcard/android/layout_tests/fast/dynamic/subtree-common-root.html
+/sdcard/android/layout_tests/fast/dynamic/style-access-late-stylesheet-load.html
+/sdcard/android/layout_tests/fast/dynamic/recursive-layout.html
+/sdcard/android/layout_tests/fast/dynamic/outerHTML-no-element.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentText.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML.html
+/sdcard/android/layout_tests/fast/dynamic/insertAdjacentHTML-allowed-parents.html
+/sdcard/android/layout_tests/fast/dynamic/inline-to-block-crash.html
+/sdcard/android/layout_tests/fast/dynamic/hovered-detach.html
+/sdcard/android/layout_tests/fast/dynamic/float-remove-above-line.html
+/sdcard/android/layout_tests/fast/dynamic/checkbox-selection-crash.html
+/sdcard/android/layout_tests/fast/dynamic/ancestor-to-absolute.html
+/sdcard/android/layout_tests/fast/dynamic/5872671.html
+/sdcard/android/layout_tests/fast/dom/Window/window-special-properties.html
+/sdcard/android/layout_tests/fast/dom/Window/window-resize-and-move-sub-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-remove-event-listener.html
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing.html
+/sdcard/android/layout_tests/fast/dom/Window/window-property-shadowing-name.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-top.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-self-from-other-frame.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/window-open-parent-no-parent.html
+/sdcard/android/layout_tests/fast/dom/Window/window-object-cross-frame-calls.html
+/sdcard/android/layout_tests/fast/dom/Window/window-location-replace-functions.html
+/sdcard/android/layout_tests/fast/dom/Window/window-function-frame-getter-precedence.html
+/sdcard/android/layout_tests/fast/dom/Window/window-custom-prototype-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-closed-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/window-appendages-cleared.html
+/sdcard/android/layout_tests/fast/dom/Window/setTimeout-no-arguments.html
+/sdcard/android/layout_tests/fast/dom/Window/global-opener-function.html
+/sdcard/android/layout_tests/fast/dom/Window/getMatchedCSSRules-null-crash.html
+/sdcard/android/layout_tests/fast/dom/Window/element-constructors-on-window.html
+/sdcard/android/layout_tests/fast/dom/Window/closure-access-after-navigation-iframe.html
+/sdcard/android/layout_tests/fast/dom/Window/attr-constructor.html
+/sdcard/android/layout_tests/fast/dom/Window/atob-btoa.html
+/sdcard/android/layout_tests/fast/dom/Window/alert-undefined.html
+/sdcard/android/layout_tests/fast/dom/TreeWalker/TreeWalker-currentNode.html
+/sdcard/android/layout_tests/fast/dom/Text/replaceWholeText.html
+/sdcard/android/layout_tests/fast/dom/StyleSheet/ownerNode-lifetime.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/viewless-document.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/not-supported-namespace-in-selector.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/id-fastpath-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/elementRoot.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/dumpNodeList-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/detached-element.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseTag.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/caseID-almost-strict.html
+/sdcard/android/layout_tests/fast/dom/SelectorAPI/bug-17313.html
+/sdcard/android/layout_tests/fast/dom/Range/range-processing-instructions.html
+/sdcard/android/layout_tests/fast/dom/Range/range-modifycontents.html
+/sdcard/android/layout_tests/fast/dom/Range/range-isPointInRange.html
+/sdcard/android/layout_tests/fast/dom/Range/range-intersectsNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-splittext.html
+/sdcard/android/layout_tests/fast/dom/Range/range-insertNode-separate-endContainer.html
+/sdcard/android/layout_tests/fast/dom/Range/range-exceptions.html
+/sdcard/android/layout_tests/fast/dom/Range/range-comparePoint.html
+/sdcard/android/layout_tests/fast/dom/Range/range-compareNode.html
+/sdcard/android/layout_tests/fast/dom/Range/range-clone-empty.html
+/sdcard/android/layout_tests/fast/dom/Range/mutation.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-2.html
+/sdcard/android/layout_tests/fast/dom/Range/compareBoundaryPoints-1.html
+/sdcard/android/layout_tests/fast/dom/Range/acid3-surround-contents.html
+/sdcard/android/layout_tests/fast/dom/Range/13000.html
+/sdcard/android/layout_tests/fast/dom/NodeList/item-by-id-with-no-document.html
+/sdcard/android/layout_tests/fast/dom/NodeList/invalidate-node-lists-when-parsing.html
+/sdcard/android/layout_tests/fast/dom/NodeList/childNodes-reset-cache.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-3.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-2.html
+/sdcard/android/layout_tests/fast/dom/NodeList/5725058-crash-scenario-1.html
+/sdcard/android/layout_tests/fast/dom/Node/initial-values.html
+/sdcard/android/layout_tests/fast/dom/Node/DOMNodeRemovedEvent.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableSectionElement/rows.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/insertCell.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableRowElement/cells.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/tBodies.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/rows.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/insert-row.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-66-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/early-acid3-65-excerpt.html
+/sdcard/android/layout_tests/fast/dom/HTMLTableElement/cellpadding-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-set-string-length.html
+/sdcard/android/layout_tests/fast/dom/HTMLSelectElement/options-collection-detached.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-set-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-reexecution.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-load-events.html
+/sdcard/android/layout_tests/fast/dom/HTMLScriptElement/script-decoding-error-after-setting-src.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/set-option-index-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-text.html
+/sdcard/android/layout_tests/fast/dom/HTMLOptionElement/option-prototype.html
+/sdcard/android/layout_tests/fast/dom/HTMLObjectElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLMetaElement/meta-attributes.html
+/sdcard/android/layout_tests/fast/dom/HTMLLabelElement/form/test1.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/size-as-number.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-text-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-hidden-value.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/input-checked-reset.html
+/sdcard/android/layout_tests/fast/dom/HTMLInputElement/checked-pseudo-selector.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-without-renderer-width.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-src-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-natural-width-height.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-lowsrc-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-longdesc-absolute-url.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/image-loading-gc.html
+/sdcard/android/layout_tests/fast/dom/HTMLImageElement/constructor-mutation-event-dispatch.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/set-version.html
+/sdcard/android/layout_tests/fast/dom/HTMLHtmlElement/duplicate-html-element-crash.html
+/sdcard/android/layout_tests/fast/dom/HTMLHeadElement/head-check.html
+/sdcard/android/layout_tests/fast/dom/HTMLFormElement/elements-not-in-document.html
+/sdcard/android/layout_tests/fast/dom/HTMLFontElement/size-attribute.html
+/sdcard/android/layout_tests/fast/dom/HTMLElement/set-inner-outer-optimization.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/writeln-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-multiple-calls.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/write-call.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/url-getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-set.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/title-get.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-unknown-child-element.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/object-by-name-or-id.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-special-properties.html
+/sdcard/android/layout_tests/fast/dom/HTMLDocument/document-plugins.html
+/sdcard/android/layout_tests/fast/dom/HTMLDivElement/align/getset.html
+/sdcard/android/layout_tests/fast/dom/HTMLButtonElement/value/getset.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/array/001.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/dumpNodeList.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/015.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/014.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/013.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/012.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/009.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/008.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/007.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/006.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/005.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/004.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/003.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/002.html
+/sdcard/android/layout_tests/fast/dom/getElementsByClassName/001.html
+/sdcard/android/layout_tests/fast/dom/EntityReference/readonly-exceptions.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-with-colon.html
+/sdcard/android/layout_tests/fast/dom/Element/setAttribute-case-insensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/onclick-case.html
+/sdcard/android/layout_tests/fast/dom/Element/offsetTop-table-cell.html
+/sdcard/android/layout_tests/fast/dom/Element/getAttribute-check-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/Element/element-traversal.html
+/sdcard/android/layout_tests/fast/dom/Element/dimension-properties-unrendered.html
+/sdcard/android/layout_tests/fast/dom/Element/contains-method.html
+/sdcard/android/layout_tests/fast/dom/Element/attribute-uppercase.html
+/sdcard/android/layout_tests/fast/dom/Element/attr-param-typechecking.html
+/sdcard/android/layout_tests/fast/dom/DOMImplementation/createDocumentType-err.html
+/sdcard/android/layout_tests/fast/dom/DOMException/RangeException.html
+/sdcard/android/layout_tests/fast/dom/DOMException/prototype-object.html
+/sdcard/android/layout_tests/fast/dom/DOMException/EventException.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-set-multiple-times.html
+/sdcard/android/layout_tests/fast/dom/Document/title-property-creates-title-element.html
+/sdcard/android/layout_tests/fast/dom/Document/replaceChild-null-oldChild.html
+/sdcard/android/layout_tests/fast/dom/Document/replace-child.html
+/sdcard/android/layout_tests/fast/dom/Document/open-with-pending-load.html
+/sdcard/android/layout_tests/fast/dom/Document/document-reopen.html
+/sdcard/android/layout_tests/fast/dom/Document/document-charset.html
+/sdcard/android/layout_tests/fast/dom/Document/doc-open-while-parsing.html
+/sdcard/android/layout_tests/fast/dom/Document/createElementNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/Document/createAttributeNS-namespace-err.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/transition-property-names.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/empty-string-property.html
+/sdcard/android/layout_tests/fast/dom/CSSStyleDeclaration/css-properties-case-sensitive.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype2.html
+/sdcard/android/layout_tests/fast/dom/XMLSerializer-doctype.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-invalid-values.html
+/sdcard/android/layout_tests/fast/dom/xmlhttprequest-html-response-encoding.html
+/sdcard/android/layout_tests/fast/dom/wrapper-identity.html
+/sdcard/android/layout_tests/fast/dom/undetectable-style-filter.html
+/sdcard/android/layout_tests/fast/dom/undetectable-document-all.html
+/sdcard/android/layout_tests/fast/dom/title-text-property.html
+/sdcard/android/layout_tests/fast/dom/title-text-property-2.html
+/sdcard/android/layout_tests/fast/dom/timer-clear-interval-in-handler.html
+/sdcard/android/layout_tests/fast/dom/space-to-text.html
+/sdcard/android/layout_tests/fast/dom/setAttributeNS.html
+/sdcard/android/layout_tests/fast/dom/setAttribute-using-initial-input-value.html
+/sdcard/android/layout_tests/fast/dom/set-inner-text-newlines.html
+/sdcard/android/layout_tests/fast/dom/serialize-cdata.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-multiple.html
+/sdcard/android/layout_tests/fast/dom/select-selectedIndex-bug-12942.html
+/sdcard/android/layout_tests/fast/dom/script-element-without-frame-crash.html
+/sdcard/android/layout_tests/fast/dom/script-element-remove-self.html
+/sdcard/android/layout_tests/fast/dom/script-element-gc.html
+/sdcard/android/layout_tests/fast/dom/script-add.html
+/sdcard/android/layout_tests/fast/dom/resource-locations-in-created-html-document.html
+/sdcard/android/layout_tests/fast/dom/replace-first-child.html
+/sdcard/android/layout_tests/fast/dom/replace-child-siblings.html
+/sdcard/android/layout_tests/fast/dom/remove-style-element.html
+/sdcard/android/layout_tests/fast/dom/remove-named-attribute-crash.html
+/sdcard/android/layout_tests/fast/dom/Range-insertNode-crash.html
+/sdcard/android/layout_tests/fast/dom/prototypes.html
+/sdcard/android/layout_tests/fast/dom/prototype-chain.html
+/sdcard/android/layout_tests/fast/dom/plugin-attributes-enumeration.html
+/sdcard/android/layout_tests/fast/dom/outerText-no-element.html
+/sdcard/android/layout_tests/fast/dom/option-properties.html
+/sdcard/android/layout_tests/fast/dom/objc-big-method-name.html
+/sdcard/android/layout_tests/fast/dom/null-document-xmlhttprequest-open.html
+/sdcard/android/layout_tests/fast/dom/location-assign.html
+/sdcard/android/layout_tests/fast/dom/javascript-backslash.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-nbsp.html
+/sdcard/android/layout_tests/fast/dom/innerHTML-escaping-attribute.html
+/sdcard/android/layout_tests/fast/dom/inner-width-height.html
+/sdcard/android/layout_tests/fast/dom/inner-text-with-no-renderer.html
+/sdcard/android/layout_tests/fast/dom/inner-text-rtl.html
+/sdcard/android/layout_tests/fast/dom/importNode-prefix.html
+/sdcard/android/layout_tests/fast/dom/importNode-null.html
+/sdcard/android/layout_tests/fast/dom/import-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/import-attribute-node.html
+/sdcard/android/layout_tests/fast/dom/implementation-createHTMLDocument.html
+/sdcard/android/layout_tests/fast/dom/ImageDocument-image-deletion.html
+/sdcard/android/layout_tests/fast/dom/image-object.html
+/sdcard/android/layout_tests/fast/dom/iframe-document.html
+/sdcard/android/layout_tests/fast/dom/iframe-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/html-attribute-types.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object2.html
+/sdcard/android/layout_tests/fast/dom/getter-on-window-object.html
+/sdcard/android/layout_tests/fast/dom/getelementbyname-invalidation.html
+/sdcard/android/layout_tests/fast/dom/generic-form-element-assert.html
+/sdcard/android/layout_tests/fast/dom/gc-7.html
+/sdcard/android/layout_tests/fast/dom/gc-6.html
+/sdcard/android/layout_tests/fast/dom/gc-5.html
+/sdcard/android/layout_tests/fast/dom/gc-4.html
+/sdcard/android/layout_tests/fast/dom/gc-3.html
+/sdcard/android/layout_tests/fast/dom/gc-2.html
+/sdcard/android/layout_tests/fast/dom/gc-11.html
+/sdcard/android/layout_tests/fast/dom/gc-1.html
+/sdcard/android/layout_tests/fast/dom/frame-contentWindow-crash.html
+/sdcard/android/layout_tests/fast/dom/features.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-timeout-crash.html
+/sdcard/android/layout_tests/fast/dom/exception-no-frame-inline-script-crash.html
+/sdcard/android/layout_tests/fast/dom/everything-to-string.html
+/sdcard/android/layout_tests/fast/dom/element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/early-frame-url.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids.html
+/sdcard/android/layout_tests/fast/dom/duplicate-ids-document-order.html
+/sdcard/android/layout_tests/fast/dom/DOMParser-assign-variable.html
+/sdcard/android/layout_tests/fast/dom/domListEnumeration.html
+/sdcard/android/layout_tests/fast/dom/dom-instanceof.html
+/sdcard/android/layout_tests/fast/dom/documenturi-loses-to-base-tag.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-relative-urls-do-not-resolve.html
+/sdcard/android/layout_tests/fast/dom/documenturi-assigned-junk-implies-baseuri-null.html
+/sdcard/android/layout_tests/fast/dom/documenturi-affects-relative-paths.html
+/sdcard/android/layout_tests/fast/dom/documentElement-null.html
+/sdcard/android/layout_tests/fast/dom/document-scripts.html
+/sdcard/android/layout_tests/fast/dom/document-dir-property.html
+/sdcard/android/layout_tests/fast/dom/document-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/document-all-select.html
+/sdcard/android/layout_tests/fast/dom/document-all-input.html
+/sdcard/android/layout_tests/fast/dom/dir-no-body.html
+/sdcard/android/layout_tests/fast/dom/destroy-selected-radio-button-crash.html
+/sdcard/android/layout_tests/fast/dom/defaultView.html
+/sdcard/android/layout_tests/fast/dom/css-shortHands.html
+/sdcard/android/layout_tests/fast/dom/css-set-property-exception.html
+/sdcard/android/layout_tests/fast/dom/css-selectorText.html
+/sdcard/android/layout_tests/fast/dom/css-RGBValue.html
+/sdcard/android/layout_tests/fast/dom/css-mediarule-functions.html
+/sdcard/android/layout_tests/fast/dom/css-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read.html
+/sdcard/android/layout_tests/fast/dom/css-dom-read-2.html
+/sdcard/android/layout_tests/fast/dom/createElementNS.html
+/sdcard/android/layout_tests/fast/dom/createElement.html
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.xml
+/sdcard/android/layout_tests/fast/dom/createElement-with-column.html
+/sdcard/android/layout_tests/fast/dom/createDocumentType2.html
+/sdcard/android/layout_tests/fast/dom/createDocument.html
+/sdcard/android/layout_tests/fast/dom/createDocument-empty.html
+/sdcard/android/layout_tests/fast/dom/createAttribute-exception.html
+/sdcard/android/layout_tests/fast/dom/constructors-overriding.html
+/sdcard/android/layout_tests/fast/dom/constants.html
+/sdcard/android/layout_tests/fast/dom/computed-style-set-property.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Strict.html
+/sdcard/android/layout_tests/fast/dom/compatMode-Compat.html
+/sdcard/android/layout_tests/fast/dom/compatMode-AlmostStrict.html
+/sdcard/android/layout_tests/fast/dom/comment-dom-node.html
+/sdcard/android/layout_tests/fast/dom/comment-document-fragment.html
+/sdcard/android/layout_tests/fast/dom/collection-null-like-arguments.html
+/sdcard/android/layout_tests/fast/dom/collection-namedItem-via-item.html
+/sdcard/android/layout_tests/fast/dom/clone-node-style.html
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements.html
+/sdcard/android/layout_tests/fast/dom/clone-node-form-elements-with-attr.html
+/sdcard/android/layout_tests/fast/dom/class-all-whitespace.html
+/sdcard/android/layout_tests/fast/dom/capturing-event-listeners.html
+/sdcard/android/layout_tests/fast/dom/canvasContext2d-element-attribute-js-null.html
+/sdcard/android/layout_tests/fast/dom/background-shorthand-csstext.html
+/sdcard/android/layout_tests/fast/dom/attribute-namespaces-get-set.html
+/sdcard/android/layout_tests/fast/dom/attribute-empty-value-no-children.html
+/sdcard/android/layout_tests/fast/dom/attribute-downcast-right.html
+/sdcard/android/layout_tests/fast/dom/attribute-case-sensitivity.html
+/sdcard/android/layout_tests/fast/dom/array-special-accessors-should-ignore-items.html
+/sdcard/android/layout_tests/fast/dom/anchor-toString.html
+/sdcard/android/layout_tests/fast/dom/anchor-backslash.html
+/sdcard/android/layout_tests/fast/doctypes/html-doctype.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-parsing.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-in-element.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-at-end.html
+/sdcard/android/layout_tests/fast/doctypes/doctype-after-comment.html
+/sdcard/android/layout_tests/fast/doctypes/005-case-preserving.html
+/sdcard/android/layout_tests/fast/css-generated-content/reset-content-to-initial.html
+/sdcard/android/layout_tests/fast/css-generated-content/empty-content-with-float-crash.html
+/sdcard/android/layout_tests/fast/css/variables/invalid-identifier.html
+/sdcard/android/layout_tests/fast/css/counters/counter-number-input.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input.html
+/sdcard/android/layout_tests/fast/css/counters/counter-function-input-2.html
+/sdcard/android/layout_tests/fast/css/word-break-user-modify-allowed-values.html
+/sdcard/android/layout_tests/fast/css/transition_shorthand_parsing.html
+/sdcard/android/layout_tests/fast/css/transition-timing-function.html
+/sdcard/android/layout_tests/fast/css/transform-function-lowercase-assert.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-2.html
+/sdcard/android/layout_tests/fast/css/stale-style-selector-crash-1.html
+/sdcard/android/layout_tests/fast/css/sheet-title.html
+/sdcard/android/layout_tests/fast/css/remove-shorthand.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-005.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-004.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-003.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-002.html
+/sdcard/android/layout_tests/fast/css/readonly-pseudoclass-opera-001.html
+/sdcard/android/layout_tests/fast/css/pseudostyle-anonymous-text.html
+/sdcard/android/layout_tests/fast/css/parse-timing-function-crash.html
+/sdcard/android/layout_tests/fast/css/padding-no-renderer.html
+/sdcard/android/layout_tests/fast/css/overflow-property.html
+/sdcard/android/layout_tests/fast/css/outline-hidden-illegal-value.html
+/sdcard/android/layout_tests/fast/css/orphaned_units_crash.html
+/sdcard/android/layout_tests/fast/css/nested-rule-parent-sheet.html
+/sdcard/android/layout_tests/fast/css/min-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/media-rule-dyn.html
+/sdcard/android/layout_tests/fast/css/max-height-and-max-width.html
+/sdcard/android/layout_tests/fast/css/max-device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/legacy-opacity-styles.html
+/sdcard/android/layout_tests/fast/css/invalid-rule-value.html
+/sdcard/android/layout_tests/fast/css/invalid-cursor-property-crash.html
+/sdcard/android/layout_tests/fast/css/insertRule-media.html
+/sdcard/android/layout_tests/fast/css/insertRule-font-face.html
+/sdcard/android/layout_tests/fast/css/import-style-update.html
+/sdcard/android/layout_tests/fast/css/hexColor-isDigit-assert.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-clip.html
+/sdcard/android/layout_tests/fast/css/getPropertyValue-border.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-zIndex-auto.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-relayout.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-borderRadius.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-spacing.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-image.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-border-box.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-size.html
+/sdcard/android/layout_tests/fast/css/getComputedStyle-background-position.html
+/sdcard/android/layout_tests/fast/css/font-property-priority.html
+/sdcard/android/layout_tests/fast/css/font-family-initial.html
+/sdcard/android/layout_tests/fast/css/font-face-multiple-families.html
+/sdcard/android/layout_tests/fast/css/font-face-descriptor-multiple-values-parsing.html
+/sdcard/android/layout_tests/fast/css/emptyStyleTag.html
+/sdcard/android/layout_tests/fast/css/empty-script.html
+/sdcard/android/layout_tests/fast/css/display-none-inline-style-change-crash.html
+/sdcard/android/layout_tests/fast/css/device-aspect-ratio.html
+/sdcard/android/layout_tests/fast/css/dashboard-regions-attr-crash.html
+/sdcard/android/layout_tests/fast/css/CSSPrimitiveValue-exceptions.html
+/sdcard/android/layout_tests/fast/css/css-selector-text.html
+/sdcard/android/layout_tests/fast/css/css-properties-case-insensitive.html
+/sdcard/android/layout_tests/fast/css/computed-style-negative-top.html
+/sdcard/android/layout_tests/fast/css/computed-style-display-none.html
+/sdcard/android/layout_tests/fast/css/child-selector-implicit-tbody.html
+/sdcard/android/layout_tests/fast/css/case-transform.html
+/sdcard/android/layout_tests/fast/css/border-image-crash.html
+/sdcard/android/layout_tests/fast/css/background-position-serialize.html
+/sdcard/android/layout_tests/fast/css/background-position-inherit.html
+/sdcard/android/layout_tests/fast/css/background-currentcolor.html
+/sdcard/android/layout_tests/fast/cookies/local-file-can-set-cookies.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-4.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-3.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-2.html
+/sdcard/android/layout_tests/fast/canvas/unclosed-canvas-1.html
+/sdcard/android/layout_tests/fast/canvas/toDataURL-noData.html
+/sdcard/android/layout_tests/fast/canvas/script-inside-canvas-fallback.html
+/sdcard/android/layout_tests/fast/canvas/radialGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/pointInPath.html
+/sdcard/android/layout_tests/fast/canvas/linearGradient-infinite-values.html
+/sdcard/android/layout_tests/fast/canvas/pattern-with-transform.html
+/sdcard/android/layout_tests/fast/canvas/gradient-with-clip.html
+/sdcard/android/layout_tests/fast/canvas/gradient-addColorStop-with-invalid-color.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-negative-source-destination.html
+/sdcard/android/layout_tests/fast/canvas/drawImage-with-invalid-args.html
+/sdcard/android/layout_tests/fast/canvas/create-pattern-does-not-crash.html
+/sdcard/android/layout_tests/fast/canvas/canvas-with-incorrect-args.html
+/sdcard/android/layout_tests/fast/canvas/canvas-putImageData.html
+/sdcard/android/layout_tests/fast/canvas/canvas-pattern-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/canvas-path-with-inf-nan-dimensions.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-strokestyle.html
+/sdcard/android/layout_tests/fast/canvas/canvas-invalid-fillstyle.html
+/sdcard/android/layout_tests/fast/canvas/canvas-ImageData-behaviour.html
+/sdcard/android/layout_tests/fast/canvas/canvas-hides-fallback.html
+/sdcard/android/layout_tests/fast/canvas/arc-crash.html
+/sdcard/android/layout_tests/fast/canvas/access-zero-sized-canvas.html
diff --git a/tests/DumpRenderTree/run_layout_tests.py b/tests/DumpRenderTree/run_layout_tests.py
new file mode 100755
index 0000000..433271e
--- /dev/null
+++ b/tests/DumpRenderTree/run_layout_tests.py
@@ -0,0 +1,274 @@
+#!/usr/bin/python
+
+"""Run layout tests using Android emulator and instrumentation.
+
+ First, you need to get an SD card or sdcard image that has layout tests on it.
+ Layout tests are in following directory:
+ /sdcard/android/layout_tests
+ For example, /sdcard/android/layout_tests/fast
+
+ Usage:
+ Run all tests under fast/ directory:
+ run_layout_tests.py, or
+ run_layout_tests.py fast
+
+ Run all tests under a sub directory:
+ run_layout_tests.py fast/dom
+
+ Run a single test:
+ run_layout_tests.py fast/dom/
+
+ After a merge, if there are changes of layout tests in SD card, you need to
+ use --refresh-test-list option *once* to re-generate test list on the card.
+
+ Some other options are:
+ --time-out-ms (default is 8000 millis) for each test
+ --adb-options="-e" passes option string to adb
+ --results-directory=..., (default is ./layout-test-results) directory name under which results are stored.
+"""
+
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import time
+
+def CountLineNumber(filename):
+ """Compute the number of lines in a given file.
+
+ Args:
+ filename: a file name related to the current directory.
+ """
+
+ fp = open(os.path.abspath(filename), "r");
+ lines = 0
+ for line in fp.readlines():
+ lines = lines + 1
+ fp.close()
+ return lines
+
+def DumpRenderTreeFinished(adb_cmd):
+ """ Check if DumpRenderTree finished running tests
+
+ Args:
+ output: adb_cmd string
+ """
+
+ # pull /sdcard/running_test.txt, if the content is "#DONE", it's done
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ return adb_output.strip() == "#DONE"
+
+def DiffResults(marker, new_results, old_results, diff_results, strip_reason):
+ """ Given two result files, generate diff and
+ write to diff_results file. All arguments are absolute paths
+ to files.
+ """
+ old_file = open(old_results, "r")
+ new_file = open(new_results, "r")
+ diff_file = open(diff_results, "a")
+
+ # Read lines from each file
+ ndict = new_file.readlines()
+ cdict = old_file.readlines()
+
+ # Write marker to diff file
+ diff_file.writelines(marker + "\n")
+ diff_file.writelines("###############\n")
+
+ # Strip reason from result lines
+ if strip_reason is True:
+ for i in range(0, len(ndict)):
+ ndict[i] = ndict[i].split(' ')[0] + "\n"
+ for i in range(0, len(cdict)):
+ cdict[i] = cdict[i].split(' ')[0] + "\n"
+
+ # Find results in new_results missing in old_results
+ new_count=0
+ for line in ndict:
+ if line not in cdict:
+ diff_file.writelines("+ " + line)
+ new_count += 1
+
+ # Find results in old_results missing in new_results
+ missing_count=0
+ for line in cdict:
+ if line not in ndict:
+ diff_file.writelines("- " + line)
+ missing_count += 1
+
+ logging.info(marker + " >>> " + str(new_count) + " new, " + str(missing_count) + " misses")
+
+ diff_file.writelines("\n\n")
+
+ old_file.close()
+ new_file.close()
+ diff_file.close()
+ return
+
+def CompareResults(ref_dir, results_dir):
+ """Compare results in two directories
+
+ Args:
+ ref_dir: the reference directory having layout results as references
+ results_dir: the results directory
+ """
+ logging.info("Comparing results to " + ref_dir)
+
+ diff_result = os.path.join(results_dir, "layout_tests_diff.txt")
+ if os.path.exists(diff_result):
+ os.remove(diff_result)
+
+ files=["passed", "failed", "nontext", "crashed"]
+ for f in files:
+ result_file_name = "layout_tests_" + f + ".txt"
+ DiffResults(f, os.path.join(results_dir, result_file_name),
+ os.path.join(ref_dir, result_file_name), diff_result,
+ f == "failed")
+ logging.info("Detailed diffs are in " + diff_result)
+
+def main(options, args):
+ """Run the tests. Will call sys.exit when complete.
+
+ Args:
+ options: a dictionary of command line options
+ args: a list of sub directories or files to test
+ """
+
+ # Set up logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format='%(message)s')
+
+ # Include all tests if none are specified.
+ if not args:
+ path = 'fast';
+ else:
+ path = ' '.join(args);
+
+ adb_cmd = "adb ";
+ if options.adb_options:
+ adb_cmd += options.adb_options
+
+ # Re-generate the test list if --refresh-test-list is on
+ if options.refresh_test_list:
+ logging.info("Generating test list.");
+ shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#generateTestList -e path fast -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+ if adb_output.find('Process crashed') != -1:
+ logging.info("Aborting because cannot generate test list.\n" + adb_output)
+ sys.exit(1)
+
+
+ logging.info("Running tests")
+
+ # Count crashed tests.
+ crashed_tests = []
+
+ timeout_ms = '8000'
+ if options.time_out_ms:
+ timeout_ms = options.time_out_ms
+
+ # Run test until it's done
+
+ # Call LayoutTestsAutoTest::startLayoutTests.
+ shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#startLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ while not DumpRenderTreeFinished(adb_cmd):
+ # Get the running_test.txt
+ logging.error("DumpRenderTree crashed, output:\n" + adb_output)
+
+ shell_cmd_str = adb_cmd + " shell cat /sdcard/running_test.txt"
+ crashed_test = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE).communicate()[0]
+
+ logging.info(crashed_test + " CRASHED");
+ crashed_tests.append(crashed_test);
+
+ logging.info("Resuming layout test runner...");
+ # Call LayoutTestsAutoTest::resumeLayoutTests
+ shell_cmd_str = adb_cmd + " shell am instrument -e class com.android.dumprendertree.LayoutTestsAutoTest#resumeLayoutTests -e path \"" + path + "\" -e timeout " + timeout_ms + " -w com.android.dumprendertree/.LayoutTestsAutoRunner"
+
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+
+ if adb_output.find('INSTRUMENTATION_FAILED') != -1:
+ logging.error("Error happened : " + adb_output)
+ sys.exit(1)
+
+ logging.debug(adb_output);
+ logging.info("Done\n");
+
+ # Pull results from /sdcard
+ results_dir = options.results_directory
+ if not os.path.exists(results_dir):
+ os.makedirs(results_dir)
+ if not os.path.isdir(results_dir):
+ logging.error("Cannot create results dir: " + results_dir);
+ sys.exit(1);
+
+ result_files = ["/sdcard/layout_tests_passed.txt",
+ "/sdcard/layout_tests_failed.txt",
+ "/sdcard/layout_tests_nontext.txt"]
+ for file in result_files:
+ shell_cmd_str = adb_cmd + " pull " + file + " " + results_dir
+ adb_output = subprocess.Popen(shell_cmd_str, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
+ logging.debug(adb_output)
+
+ # Create the crash list.
+ fp = open(results_dir + "/layout_tests_crashed.txt", "w");
+ fp.writelines(crashed_tests)
+ fp.close()
+
+ # Count the number of tests in each category.
+ passed_tests = CountLineNumber(results_dir + "/layout_tests_passed.txt")
+ logging.info(str(passed_tests) + " passed")
+ failed_tests = CountLineNumber(results_dir + "/layout_tests_failed.txt")
+ logging.info(str(failed_tests) + " failed")
+ crashed_tests = CountLineNumber(results_dir + "/layout_tests_crashed.txt")
+ logging.info(str(crashed_tests) + " crashed")
+ nontext_tests = CountLineNumber(results_dir + "/layout_tests_nontext.txt")
+ logging.info(str(nontext_tests) + " no dumpAsText")
+
+ logging.info("Results are stored under: " + results_dir + "\n")
+
+ # Comparing results to references to find new fixes and regressions.
+ results_dir = os.path.abspath(options.results_directory)
+ ref_dir = options.ref_directory
+
+ # if ref_dir is null, cannonify ref_dir to the script dir.
+ if not ref_dir:
+ script_self = sys.argv[0]
+ script_dir = os.path.dirname(script_self)
+ ref_dir = os.path.join(script_dir, "results")
+
+ ref_dir = os.path.abspath(ref_dir)
+
+ CompareResults(ref_dir, results_dir)
+
+if '__main__' == __name__:
+ option_parser = optparse.OptionParser()
+ option_parser.add_option("", "--time-out-ms",
+ default=None,
+ help="set the timeout for each test")
+ option_parser.add_option("", "--verbose", action="store_true",
+ default=False,
+ help="include debug-level logging")
+ option_parser.add_option("", "--refresh-test-list", action="store_true",
+ default=False,
+ help="re-generate test list, it may take some time.")
+ option_parser.add_option("", "--adb-options",
+ default=None,
+ help="pass options to adb, such as -d -e, etc");
+ option_parser.add_option("", "--results-directory",
+ default="layout-test-results",
+ help="directory which results are stored.")
+ option_parser.add_option("", "--ref-directory",
+ default=None,
+ dest="ref_directory",
+ help="directory where reference results are stored.")
+
+ options, args = option_parser.parse_args();
+ main(options, args)
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
new file mode 100644
index 0000000..a389461
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/CallbackProxy.java
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.os.Handler;
+import android.os.Message;
+
+import java.util.HashMap;
+
+public class CallbackProxy extends Handler implements EventSender, LayoutTestController {
+
+ private EventSender mEventSender;
+ private LayoutTestController mLayoutTestController;
+
+ private static final int EVENT_DOM_LOG = 1;
+ private static final int EVENT_FIRE_KBD = 2;
+ private static final int EVENT_KEY_DOWN_1 = 3;
+ private static final int EVENT_KEY_DOWN_2 = 4;
+ private static final int EVENT_LEAP = 5;
+ private static final int EVENT_MOUSE_CLICK = 6;
+ private static final int EVENT_MOUSE_DOWN = 7;
+ private static final int EVENT_MOUSE_MOVE = 8;
+ private static final int EVENT_MOUSE_UP = 9;
+
+ private static final int LAYOUT_CLEAR_LIST = 20;
+ private static final int LAYOUT_DISPLAY = 21;
+ private static final int LAYOUT_DUMP_TEXT = 22;
+ private static final int LAYOUT_DUMP_HISTORY = 23;
+ private static final int LAYOUT_DUMP_CHILD_SCROLL = 24;
+ private static final int LAYOUT_DUMP_EDIT_CB = 25;
+ private static final int LAYOUT_DUMP_SEL_RECT = 26;
+ private static final int LAYOUT_DUMP_TITLE_CHANGES = 27;
+ private static final int LAYOUT_KEEP_WEB_HISTORY = 28;
+ private static final int LAYOUT_NOTIFY_DONE = 29;
+ private static final int LAYOUT_QUEUE_BACK_NAV = 30;
+ private static final int LAYOUT_QUEUE_FWD_NAV = 31;
+ private static final int LAYOUT_QUEUE_LOAD = 32;
+ private static final int LAYOUT_QUEUE_RELOAD = 33;
+ private static final int LAYOUT_QUEUE_SCRIPT = 34;
+ private static final int LAYOUT_REPAINT_HORZ = 35;
+ private static final int LAYOUT_SET_ACCEPT_EDIT = 36;
+ private static final int LAYOUT_MAIN_FIRST_RESP = 37;
+ private static final int LAYOUT_SET_WINDOW_KEY = 38;
+ private static final int LAYOUT_TEST_REPAINT = 39;
+ private static final int LAYOUT_WAIT_UNTIL_DONE = 40;
+
+ CallbackProxy(EventSender eventSender,
+ LayoutTestController layoutTestController) {
+ mEventSender = eventSender;
+ mLayoutTestController = layoutTestController;
+ }
+
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_DOM_LOG:
+ mEventSender.enableDOMUIEventLogging(msg.arg1);
+ break;
+ case EVENT_FIRE_KBD:
+ mEventSender.fireKeyboardEventsToElement(msg.arg1);
+ break;
+ case EVENT_KEY_DOWN_1:
+ HashMap map = (HashMap) msg.obj;
+ mEventSender.keyDown((String) map.get("character"),
+ (String[]) map.get("withModifiers"));
+ break;
+
+ case EVENT_KEY_DOWN_2:
+ mEventSender.keyDown((String)msg.obj);
+ break;
+
+ case EVENT_LEAP:
+ mEventSender.leapForward(msg.arg1);
+ break;
+
+ case EVENT_MOUSE_CLICK:
+ mEventSender.mouseClick();
+ break;
+
+ case EVENT_MOUSE_DOWN:
+ mEventSender.mouseDown();
+ break;
+
+ case EVENT_MOUSE_MOVE:
+ mEventSender.mouseMoveTo(msg.arg1, msg.arg2);
+ break;
+
+ case EVENT_MOUSE_UP:
+ mEventSender.mouseUp();
+ break;
+
+ case LAYOUT_CLEAR_LIST:
+ mLayoutTestController.clearBackForwardList();
+ break;
+
+ case LAYOUT_DISPLAY:
+ mLayoutTestController.display();
+ break;
+
+ case LAYOUT_DUMP_TEXT:
+ mLayoutTestController.dumpAsText();
+ break;
+
+ case LAYOUT_DUMP_HISTORY:
+ mLayoutTestController.dumpBackForwardList();
+ break;
+
+ case LAYOUT_DUMP_CHILD_SCROLL:
+ mLayoutTestController.dumpChildFrameScrollPositions();
+ break;
+
+ case LAYOUT_DUMP_EDIT_CB:
+ mLayoutTestController.dumpEditingCallbacks();
+ break;
+
+ case LAYOUT_DUMP_SEL_RECT:
+ mLayoutTestController.dumpSelectionRect();
+ break;
+
+ case LAYOUT_DUMP_TITLE_CHANGES:
+ mLayoutTestController.dumpTitleChanges();
+ break;
+
+ case LAYOUT_KEEP_WEB_HISTORY:
+ mLayoutTestController.keepWebHistory();
+ break;
+
+ case LAYOUT_NOTIFY_DONE:
+ mLayoutTestController.notifyDone();
+ break;
+
+ case LAYOUT_QUEUE_BACK_NAV:
+ mLayoutTestController.queueBackNavigation(msg.arg1);
+ break;
+
+ case LAYOUT_QUEUE_FWD_NAV:
+ mLayoutTestController.queueForwardNavigation(msg.arg1);
+ break;
+
+ case LAYOUT_QUEUE_LOAD:
+ HashMap<String, String> loadMap =
+ (HashMap<String, String>) msg.obj;
+ mLayoutTestController.queueLoad(loadMap.get("Url"),
+ loadMap.get("frameTarget"));
+ break;
+
+ case LAYOUT_QUEUE_RELOAD:
+ mLayoutTestController.queueReload();
+ break;
+
+ case LAYOUT_QUEUE_SCRIPT:
+ mLayoutTestController.queueScript((String)msg.obj);
+ break;
+
+ case LAYOUT_REPAINT_HORZ:
+ mLayoutTestController.repaintSweepHorizontally();
+ break;
+
+ case LAYOUT_SET_ACCEPT_EDIT:
+ mLayoutTestController.setAcceptsEditing(
+ msg.arg1 == 1 ? true : false);
+ break;
+ case LAYOUT_MAIN_FIRST_RESP:
+ mLayoutTestController.setMainFrameIsFirstResponder(
+ msg.arg1 == 1 ? true : false);
+ break;
+
+ case LAYOUT_SET_WINDOW_KEY:
+ mLayoutTestController.setWindowIsKey(
+ msg.arg1 == 1 ? true : false);
+ break;
+
+ case LAYOUT_TEST_REPAINT:
+ mLayoutTestController.testRepaint();
+ break;
+
+ case LAYOUT_WAIT_UNTIL_DONE:
+ mLayoutTestController.waitUntilDone();
+ break;
+ }
+ }
+
+ // EventSender Methods
+
+ public void enableDOMUIEventLogging(int DOMNode) {
+ obtainMessage(EVENT_DOM_LOG, DOMNode, 0).sendToTarget();
+ }
+
+ public void fireKeyboardEventsToElement(int DOMNode) {
+ obtainMessage(EVENT_FIRE_KBD, DOMNode, 0).sendToTarget();
+ }
+
+ public void keyDown(String character, String[] withModifiers) {
+ // TODO Auto-generated method stub
+ HashMap map = new HashMap();
+ map.put("character", character);
+ map.put("withModifiers", withModifiers);
+ obtainMessage(EVENT_KEY_DOWN_1, map).sendToTarget();
+ }
+
+ public void keyDown(String character) {
+ obtainMessage(EVENT_KEY_DOWN_2, character).sendToTarget();
+ }
+
+ public void leapForward(int milliseconds) {
+ obtainMessage(EVENT_LEAP, milliseconds, 0).sendToTarget();
+ }
+
+ public void mouseClick() {
+ obtainMessage(EVENT_MOUSE_CLICK).sendToTarget();
+ }
+
+ public void mouseDown() {
+ obtainMessage(EVENT_MOUSE_DOWN).sendToTarget();
+ }
+
+ public void mouseMoveTo(int X, int Y) {
+ obtainMessage(EVENT_MOUSE_MOVE, X, Y).sendToTarget();
+ }
+
+ public void mouseUp() {
+ obtainMessage(EVENT_MOUSE_UP).sendToTarget();
+ }
+
+ // LayoutTestController Methods
+
+ public void clearBackForwardList() {
+ obtainMessage(LAYOUT_CLEAR_LIST).sendToTarget();
+ }
+
+ public void display() {
+ obtainMessage(LAYOUT_DISPLAY).sendToTarget();
+ }
+
+ public void dumpAsText() {
+ obtainMessage(LAYOUT_DUMP_TEXT).sendToTarget();
+ }
+
+ public void dumpBackForwardList() {
+ obtainMessage(LAYOUT_DUMP_HISTORY).sendToTarget();
+ }
+
+ public void dumpChildFrameScrollPositions() {
+ obtainMessage(LAYOUT_DUMP_CHILD_SCROLL).sendToTarget();
+ }
+
+ public void dumpEditingCallbacks() {
+ obtainMessage(LAYOUT_DUMP_EDIT_CB).sendToTarget();
+ }
+
+ public void dumpSelectionRect() {
+ obtainMessage(LAYOUT_DUMP_SEL_RECT).sendToTarget();
+ }
+
+ public void dumpTitleChanges() {
+ obtainMessage(LAYOUT_DUMP_TITLE_CHANGES).sendToTarget();
+ }
+
+ public void keepWebHistory() {
+ obtainMessage(LAYOUT_KEEP_WEB_HISTORY).sendToTarget();
+ }
+
+ public void notifyDone() {
+ obtainMessage(LAYOUT_NOTIFY_DONE).sendToTarget();
+ }
+
+ public void queueBackNavigation(int howfar) {
+ obtainMessage(LAYOUT_QUEUE_BACK_NAV, howfar, 0).sendToTarget();
+ }
+
+ public void queueForwardNavigation(int howfar) {
+ obtainMessage(LAYOUT_QUEUE_FWD_NAV, howfar, 0).sendToTarget();
+ }
+
+ public void queueLoad(String Url, String frameTarget) {
+ HashMap <String, String>map = new HashMap<String, String>();
+ map.put("Url", Url);
+ map.put("frameTarget", frameTarget);
+ obtainMessage(LAYOUT_QUEUE_LOAD, map).sendToTarget();
+ }
+
+ public void queueReload() {
+ obtainMessage(LAYOUT_QUEUE_RELOAD).sendToTarget();
+ }
+
+ public void queueScript(String scriptToRunInCurrentContext) {
+ obtainMessage(LAYOUT_QUEUE_SCRIPT,
+ scriptToRunInCurrentContext).sendToTarget();
+ }
+
+ public void repaintSweepHorizontally() {
+ obtainMessage(LAYOUT_REPAINT_HORZ).sendToTarget();
+ }
+
+ public void setAcceptsEditing(boolean b) {
+ obtainMessage(LAYOUT_SET_ACCEPT_EDIT, b ? 1 : 0, 0).sendToTarget();
+ }
+
+ public void setMainFrameIsFirstResponder(boolean b) {
+ obtainMessage(LAYOUT_MAIN_FIRST_RESP, b ? 1 : 0, 0).sendToTarget();
+ }
+
+ public void setWindowIsKey(boolean b) {
+ obtainMessage(LAYOUT_SET_WINDOW_KEY,b ? 1 : 0, 0).sendToTarget();
+ }
+
+ public void testRepaint() {
+ obtainMessage(LAYOUT_TEST_REPAINT).sendToTarget();
+ }
+
+ public void waitUntilDone() {
+ obtainMessage(LAYOUT_WAIT_UNTIL_DONE).sendToTarget();
+ }
+
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
new file mode 100644
index 0000000..82fd8d8
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/EventSender.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+public interface EventSender {
+ public void mouseDown();
+ public void mouseUp();
+ public void mouseClick();
+ public void mouseMoveTo(int X, int Y);
+ public void leapForward(int milliseconds);
+ public void keyDown (String character, String[] withModifiers);
+ public void keyDown (String character);
+ public void enableDOMUIEventLogging(int DOMNode);
+ public void fireKeyboardEventsToElement(int DOMNode);
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
new file mode 100644
index 0000000..9be33db
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileFilter.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import java.util.HashSet;
+import java.util.Hashtable;
+import android.util.*;
+
+public class FileFilter {
+
+ public static boolean ignoreTest(String file) {
+ // treat files like directories for the time being.
+ for (int i = 0; i < ignoreTestList.length; i ++) {
+ if (file.endsWith(ignoreTestList[i])) {
+ Log.e("FileFilter", "File path in IgnoreTest: " + file);
+ return true;
+ }
+ }
+ for (int i = 0; i < ignoreTestDirs.length; i++) {
+ if (file.endsWith(ignoreTestDirs[i])) {
+ Log.e("FileFilter", "File path in ignore list: " + file);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public static boolean ignoreResults(String file) {
+ int index = file.indexOf("fast");
+ if (index != -1) {
+ String sub = file.substring(index);
+ if (ignoreResultList.contains(sub))
+ return true;
+ }
+ return false;
+
+ }
+
+ public static String isKnownBug(String file) {
+ int index = file.indexOf("fast");
+ if (index != -1) {
+ String sub = file.substring(index);
+ // Log.e("FileFilter", "Looking for:"+sub);
+ if (bugList.containsKey(sub))
+ return bugList.get(sub);
+ }
+ return null;
+ }
+
+ final static HashSet<String> ignoreResultList = new HashSet<String>();
+ final static Hashtable<String, String> bugList =
+ new Hashtable<String, String>();
+
+ static {
+ fillIgnoreResultSet();
+ fillBugTable();
+ }
+
+ static final String[] ignoreTestDirs = {
+ ".", // ignore hidden directories and files
+ "resources", // ignore resource directories
+ "AppleScript", // AppleScript not supported
+ "xpath", // xpath requires libxml2, not supported
+ "xsl", //xsl requires libxml2 & libxslt, not sup.
+ "kde", // don't run kde tests.
+ ".svn", // don't run anything under .svn folder
+ "gradients", // known crash
+ "profiler" // profiler is not supported
+ };
+
+ static final String [] ignoreTestList = {
+ "toString-stack-overflow.html", // Crashes #606688
+ "frame-limit.html", // generates too many GREFs
+ "css-insert-import-rule.html", // Crashes, #717414
+ "input-text-enter.html", // Crashes. #735088
+ "text-shadow-extreme-value.html", // Crashes #571671
+ "reflection-masks.html",
+ "frame-creation-removal.html",
+ "large-expressions.html",
+ "null-page-show-modal-dialog-crash.html",
+ "font-face-implicit-local-font.html",
+ "font-face-locally-installed.html",
+ "beforeSelectorOnCodeElement.html",
+ "cssTarget-crash.html",
+ "searchfield-heights.html", // Bug 1570692
+ "tabindex-focus-blur-all.html",
+ "search-rtl.html" // fast/forms/search-rtl.html
+ };
+
+ static void fillIgnoreResultSet() {
+ // need test plugin
+ ignoreResultList.add("fast/dom/Window/Plug-ins.html");
+ // pixel depth
+ ignoreResultList.add("fast/dom/Window/window-screen-properties.html");
+ // missing space in textrun, ok as text is wrapped. ignore. #714933
+ ignoreResultList.add("fast/events/onload-webkit-before-webcore.html");
+ // missing support for textInputController.makeAttributedString()
+ ignoreResultList.add("fast/forms/attributed-strings.html");
+ // charset convert. #516936 ignore, won't fix
+ ignoreResultList.add("fast/forms/form-data-encoding-2.html");
+ // charset convert. #516936 ignore, won't fix
+ ignoreResultList.add("fast/forms/form-data-encoding.html");
+ // execCommand "insertText" not supported
+ ignoreResultList.add("fast/forms/input-appearance-maxlength.html");
+ // Copy&Paste commands not supported
+ ignoreResultList.add("fast/forms/input-truncate-newline.html");
+ ignoreResultList.add("fast/forms/textarea-paste-newline.html");
+ // requires eventSender.mouseMoveTo, mouseDown & mouseUp and
+ // abs. position of mouse to select a word. ignore, won't fix #716583
+ ignoreResultList.add("fast/forms/onselect-textarea.html");
+ // requires eventSender.mouseMoveTo, mouseDown & mouseUp and
+ // abs. position of mouse to select a word. ignore, won't fix #716583
+ ignoreResultList.add("fast/forms/onselect-textfield.html");
+ // not implemented queryCommandEnabled:BackColor, Undo & Redo
+ ignoreResultList.add("fast/forms/plaintext-mode-1.html");
+ // Our text areas are a little thinner than Apples. Also RTL test failes
+ ignoreResultList.add("fast/forms/textarea-appearance-wrap.html");
+ // Our text areas are a little thinner than Apples
+ ignoreResultList.add("fast/forms/textarea-hard-linewrap.html");
+ // screen width&height are different
+ ignoreResultList.add("fast/frames/frameElement-widthheight.html");
+ ignoreResultList.add("fast/frames/frame-js-url-clientWidth.html");
+ // requires JS test API, textInputController
+ ignoreResultList.add("fast/text/attributed-substring-from-range.html");
+ ignoreResultList.add("fast/text/attributed-substring-from-range-001.html");
+ // will not fix #619707
+ ignoreResultList.add("fast/css/case-transform.html");
+ // different platform defaults for font and different screen size
+ ignoreResultList.add("fast/css/computed-style.html");
+ // different screen size result in extra spaces in Apple compared to us
+ ignoreResultList.add("fast/dom/Element/offsetLeft-offsetTop-body-quirk.html");
+ // xslt and xpath elements missing from property list
+ ignoreResultList.add("fast/dom/Window/window-properties.html");
+ // requires textInputController.characterIndexForPoint
+ ignoreResultList.add("fast/dom/character-index-for-point.html");
+ // requires xpath support
+ ignoreResultList.add("fast/dom/gc-9.html");
+ // requires xslt and xpath support
+ ignoreResultList.add("fast/dom/global-constructors.html");
+ // dynamic plugins not supported
+ ignoreResultList.add("fast/dom/object-embed-plugin-scripting.html");
+ ignoreResultList.add("fast/js/navigator-mimeTypes-length.html");
+ // there is extra spacing in the file due to multiple input boxes
+ // fitting on one line on Apple, ours are wrapped. Space at line ends
+ // are stripped.
+ ignoreResultList.add("fast/dom/tabindex-clamp.html");
+
+ // requires eventSender.mouseDown(),mouseUp()
+ ignoreResultList.add("fast/dom/Window/window-xy-properties.html");
+ ignoreResultList.add("fast/events/window-events-bubble.html");
+ ignoreResultList.add("fast/events/window-events-bubble2.html");
+ ignoreResultList.add("fast/events/window-events-capture.html");
+ ignoreResultList.add("fast/forms/select-empty-list.html");
+ ignoreResultList.add("fast/replaced/image-map.html");
+ ignoreResultList.add("fast/events/capture-on-target.html");
+ ignoreResultList.add("fast/events/dblclick-addEventListener.html");
+ ignoreResultList.add("fast/events/drag-in-frames.html");
+ ignoreResultList.add("fast/events/drag-outside-window.html");
+ ignoreResultList.add("fast/events/event-sender-mouse-click.html");
+ ignoreResultList.add("fast/events/event-view-toString.html");
+ ignoreResultList.add("fast/events/frame-click-focus.html");
+ ignoreResultList.add("fast/events/input-image-scrolled-x-y.html");
+ ignoreResultList.add("fast/events/anchor-image-scrolled-x-y.html");
+ ignoreResultList.add("fast/events/mouseclick-target-and-positioning.html");
+ ignoreResultList.add("fast/events/mouseover-mouseout.html");
+ ignoreResultList.add("fast/events/mouseover-mouseout2.html");
+ ignoreResultList.add("fast/events/mouseup-outside-button.html");
+ ignoreResultList.add("fast/events/mouseup-outside-document.html");
+ ignoreResultList.add("fast/events/onclick-list-marker.html");
+ ignoreResultList.add("fast/events/ondragenter.html");
+ ignoreResultList.add("fast/forms/drag-into-textarea.html");
+ ignoreResultList.add("fast/forms/input-select-on-click.html");
+ ignoreResultList.add("fast/forms/listbox-onchange.html");
+ ignoreResultList.add("fast/forms/search-cancel-button-mouseup.html");
+ ignoreResultList.add("fast/forms/textarea-scrolled-endline-caret.html");
+
+ // there is extra spacing in the file due to multiple frame boxes
+ // fitting on one line on Apple, ours are wrapped. Space at line ends
+ // are stripped.
+ ignoreResultList.add("fast/events/iframe-object-onload.html");
+ // eventSender.mouseDown(), mouseUp() and objc API missing
+ ignoreResultList.add("fast/events/mouseup-outside-document.html");
+ ignoreResultList.add("fast/events/objc-keyboard-event-creation.html");
+ ignoreResultList.add("fast/events/objc-event-api.html");
+ // not capturing the console messages
+ ignoreResultList.add("fast/forms/selected-index-assert.html");
+ ignoreResultList.add("fast/parser/script-tag-with-trailing-slash.html");
+ // there is extra spacing as the text areas and input boxes fit next
+ // to each other on Apple, but are wrapped on our screen.
+ ignoreResultList.add("fast/forms/selection-functions.html");
+ // Text selection done differently on our platform. When a inputbox
+ // gets focus, the entire block is selected.
+ ignoreResultList.add("fast/forms/textarea-initial-caret-position.html");
+ ignoreResultList.add("fast/forms/textarea-no-scroll-on-blur.html");
+ // Requires LayoutTests to exist at /tmp/LayoutTests
+ ignoreResultList.add("fast/loader/local-JavaScript-from-local.html");
+ ignoreResultList.add("fast/loader/local-iFrame-source-from-local.html");
+ // extra spacing because iFrames rendered next to each other on Apple
+ ignoreResultList.add("fast/loader/opaque-base-url.html");
+ // RegExp is too large, causing OOM
+ ignoreResultList.add("fast/js/regexp-charclass-crash.html");
+ ignoreResultList.add("fast/text/plain-text-line-breaks.html");
+
+
+ }
+
+ static void fillBugTable() {
+ bugList.put("fast/forms/check-box-enter-key.html", "716715");
+ bugList.put("fast/forms/focus-control-to-page.html", "716638");
+ bugList.put("fast/html/tab-order.html", "719289");
+ bugList.put("fast/dom/attribute-namespaces-get-set.html", "733229");
+ bugList.put("fast/dom/location-hash.html", "733822");
+ bugList.put("fast/dom/set-innerHTML.html", "733823");
+ bugList.put("fast/dom/xmlhttprequest-get.html", "733846");
+ bugList.put("fast/encoding/css-charset-default.html", "733856");
+ bugList.put("fast/encoding/default-xhtml-encoding.html", "733882");
+ bugList.put("fast/encoding/meta-in-xhtml.html", "733882");
+ bugList.put("fast/events/frame-tab-focus.html", "734308");
+ bugList.put("fast/events/keydown-keypress-focus-change.html", "653224");
+ bugList.put("fast/events/keypress-focus-change.html", "653224");
+ bugList.put("fast/events/option-tab.html", "734308");
+ bugList.put("fast/forms/focus2.html", "735111");
+ bugList.put("fast/forms/listbox-selection.html", "735116");
+ bugList.put("fast/forms/search-event-delay.html", "735120");
+ bugList.put("fast/frames/iframe-window-focus.html", "735140");
+ bugList.put("fast/innerHTML/004.html", "733882");
+ bugList.put("fast/js/date-DST-time-cusps.html", "735144");
+ bugList.put("fast/js/string-capitalization.html", "516936");
+ bugList.put("fast/js/string-concatenate-outofmemory.html","735152");
+ bugList.put("fast/parser/external-entities.html", "735176");
+ bugList.put("fast/events/div-focus.html", "735185");
+ bugList.put("fast/overflow/scroll-vertical-not-horizontal.html", "735196");
+ bugList.put("fast/events/arrow-navigation.html", "735233");
+ bugList.put("fast/forms/select-type-ahead-non-latin.html", "735244");
+ bugList.put("fast/events/js-keyboard-event-creation.html", "735255");
+
+ }
+
+
+
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
new file mode 100644
index 0000000..d685f5d
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/FileList.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.io.File;
+
+import android.app.ListActivity;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.SimpleAdapter;
+import android.os.Bundle;
+
+
+public abstract class FileList extends ListActivity
+{
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch (keyCode)
+ {
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ if (mPath.length() > mBaseLength) {
+ File f = new File(mPath);
+ mFocusFile = f.getName();
+ mFocusIndex = 0;
+ f = f.getParentFile();
+ mPath = f.getPath();
+ updateList();
+ return true;
+ }
+ break;
+
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ {
+ Map map = (Map) getListView().getItemAtPosition(getListView().getSelectedItemPosition());
+ String path = (String)map.get("path");
+ if ((new File(path)).isDirectory()) {
+ mPath = path;
+ mFocusFile = null;
+ updateList();
+ } else {
+ processFile(path, false);
+ }
+ return true;
+ }
+
+ default:
+ break;
+ }
+ return super.onKeyDown(keyCode, event);
+ }
+
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+ setupPath();
+ updateList();
+ }
+
+ protected List getData()
+ {
+ List myData = new ArrayList<HashMap>();
+
+ File f = new File(mPath);
+ if (!f.exists()) {
+ addItem(myData, "!LayoutTests path missing!", "");
+ return myData;
+ }
+ String[] files = f.list();
+
+ for (int i = 0; i < files.length; i++) {
+ StringBuilder sb = new StringBuilder(mPath);
+ sb.append(File.separatorChar);
+ sb.append(files[i]);
+ String path = sb.toString();
+ File c = new File(path);
+ if (fileFilter(c)) {
+ if (c.isDirectory()) {
+ addItem(myData, "<"+files[i]+">", path);
+ if (mFocusFile != null && mFocusFile.equals(files[i]))
+ mFocusIndex = myData.size()-1;
+ }
+ else
+ addItem(myData, files[i], path);
+ }
+ }
+
+ return myData;
+ }
+
+ protected void addItem(List<Map> data, String name, String path)
+ {
+ HashMap temp = new HashMap();
+ temp.put("title", name);
+ temp.put("path", path);
+ data.add(temp);
+ }
+
+ protected void onListItemClick(ListView l, View v, int position, long id)
+ {
+ Map map = (Map) l.getItemAtPosition(position);
+ String path = (String)map.get("path");
+
+ if ((new File(path)).isDirectory()) {
+ mPath = path;
+ mFocusFile = null;
+ updateList();
+ } else {
+ processFile(path, false);
+ }
+ }
+
+ /*
+ * This function is called when the user has selected a file in the
+ * file list. The selected file could be a file or a directory.
+ * The flag indicates if this was from a selection or not.
+ */
+ abstract void processFile(String filename, boolean selection);
+
+ /*
+ * This function is called when the file list is being built. Return
+ * true if the file is to be added to the file list.
+ */
+ abstract boolean fileFilter(File f);
+
+ protected void updateList() {
+ setListAdapter(new SimpleAdapter(this,
+ getData(),
+ android.R.layout.simple_list_item_1,
+ new String[] {"title"},
+ new int[] {android.R.id.text1}));
+ String title = mPath; //.substring(mBaseLength-11); // show the word LayoutTests
+ setTitle(title);
+ getListView().setSelection(mFocusIndex);
+ }
+
+ protected void setupPath()
+ {
+ mPath = "/sdcard/android/layout_tests";
+ mBaseLength = mPath.length();
+ }
+
+ protected String mPath;
+ protected int mBaseLength;
+ protected String mFocusFile;
+ protected int mFocusIndex;
+
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
new file mode 100644
index 0000000..86bfad7
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostActivity.java
@@ -0,0 +1,726 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.BufferedOutputStream;
+import java.io.FileInputStream;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.List;
+import java.util.Vector;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.ViewGroup;
+import android.webkit.JsPromptResult;
+import android.webkit.JsResult;
+import android.webkit.WebChromeClient;
+import android.webkit.WebSettings;
+import android.webkit.WebView;
+import android.widget.LinearLayout;
+import android.os.*;
+
+// TestRecorder creates two files, one for passing tests
+// and another for failing tests and writes the paths to
+// layout tests one line at a time. TestRecorder does not
+// have ability to clear the results.
+class TestRecorder {
+ public void passed(String layout_file) {
+ try {
+ mBufferedOutputPassedStream.write(layout_file.getBytes());
+ mBufferedOutputPassedStream.write('\n');
+ mBufferedOutputPassedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void failed(String layout_file, String reason) {
+ try {
+ mBufferedOutputFailedStream.write(layout_file.getBytes());
+ mBufferedOutputFailedStream.write(" : ".getBytes());
+ mBufferedOutputFailedStream.write(reason.getBytes());
+ mBufferedOutputFailedStream.write('\n');
+ mBufferedOutputFailedStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void nontext(String layout_file, boolean has_results) {
+ try {
+ mBufferedOutputNontextStream.write(layout_file.getBytes());
+ if (has_results) {
+ mBufferedOutputNontextStream.write(" : has expected results".getBytes());
+ }
+ mBufferedOutputNontextStream.write('\n');
+ mBufferedOutputNontextStream.flush();
+ } catch(Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public TestRecorder(boolean resume) {
+ try {
+ File resultsPassedFile = new File("/sdcard/layout_tests_passed.txt");
+ File resultsFailedFile = new File("/sdcard/layout_tests_failed.txt");
+ File resultsNontextFile = new File("/sdcard/layout_tests_nontext.txt");
+
+ mBufferedOutputPassedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsPassedFile, resume));
+ mBufferedOutputFailedStream =
+ new BufferedOutputStream(new FileOutputStream(resultsFailedFile, resume));
+ mBufferedOutputNontextStream =
+ new BufferedOutputStream(new FileOutputStream(resultsNontextFile, resume));
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void close() {
+ try {
+ mBufferedOutputPassedStream.close();
+ mBufferedOutputFailedStream.close();
+ mBufferedOutputNontextStream.close();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ private BufferedOutputStream mBufferedOutputPassedStream;
+ private BufferedOutputStream mBufferedOutputFailedStream;
+ private BufferedOutputStream mBufferedOutputNontextStream;
+}
+
+public class HTMLHostActivity extends Activity
+ implements LayoutTestController {
+
+ public class AsyncHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ if (msg.what == MSG_TIMEOUT) {
+ mTimedOut = true;
+ requestWebKitData();
+ return;
+ } else if (msg.what == MSG_WEBKIT_DATA) {
+ HTMLHostActivity.this.dump(mTimedOut, (String)msg.obj);
+ return;
+ }
+
+ super.handleMessage(msg);
+ }
+ }
+
+ public void requestWebKitData() {
+ Message callback = mHandler.obtainMessage(MSG_WEBKIT_DATA);
+
+ if (mRequestedWebKitData)
+ throw new AssertionError("Requested webkit data twice: " + mWebView.getUrl());
+
+ mRequestedWebKitData = true;
+ if (mDumpAsText) {
+ mWebView.documentAsText(callback);
+ } else {
+ mWebView.externalRepresentation(callback);
+ }
+ }
+ // Activity methods
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ LinearLayout contentView = new LinearLayout(this);
+ contentView.setOrientation(LinearLayout.VERTICAL);
+ setContentView(contentView);
+
+ mWebView = new WebView(this);
+ mWebView.getSettings().setJavaScriptEnabled(true);
+ mWebView.setWebChromeClient(mChromeClient);
+ mEventSender = new WebViewEventSender(mWebView);
+ mCallbackProxy = new CallbackProxy(mEventSender, this);
+ mFinishedRunning = false;
+
+ mWebView.addJavascriptInterface(mCallbackProxy, "layoutTestController");
+ mWebView.addJavascriptInterface(mCallbackProxy, "eventSender");
+ contentView.addView(mWebView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT, 0.0f));
+
+ mHandler = new AsyncHandler();
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Bundle savedInstanceState) {
+ super.onRestoreInstanceState(savedInstanceState);
+ }
+
+ private void getTestList() {
+ // Read test list.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(LAYOUT_TESTS_LIST_FILE));
+ String line = inReader.readLine();
+ while (line != null) {
+ if (line.startsWith(mTestPathPrefix))
+ mTestList.add(line);
+ line = inReader.readLine();
+ }
+ inReader.close();
+ Log.v(LOGTAG, "Test list has " + mTestList.size() + " test(s).");
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error while reading test list : " + e.getMessage());
+ }
+ }
+
+ private void resumeTestList() {
+ // read out the test name it stoped last time.
+ try {
+ BufferedReader inReader = new BufferedReader(new FileReader(TEST_STATUS_FILE));
+ String line = inReader.readLine();
+ for (int i = 0; i < mTestList.size(); i++) {
+ if (mTestList.elementAt(i).equals(line)) {
+ mTestList = new Vector<String>(mTestList.subList(i+1, mTestList.size()));
+ break;
+ }
+ }
+ inReader.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error reading " + TEST_STATUS_FILE);
+ }
+ }
+
+ private void clearTestStatus() {
+ // Delete TEST_STATUS_FILE
+ try {
+ File f = new File(TEST_STATUS_FILE);
+ if (f.delete())
+ Log.v(LOGTAG, "Deleted " + TEST_STATUS_FILE);
+ else
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE);
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Fail to delete " + TEST_STATUS_FILE + " : " + e.getMessage());
+ }
+ }
+
+ private void updateTestStatus(String s) {
+ // Write TEST_STATUS_FILE
+ try {
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(TEST_STATUS_FILE));
+ bos.write(s.getBytes());
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Cannot update file " + TEST_STATUS_FILE);
+ }
+ }
+
+ protected void onResume() {
+ super.onResume();
+ if (mTestList == null)
+ mTestList = new Vector<String>();
+
+ if (mTestList.isEmpty()) {
+ // Read settings
+ Intent intent = getIntent();
+ mTestPathPrefix = intent.getStringExtra(TEST_PATH_PREFIX);
+ mSingleTestMode = intent.getBooleanExtra(SINGLE_TEST_MODE, false);
+ boolean resume = intent.getBooleanExtra(RESUME_FROM_CRASH, false);
+ mTimeoutInMillis = intent.getIntExtra(TIMEOUT_IN_MILLIS, 8000);
+
+ mWebView.getSettings().setLayoutAlgorithm(WebSettings.LayoutAlgorithm.NORMAL);
+
+ if (mTestPathPrefix == null)
+ throw new AssertionError("mTestPathPrefix cannot be null");
+
+ Log.v(LOGTAG, "Run tests with prefix: " + mTestPathPrefix);
+
+ mResultRecorder = new TestRecorder(resume);
+
+ if (!resume)
+ clearTestStatus();
+
+ if (!mSingleTestMode) {
+ getTestList();
+ if (resume)
+ resumeTestList();
+ } else {
+ mTestList.add(mTestPathPrefix);
+ }
+
+ if (!mTestList.isEmpty())
+ runTestAtIndex(0);
+ else
+ mWebView.loadUrl("about:");
+ }
+ }
+
+ protected void onStop() {
+ super.onStop();
+ mWebView.stopLoading();
+ }
+
+ protected void onDestroy() {
+ super.onDestroy();
+ mResultRecorder.close();
+ mWebView.destroy();
+ mWebView = null;
+ }
+
+ public void onLowMemory() {
+ super.onLowMemory();
+ // Simulate a crash
+ Log.e(LOGTAG, "Low memory, killing self");
+ System.exit(1);
+ }
+
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ // Log key strokes as they don't seem to be matched
+ //Log.e(LOGTAG, "Event: "+event);
+ return super.dispatchKeyEvent(event);
+ }
+
+ // Run a test at specified index in the test list.
+ // Stops activity if run out of tests.
+ protected void runTestAtIndex(int testIndex) {
+ mTestIndex = testIndex;
+
+ resetTestStatus();
+
+ if (testIndex == mTestList.size()) {
+ if (!mSingleTestMode) {
+ updateTestStatus("#DONE");
+ }
+ finished();
+ return;
+ }
+ String s = mTestList.elementAt(testIndex);
+ if (!mSingleTestMode)
+ updateTestStatus(s);
+
+ Log.v(LOGTAG, " Running test: "+s);
+ mWebView.loadUrl("file://"+s);
+
+ if (!mSingleTestMode) {
+ // Create a timeout timer
+ Message m = mHandler.obtainMessage(MSG_TIMEOUT);
+ mHandler.sendMessageDelayed(m, mTimeoutInMillis);
+ }
+ }
+
+ // Dump the page
+ public void dump(boolean timeout, String webkitData) {
+ String currentTest = mTestList.elementAt(mTestIndex);
+ String resultFile = currentTest.substring(0, currentTest.lastIndexOf('.'));
+
+ // dumpAsText version can be directly compared to expected results
+ if (mDumpAsText) {
+ resultFile += "-results.txt";
+ } else {
+ resultFile += "-android-results.txt";
+ }
+
+ try {
+ FileOutputStream os = new FileOutputStream(resultFile);
+ if (timeout) {
+ Log.w("Layout test: Timeout", resultFile);
+ os.write(TIMEOUT_STR.getBytes());
+ os.write('\n');
+ }
+ if (mDumpTitleChanges)
+ os.write(mTitleChanges.toString().getBytes());
+ if (mDialogStrings != null)
+ os.write(mDialogStrings.toString().getBytes());
+ mDialogStrings = null;
+ os.write(webkitData.getBytes());
+ os.flush();
+ os.close();
+ } catch (FileNotFoundException ex) {
+ ex.printStackTrace();
+ } catch (IOException ex) {
+ ex.printStackTrace();
+ }
+
+ processResult(timeout, currentTest);
+ runTestAtIndex(mTestIndex + 1);
+ }
+
+ // Wrap up
+ public void failedCase(String file, String reason) {
+ Log.w("Layout test: ", file + " failed " + reason);
+ mResultRecorder.failed(file, reason);
+
+ String bugNumber = FileFilter.isKnownBug(file);
+ if (bugNumber != null) {
+ System.out.println("FAIL known:"+bugNumber+ " "+file+reason);
+ return;
+ }
+ if (FileFilter.ignoreResults(file)) {
+ return;
+ }
+ System.out.println("FAIL: "+file+reason);
+ }
+
+ public void passedCase(String file) {
+ Log.v("Layout test:", file + " passed");
+ mResultRecorder.passed(file);
+
+ String bugNumber = FileFilter.isKnownBug(file);
+ if (bugNumber != null) {
+ System.out.println("Bug Fixed: "+bugNumber+ " "+file);
+ return;
+ }
+
+ if (FileFilter.ignoreResults(file)) {
+ System.out.println("Ignored test passed: "+file);
+ return;
+ }
+ }
+
+ public void nontextCase(String file, boolean has_expected_results) {
+ Log.v("Layout test:", file + " nontext");
+ mResultRecorder.nontext(file, has_expected_results);
+ }
+
+ public void setCallback(HTMLHostCallbackInterface callback) {
+ mCallback = callback;
+ }
+
+ public void processResult(boolean timeout, String test_path) {
+ Log.v(LOGTAG, " Processing result: " + test_path);
+ // remove the extension
+ String short_file = test_path.substring(0, test_path.lastIndexOf('.'));
+ if (timeout) {
+ failedCase(test_path, "TIMEDOUT");
+ return;
+ }
+ // Only check results that we can check, ie dumpAsText results
+ String dumpFile = short_file + "-results.txt";
+ File f = new File(dumpFile);
+ if (f.exists()) {
+ try {
+ FileInputStream fr = new FileInputStream(short_file+"-results.txt");
+ FileInputStream fe = new FileInputStream(short_file+"-expected.txt");
+
+ // If the length is different then they are different
+ int diff = fe.available() - fr.available();
+ if (diff > 1 || diff < 0) {
+ failedCase(test_path, " different length");
+ fr.close();
+ fe.close();
+ return;
+ }
+ byte[] br = new byte[fr.available()];
+ byte[] be = new byte[fe.available()];
+ fr.read(br);
+ fe.read(be);
+ boolean fail = false;
+ for (int i = 0; i < br.length; i++) {
+ if (br[i] != be[i]) {
+ failedCase(test_path, " @offset: "+i);
+ fr.close();
+ fe.close();
+ return;
+ }
+ }
+ if (br.length != be.length && be[be.length-1] == '\n') {
+ Log.d(LOGTAG, "Extra new line being ignore:" + test_path);
+ }
+ fr.close();
+ fe.close();
+ passedCase(test_path);
+ } catch (FileNotFoundException ex) {
+ // TODO do something here
+ } catch (IOException ex) {
+ // Failed on available() or read()
+ }
+
+ return;
+ }
+
+ File nontext_result = new File(short_file + "-android-results.txt");
+ if (nontext_result.exists()) {
+ // Check if the test has expected results.
+ File expected = new File(short_file + "-expected.txt");
+ nontextCase(test_path, expected.exists());
+ }
+ }
+
+ public void finished() {
+ if (mCallback != null) {
+ mCallback.waitForFinish();
+ }
+
+ mFinishedRunning = true;
+ finish();
+ }
+
+ // LayoutTestController Functions
+ public void dumpAsText() {
+ mDumpAsText = true;
+ if (mWebView != null) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "dumpAsText called: "+url);
+ }
+ }
+
+ public void waitUntilDone() {
+ mWaitUntilDone = true;
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "waitUntilDone called: " + url);
+ }
+ public void notifyDone() {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "notifyDone called: " + url);
+ if (mWaitUntilDone) {
+ mWaitUntilDone = false;
+ mChromeClient.onProgressChanged(mWebView, 100);
+ }
+ }
+
+ public void display() {
+ mWebView.invalidate();
+ }
+
+ public void clearBackForwardList() {
+ mWebView.clearHistory();
+
+ }
+
+ public void dumpBackForwardList() {
+ //printf("\n============== Back Forward List ==============\n");
+ // mWebHistory
+ //printf("===============================================\n");
+
+ }
+
+ public void dumpChildFrameScrollPositions() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpEditingCallbacks() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpSelectionRect() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void dumpTitleChanges() {
+ if (!mDumpTitleChanges) {
+ mTitleChanges = new StringBuffer();
+ }
+ mDumpTitleChanges = true;
+ }
+
+ public void keepWebHistory() {
+ if (!mKeepWebHistory) {
+ mWebHistory = new Vector();
+ }
+ mKeepWebHistory = true;
+ }
+
+ public void queueBackNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueForwardNavigation(int howfar) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueLoad(String Url, String frameTarget) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void queueReload() {
+ mWebView.reload();
+ }
+
+ public void queueScript(String scriptToRunInCurrentContext) {
+ mWebView.loadUrl("javascript:"+scriptToRunInCurrentContext);
+ }
+
+ public void repaintSweepHorizontally() {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setAcceptsEditing(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setMainFrameIsFirstResponder(boolean b) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void setWindowIsKey(boolean b) {
+ // This is meant to show/hide the window. The best I can find
+ // is setEnabled()
+ mWebView.setEnabled(b);
+ }
+
+ public void testRepaint() {
+ mWebView.invalidate();
+ }
+
+ // Instrumentation calls this to find
+ // if the activity has finished running the layout tests
+ // TODO(fqian): need to sync on mFinisheRunning
+ public boolean hasFinishedRunning() {
+ return mFinishedRunning;
+ }
+
+ private final WebChromeClient mChromeClient = new WebChromeClient() {
+ @Override
+ public void onProgressChanged(WebView view, int newProgress) {
+ if (newProgress == 100) {
+ if (!mSingleTestMode && !mTimedOut && !mWaitUntilDone && !mRequestedWebKitData) {
+ String url = mWebView.getUrl();
+ Log.v(LOGTAG, "Finished: "+ url);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ requestWebKitData();
+ } else {
+ String url = mWebView.getUrl();
+ if (mSingleTestMode) {
+ Log.v(LOGTAG, "Single test mode: " + url);
+ } else if (mTimedOut) {
+ Log.v(LOGTAG, "Timed out before finishing: " + url);
+ } else if (mWaitUntilDone) {
+ Log.v(LOGTAG, "Waiting for notifyDone: " + url);
+ } else if (mRequestedWebKitData) {
+ Log.v(LOGTAG, "Requested webkit data ready: " + url);
+ }
+ }
+ }
+ }
+
+ @Override
+ public void onReceivedTitle(WebView view, String title) {
+ if (title.length() > 30)
+ title = "..."+title.substring(title.length()-30);
+ setTitle(title);
+ if (mDumpTitleChanges) {
+ mTitleChanges.append("TITLE CHANGED: ");
+ mTitleChanges.append(title);
+ mTitleChanges.append("\n");
+ }
+ }
+
+ @Override
+ public boolean onJsAlert(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("ALERT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsConfirm(WebView view, String url, String message,
+ JsResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("CONFIRM: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+
+ @Override
+ public boolean onJsPrompt(WebView view, String url, String message,
+ String defaultValue, JsPromptResult result) {
+ if (mDialogStrings == null) {
+ mDialogStrings = new StringBuffer();
+ }
+ mDialogStrings.append("PROMPT: ");
+ mDialogStrings.append(message);
+ mDialogStrings.append(", default text: ");
+ mDialogStrings.append(defaultValue);
+ mDialogStrings.append('\n');
+ result.confirm();
+ return true;
+ }
+ };
+
+ private void resetTestStatus() {
+ mWaitUntilDone = false;
+ mDumpAsText = false;
+ mTimedOut = false;
+ mDumpTitleChanges = false;
+ mRequestedWebKitData = false;
+ mEventSender.resetMouse();
+ }
+
+ private TestRecorder mResultRecorder;
+ private HTMLHostCallbackInterface mCallback = null;
+ private CallbackProxy mCallbackProxy;
+
+ private WebView mWebView;
+ private WebViewEventSender mEventSender;
+
+ private Vector<String> mTestList;
+ private int mTestIndex;
+
+ private int mTimeoutInMillis;
+ private String mTestPathPrefix;
+ private boolean mSingleTestMode;
+
+ private AsyncHandler mHandler;
+ private boolean mFinishedRunning;
+
+ private boolean mTimedOut;
+ private boolean mRequestedWebKitData;
+ private boolean mDumpAsText;
+ private boolean mWaitUntilDone;
+ private boolean mDumpTitleChanges;
+
+ private StringBuffer mTitleChanges;
+ private StringBuffer mDialogStrings;
+
+ private boolean mKeepWebHistory;
+ private Vector mWebHistory;
+
+ static final String TIMEOUT_STR = "**Test timeout";
+
+ static final int MSG_TIMEOUT = 0;
+ static final int MSG_WEBKIT_DATA = 1;
+
+ static final String LOGTAG="DumpRenderTree";
+
+ static final String LAYOUT_TESTS_ROOT = "/sdcard/android/layout_tests/";
+ static final String LAYOUT_TESTS_LIST_FILE = "/sdcard/layout_tests_list.txt";
+ static final String TEST_STATUS_FILE = "/sdcard/running_test.txt";
+
+ static final String RESUME_FROM_CRASH = "ResumeFromCrash";
+ static final String TEST_PATH_PREFIX = "TestPathPrefix";
+ static final String TIMEOUT_IN_MILLIS = "TimeoutInMillis";
+ static final String SINGLE_TEST_MODE = "SingleTestMode";
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
new file mode 100644
index 0000000..f610f5a
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostApp.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.app.Application;
+
+public class HTMLHostApp extends Application {
+
+ public HTMLHostApp() {
+ }
+
+ public void onCreate() {
+ }
+
+ public void onTerminate() {
+ }
+
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
new file mode 100644
index 0000000..60a2915
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/HTMLHostCallbackInterface.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+public interface HTMLHostCallbackInterface {
+ public void waitForFinish();
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
new file mode 100644
index 0000000..6166dd0
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestController.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+public interface LayoutTestController {
+
+ public void dumpAsText();
+ public void waitUntilDone();
+ public void notifyDone();
+
+ // Force a redraw of the page
+ public void display();
+ // Used with pixel dumps of content
+ public void testRepaint();
+
+ // If the page title changes, add the information to the output.
+ public void dumpTitleChanges();
+ public void dumpBackForwardList();
+ public void dumpChildFrameScrollPositions();
+ public void dumpEditingCallbacks();
+
+ // Show/Hide window for window.onBlur() testing
+ public void setWindowIsKey(boolean b);
+ // Mac function, used to disable events going to the window
+ public void setMainFrameIsFirstResponder(boolean b);
+
+ public void dumpSelectionRect();
+
+ // invalidate and draw one line at a time of the web view.
+ public void repaintSweepHorizontally();
+
+ // History testing functions
+ public void keepWebHistory();
+ public void clearBackForwardList();
+ // navigate after page load has finished
+ public void queueBackNavigation(int howfar);
+ public void queueForwardNavigation(int howfar);
+
+ // Reload when the page load has finished
+ public void queueReload();
+ // Execute the provided script in current context when page load has finished.
+ public void queueScript(String scriptToRunInCurrentContext);
+ // Load the provided URL into the provided frame
+ public void queueLoad(String Url, String frameTarget);
+
+ public void setAcceptsEditing(boolean b);
+
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
new file mode 100755
index 0000000..1f37405
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoRunner.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import junit.framework.TestSuite;
+import com.android.dumprendertree.LayoutTestsAutoTest;
+
+import android.test.InstrumentationTestRunner;
+import android.test.InstrumentationTestSuite;
+import android.util.Log;
+import android.content.Intent;
+import android.os.Bundle;
+
+
+/**
+ * Instrumentation Test Runner for all MediaPlayer tests.
+ *
+ * Running all tests:
+ *
+ * adb shell am instrument \
+ * -w com.android.dumprendertree.LayoutTestsAutoRunner
+ */
+
+public class LayoutTestsAutoRunner extends InstrumentationTestRunner {
+ @Override
+ public TestSuite getAllTests() {
+ TestSuite suite = new InstrumentationTestSuite(this);
+ suite.addTestSuite(LayoutTestsAutoTest.class);
+ return suite;
+ }
+
+ @Override
+ public ClassLoader getLoader() {
+ return LayoutTestsAutoRunner.class.getClassLoader();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ String path = (String) icicle.get("path");
+ LayoutTestsAutoTest.setLayoutTestDir(path);
+ String timeout_str = (String) icicle.get("timeout");
+ int timeout = 0; // default value
+ if (timeout_str != null) {
+ try {
+ timeout = Integer.parseInt(timeout_str);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ LayoutTestsAutoTest.setTimeoutInMillis(timeout);
+ }
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
new file mode 100644
index 0000000..3e65f0358
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/LayoutTestsAutoTest.java
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.ContentResolver;
+import android.content.ContentValues;
+import android.content.Intent;
+
+import android.util.Log;
+import android.view.KeyEvent;
+
+import android.os.Bundle;
+import android.os.Message;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import com.android.dumprendertree.HTMLHostActivity;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class LayoutTestsAutoTest extends ActivityInstrumentationTestCase<Menu> {
+
+ private final static String LOGTAG = "LayoutTests";
+ private final static int DEFAULT_TIMEOUT_IN_MILLIS = 6000;
+ private static String layoutTestDir = null;
+ private static int mTimeoutInMillis = 0;
+
+ public LayoutTestsAutoTest() {
+ super("com.android.dumprendertree", Menu.class);
+ }
+
+ // This function writes the result of the layout test to
+ // Am status so that it can be picked up from a script.
+ public void passOrFailCallback(String file, boolean result) {
+ Instrumentation inst = getInstrumentation();
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(file, result);
+ inst.sendStatus(0, bundle);
+ }
+
+ public static void setTimeoutInMillis(int millis) {
+ mTimeoutInMillis = (millis > 0) ? millis : DEFAULT_TIMEOUT_IN_MILLIS;
+ }
+
+ public static void setLayoutTestDir(String name) {
+ if (name == null)
+ throw new AssertionError("Layout test directory cannot be null.");
+ layoutTestDir = HTMLHostActivity.LAYOUT_TESTS_ROOT + name;
+ Log.v("LayoutTestsAutoTest", " Only running the layout tests : " + layoutTestDir);
+ }
+
+ // Invokes running of layout tests
+ // and waits till it has finished running.
+ public void executeLayoutTests(boolean resume) {
+ Instrumentation inst = getInstrumentation();
+
+ {
+ Activity activity = getActivity();
+ Intent intent = new Intent();
+ intent.setClass(activity, HTMLHostActivity.class);
+ intent.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, resume);
+ intent.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, false);
+ intent.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, layoutTestDir);
+ intent.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, mTimeoutInMillis);
+ activity.startActivity(intent);
+ }
+
+ ActivityMonitor htmlHostActivityMonitor =
+ inst.addMonitor("com.android.dumprendertree.HTMLHostActivity", null, false);
+
+ HTMLHostActivity activity =
+ (HTMLHostActivity) htmlHostActivityMonitor.waitForActivity();
+
+ while (!activity.hasFinishedRunning()) {
+ // Poll every 5 seconds to determine if the layout
+ // tests have finished running
+ try {Thread.sleep(5000); } catch(Exception e){}
+ }
+
+ // Wait few more seconds so that results are
+ // flushed to the /sdcard
+ try {Thread.sleep(5000); } catch(Exception e){}
+
+ // Clean up the HTMLHostActivity activity
+ activity.finish();
+ }
+
+ public void generateTestList() {
+ try {
+ File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+ BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(tests_list, false));
+ findTestsRecursively(bos, layoutTestDir);
+ bos.flush();
+ bos.close();
+ } catch (Exception e) {
+ Log.e(LOGTAG, "Error when creating test list: " + e.getMessage());
+ }
+ }
+
+ private void findTestsRecursively(BufferedOutputStream bos, String dir) throws IOException {
+ Log.v(LOGTAG, "Searching tests under " + dir);
+
+ File d = new File(dir);
+ if (!d.isDirectory()) {
+ throw new AssertionError("A directory expected, but got " + dir);
+ }
+
+ String[] files = d.list();
+ for (int i = 0; i < files.length; i++) {
+ String s = dir + "/" + files[i];
+ if (FileFilter.ignoreTest(s)) {
+ Log.v(LOGTAG, " Ignoring: " + s);
+ continue;
+ }
+ if (s.toLowerCase().endsWith(".html")
+ || s.toLowerCase().endsWith(".xml")) {
+ bos.write(s.getBytes());
+ bos.write('\n');
+ continue;
+ }
+
+ File f = new File(s);
+ if (f.isDirectory()) {
+ findTestsRecursively(bos, s);
+ continue;
+ }
+
+ Log.v(LOGTAG, "Skipping " + s);
+ }
+ }
+
+ // Running all the layout tests at once sometimes
+ // causes the dumprendertree to run out of memory.
+ // So, additional tests are added to run the tests
+ // in chunks.
+ public void startLayoutTests() {
+ try {
+ File tests_list = new File(HTMLHostActivity.LAYOUT_TESTS_LIST_FILE);
+ if (!tests_list.exists())
+ generateTestList();
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ executeLayoutTests(false);
+ }
+
+ public void resumeLayoutTests() {
+ executeLayoutTests(true);
+ }
+}
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
new file mode 100644
index 0000000..de0da61
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/Menu.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+
+import java.io.File;
+
+public class Menu extends FileList {
+
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+ }
+
+ boolean fileFilter(File f) {
+ if (f.getName().startsWith("."))
+ return false;
+ if (f.getName().equalsIgnoreCase("resources"))
+ return false;
+ if (f.isDirectory())
+ return true;
+ if (f.getPath().toLowerCase().endsWith("ml"))
+ return true;
+ return false;
+ }
+
+ void processFile(String filename, boolean selection)
+ {
+ Intent result = new Intent();
+ result.setClass(this, HTMLHostActivity.class);
+ result.putExtra(HTMLHostActivity.RESUME_FROM_CRASH, false);
+ result.putExtra(HTMLHostActivity.SINGLE_TEST_MODE, true);
+ result.putExtra(HTMLHostActivity.TEST_PATH_PREFIX, filename);
+ result.putExtra(HTMLHostActivity.TIMEOUT_IN_MILLIS, 8000);
+ startActivity(result);
+ }
+
+}
+
diff --git a/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
new file mode 100644
index 0000000..eea6346
--- /dev/null
+++ b/tests/DumpRenderTree/src/com/android/dumprendertree/WebViewEventSender.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.dumprendertree;
+
+import android.webkit.WebView;
+import android.view.KeyEvent;
+import android.util.*;
+
+import java.util.Arrays;
+
+public class WebViewEventSender implements EventSender {
+
+ WebViewEventSender(WebView webView) {
+ mWebView = webView;
+ }
+
+ public void resetMouse() {
+ mouseX = mouseY = 0;
+ }
+
+ public void enableDOMUIEventLogging(int DOMNode) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void fireKeyboardEventsToElement(int DOMNode) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void keyDown(String character, String[] withModifiers) {
+ Log.e("EventSender", "KeyDown: " + character + "("
+ + character.getBytes()[0] + ") Modifiers: "
+ + Arrays.toString(withModifiers));
+ KeyEvent modifier = null;
+ if (withModifiers != null && withModifiers.length > 0) {
+ for (int i = 0; i < withModifiers.length; i++) {
+ int keyCode = modifierMapper(withModifiers[i]);
+ modifier = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+ mWebView.onKeyDown(modifier.getKeyCode(), modifier);
+ }
+ }
+ int keyCode = keyMapper(character.toLowerCase().toCharArray()[0]);
+ KeyEvent event = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+ mWebView.onKeyDown(event.getKeyCode(), event);
+
+ }
+
+ public void keyDown(String character) {
+ keyDown(character, null);
+ }
+
+ public void leapForward(int milliseconds) {
+ // TODO Auto-generated method stub
+
+ }
+
+ public void mouseClick() {
+ mouseDown();
+ mouseUp();
+ }
+
+ public void mouseDown() {
+ /* KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
+ mWebView.onKeyDown(event.getKeyCode(), event); */
+ }
+
+ public void mouseMoveTo(int X, int Y) {
+ if (X > mouseX) {
+ KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
+ mWebView.onKeyDown(event.getKeyCode(), event);
+ mWebView.onKeyUp(event.getKeyCode(), event);
+ } else if ( X < mouseX ) {
+ KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_LEFT);
+ mWebView.onKeyDown(event.getKeyCode(), event);
+ mWebView.onKeyUp(event.getKeyCode(), event);
+ }
+ if (Y > mouseY) {
+ KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_DOWN);
+ mWebView.onKeyDown(event.getKeyCode(), event);
+ mWebView.onKeyUp(event.getKeyCode(), event);
+ } else if (Y < mouseY ) {
+ KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_UP);
+ mWebView.onKeyDown(event.getKeyCode(), event);
+ mWebView.onKeyUp(event.getKeyCode(), event);
+ }
+ mouseX= X;
+ mouseY= Y;
+
+ }
+
+ public void mouseUp() {
+ /* KeyEvent event = new KeyEvent(
+ KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER);
+ mWebView.onKeyDown(event.getKeyCode(), event);*/
+
+ }
+
+ // Assumes lowercase chars, case needs to be
+ // handled by calling function.
+ static int keyMapper(char c) {
+ // handle numbers
+ if (c >= '0' && c<= '9') {
+ int offset = c - '0';
+ return KeyEvent.KEYCODE_0 + offset;
+ }
+
+ // handle characters
+ if (c >= 'a' && c <= 'z') {
+ int offset = c - 'a';
+ return KeyEvent.KEYCODE_A + offset;
+ }
+
+ // handle all others
+ switch (c) {
+ case '*':
+ return KeyEvent.KEYCODE_STAR;
+ case '#':
+ return KeyEvent.KEYCODE_POUND;
+ case ',':
+ return KeyEvent.KEYCODE_COMMA;
+ case '.':
+ return KeyEvent.KEYCODE_PERIOD;
+ case '\t':
+ return KeyEvent.KEYCODE_TAB;
+ case ' ':
+ return KeyEvent.KEYCODE_SPACE;
+ case '\n':
+ return KeyEvent.KEYCODE_ENTER;
+ case '\b':
+ case 0x7F:
+ return KeyEvent.KEYCODE_DEL;
+ case '~':
+ return KeyEvent.KEYCODE_GRAVE;
+ case '-':
+ return KeyEvent.KEYCODE_MINUS;
+ case '=':
+ return KeyEvent.KEYCODE_EQUALS;
+ case '(':
+ return KeyEvent.KEYCODE_LEFT_BRACKET;
+ case ')':
+ return KeyEvent.KEYCODE_RIGHT_BRACKET;
+ case '\\':
+ return KeyEvent.KEYCODE_BACKSLASH;
+ case ';':
+ return KeyEvent.KEYCODE_SEMICOLON;
+ case '\'':
+ return KeyEvent.KEYCODE_APOSTROPHE;
+ case '/':
+ return KeyEvent.KEYCODE_SLASH;
+ default:
+ break;
+ }
+
+ return c;
+ }
+
+ static int modifierMapper(String modifier) {
+ if (modifier.equals("ctrlKey")) {
+ return KeyEvent.KEYCODE_ALT_LEFT;
+ } else if (modifier.equals("shiftKey")) {
+ return KeyEvent.KEYCODE_SHIFT_LEFT;
+ } else if (modifier.equals("altKey")) {
+ return KeyEvent.KEYCODE_SYM;
+ } else if (modifier.equals("metaKey")) {
+ return KeyEvent.KEYCODE_UNKNOWN;
+ }
+ return KeyEvent.KEYCODE_UNKNOWN;
+ }
+
+ private WebView mWebView = null;
+ private int mouseX;
+ private int mouseY;
+
+}
diff --git a/tests/FrameworkTest/Android.mk b/tests/FrameworkTest/Android.mk
new file mode 100644
index 0000000..61cdbfa
--- /dev/null
+++ b/tests/FrameworkTest/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworkTest
+
+include $(BUILD_PACKAGE)
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/FrameworkTest/AndroidManifest.xml b/tests/FrameworkTest/AndroidManifest.xml
new file mode 100644
index 0000000..c70302b
--- /dev/null
+++ b/tests/FrameworkTest/AndroidManifest.xml
@@ -0,0 +1,952 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworktest">
+
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.HARDWARE_TEST" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+
+ <application android:theme="@style/Theme">
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name=".FrameworkTestApplication" android:label="FrameworkTestApplication">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".performance.InvalidateCycle" android:label="InvalidateCycle">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.DescendantFocusability" android:label="DescendantFocusability">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.FocusAfterRemoval" android:label="FocusAfterRemoval">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.RequestFocus" android:label="RequestFocus">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />V
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.ListOfButtons" android:label="ListOfButtons">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.LinearLayoutGrid" android:label="LinearLayoutGrid">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.ListOfEditTexts" android:label="ListOfEditTexts">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.ListOfInternalSelectionViews" android:label="ListOfInternalSelectionViews">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.ListWithFooterViewAndNewLabels" android:label="FocusListWithFooter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.ListWithMailMessages" android:label="ListWithMailMessages">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.HorizontalFocusSearch" android:label="HorizontalFocusSearch">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.VerticalFocusSearch" android:label="VerticalFocusSearch">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.AdjacentVerticalRectLists" android:label="AdjacentVerticalRectLists">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".focus.GoneParentFocusedChild" android:label="GoneParentFocusedChild">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.frame.FrameLayoutGravity" android:label="FrameLayoutGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.frame.FrameLayoutMargin" android:label="FrameLayoutMargin">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.BaselineAlignmentCenterGravity" android:label="BaselineAlignmentCenterGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.BaselineButtons" android:label="BaselineButtons">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.FillInWrap" android:label="FillInWrap">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.BaselineAlignmentZeroWidthAndWeight" android:label="Baseline0WidthAndWeight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.HorizontalOrientationVerticalAlignment" android:label="HorizontalOrientationVerticalAlignment">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.LLEditTextThenButton" android:label="LLEditTextThenButton">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.LLOfButtons1" android:label="LLOfButtons1">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.LinearLayoutEditTexts" android:label="LinearLayoutEditTexts">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.LLOfButtons2" android:label="LLOfButtons2">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.LLOfTwoFocusableInTouchMode" android:label="LLOfTwoFocusableInTouchMode">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.Weight" android:label="Weight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.linear.WeightSum" android:label="WeightSum">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.AdjacentListsWithAdjacentISVsInside" android:label="AdjacentListsWithAdjacentISVsInside">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListDividers" android:label="ListDividers">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListViewHeight" android:label="ListViewHeight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.FixedWidth" android:label="CellFixedWidth">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.Weight" android:label="CellWeight">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.HorizontalGravity" android:label="CellHorizontalGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.VerticalGravity" android:label="CellVerticalGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.AddColumn" android:label="AddColumnInTable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".layout.table.CellSpan" android:label="CellSpan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.ButtonAboveTallInternalSelectionView" android:label="ButtonAboveTallInternalSelectionView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.ButtonsWithTallTextViewInBetween" android:label="scrollButtonsWithTallTextViewInBetween">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.RequestRectangleVisible" android:label="ScrollToChildRect">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.RequestRectangleVisibleWithInternalScroll" android:label="ScrollToChildRectWithInternalScroll">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.ScrollViewButtonsAndLabels" android:label="ScrollViewButtonsAndLabels">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.ShortButtons" android:label="scrollShortButtons">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".scroll.TallTextAboveButton" android:label="scrollTallTextAboveButton">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Include" android:label="IncludeTag">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Merge" android:label="MergeTag">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.StubbedView" android:label="ViewStub">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.RunQueue" android:label="RunQueue">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Visibility" android:label="Visibility">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.BigCache" android:label="BigCache">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.ZeroSized" android:label="ZeroSized">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Disabled" android:label="Disabled">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.PopupWindowVisibility" android:label="PopupWindowVisibility">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.PreDrawListener" android:label="PreDrawListener">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.GlobalFocusChange" android:label="GlobalFocusChange">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListSetSelection" android:label="ListSetSelection">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListSimple" android:label="ListSimple">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListFilter" android:label="ListFilter">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListScrollListener" android:label="ListScrollListener">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListThrasher" android:label="ListThrasher">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListTakeFocusFromSide" android:label="ListTakeFocusFromSide">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListBottomGravity" android:label="ListBottomGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListBottomGravityMany" android:label="ListBottomGravityMany">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+
+ <activity android:name=".listview.ListButtonsDiagonalAcrossItems" android:label="ListButtonsDiagonalAcrossItems">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListTopGravity" android:label="ListTopGravity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListTopGravityMany" android:label="ListTopGravityMany">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListEndingWithMultipleSeparators" android:label="ListEndingWithMultipleSeparators">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListGetSelectedView" android:label="ListGetSelectedView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListInHorizontal" android:label="ListInHorizontal">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListInVertical" android:label="ListInVertical">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListInterleaveFocusables" android:label="ListInterleaveFocusables">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfItemsShorterThanScreen" android:label="ListOfItemsShorterThanScreen">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfItemsTallerThanScreen" android:label="ListOfItemsTallerThanScreen">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfThinItems" android:label="ListOfThinItems">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfShortTallShort" android:label="ListOfShortTallShort">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfShortShortTallShortShort" android:label="ListOfShortShortTallShortShort">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithOffScreenNextSelectable" android:label="ListWithOffScreenNextSelectable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithFirstScreenUnSelectable" android:label="ListWithFirstScreenUnSelectable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+
+ <activity android:name=".listview.ListWithSeparators" android:label="ListWithSeparators">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithHeaders" android:label="ListWithHeaders">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithEditTextHeader" android:label="ListWithEditTextHeader">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+
+ <activity android:name=".listview.ListWithNoFadingEdge" android:label="ListWithNoFadingEdge">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithScreenOfNoSelectables" android:label="ListWithScreenOfNoSelectables">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListItemFocusablesFarApart" android:label="ListItemFocusablesFarApart">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListItemFocusableAboveUnfocusable" android:label="ListItemFocusableAboveUnfocusable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListItemFocusablesClose" android:label="ListItemFocusablesClose">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListLastItemPartiallyVisible" android:label="ListLastItemPartiallyVisible">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListItemsExpandOnSelection" android:label="ListItemsExpandOnSelection">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithOnItemSelectedAction" android:label="ListWithOnItemSelectedAction">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListItemISVAndButton" android:label="ListItemISVAndButton">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListOfTouchables" android:label="ListOfTouchables">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListRecyclerProfiling" android:label="ListRecyclerProfiling">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListHeterogeneous" android:label="ListHeterogeneous">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListHorizontalFocusWithinItemWins" android:label="ListHorizontalFocusWithinItemWins">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListManagedCursor" android:label="ListManagedCursor">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithEmptyView" android:label="ListWithEmptyView">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridInHorizontal" android:label="GridInHorizontal">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridPadding" android:label="GridPadding">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridInVertical" android:label="GridInVertical">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridScrollListener" android:label="GridScrollListener">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridThrasher" android:label="GridThrasher">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSimple" android:label="GridSimple">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridDelete" android:label="GridDelete">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSetSelection" android:label="GridSetSelection">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSetSelectionMany" android:label="GridSetSelectionMany">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSetSelectionStackFromBottom" android:label="GridSetSelectionStackFromBottom">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSetSelectionStackFromBottomMany" android:label="GridSetSelectionStackFromBottomMany">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridStackFromBottom" android:label="GridStackFromBottom">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridStackFromBottomMany" android:label="GridStackFromBottomMany">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridVerticalSpacing" android:label="GridVerticalSpacing">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridVerticalSpacingStackFromBottom" android:label="GridVerticalSpacingStackFromBottom">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".gridview.GridSingleColumn" android:label="GridSingleColumn">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".menus.ListContextMenu" android:label="ListContextMenu">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.ViewGroupChildren" android:label="ViewGroup Children">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.RemoteViewsActivity" android:label="RemoteViewsActicity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".drawable.BitmapDrawable" android:label="BitmapDrawable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".drawable.DrawableBgMinSize" android:label="DrawableBgMinSize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".drawable.MutateDrawable" android:label="MutateDrawable">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".activity.TranslucentFancyActivity" android:label="TranslucentFancyActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".view.Longpress" android:label="Longpress">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".expandablelistview.ExpandableListWithHeaders" android:label="ExpandableListWithHeaders">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".listview.ListWithDisappearingItemBug" android:label="ListWithDisappearingItemBug">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".menus.MenuWith1Item" android:label="MenuWith1Item">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".menus.MenuLayoutPortrait" android:label="MenuLayoutPortrait"
+ android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".menus.MenuLayoutLandscape" android:label="MenuLayoutLandscape"
+ android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".expandablelistview.InflatedExpandableListView" android:label="ExpandableListView Inflated">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".expandablelistview.ExpandableListSimple" android:label="ExpandableListSimple">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".settings.RingtonePickerActivityLauncher" android:label="RingtonePickerActivityLauncher">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".settings.BrightnessLimit" android:label="BrightnessLimit">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name="android.widget.AutoCompleteTextViewSimple"
+ android:label="AutoCompleteTextViewSimple">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/tests/FrameworkTest/README b/tests/FrameworkTest/README
new file mode 100644
index 0000000..d6d0042
--- /dev/null
+++ b/tests/FrameworkTest/README
@@ -0,0 +1,8 @@
+FrameworkTestApplication should hold snippets of functionality that are
+helpful for testing the UI framework code, but not appropriate for
+sample code. For instance, a layout contrived to exercise an edge case
+of scrolling behavior.
+
+InstrumentationTestCases should be added under tests and added to the
+list of tests in FrameworkInstrumentationTestRunner.
+
diff --git a/tests/FrameworkTest/res/drawable/big_drawable_background.9.png b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png
new file mode 100644
index 0000000..aded635
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/big_drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/bitmap_drawable.xml b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml
new file mode 100644
index 0000000..35673ec
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/bitmap_drawable.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:gravity="top|right" />
diff --git a/tests/FrameworkTest/res/drawable/black_square.png b/tests/FrameworkTest/res/drawable/black_square.png
new file mode 100644
index 0000000..1bfe0a2
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/black_square.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png
new file mode 100644
index 0000000..1fcbeb1
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/black_square_stretchable.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/box.xml b/tests/FrameworkTest/res/drawable/box.xml
new file mode 100644
index 0000000..6849bd34
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/box.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/res/drawable/box.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+ <solid android:color="#00000000"/>
+ <stroke android:width="1dp" color="#ff000000"/>
+ <padding android:left="1dp" android:top="1dp"
+ android:right="1dp" android:bottom="1dp" />
+</shape>
diff --git a/tests/FrameworkTest/res/drawable/drawable_background.9.png b/tests/FrameworkTest/res/drawable/drawable_background.9.png
new file mode 100644
index 0000000..1337ba9
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/drawable_background.9.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png
new file mode 100644
index 0000000..2f19d08
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_pause_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png
new file mode 100644
index 0000000..f945a81
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_backward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png
new file mode 100644
index 0000000..da9361a
--- /dev/null
+++ b/tests/FrameworkTest/res/drawable/sym_now_playing_skip_forward_1.png
Binary files differ
diff --git a/tests/FrameworkTest/res/layout/add_column_in_table.xml b/tests/FrameworkTest/res/layout/add_column_in_table.xml
new file mode 100644
index 0000000..62c27f3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/add_column_in_table.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TableLayout android:id="@+id/table"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0">
+
+ <TableRow>
+ <TextView
+ android:text="@string/table_layout_a"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_b"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_c"
+ android:padding="3dip" />
+ </TableRow>
+
+ </TableLayout>
+
+ <Button android:id="@+id/add_row_button"
+ android:text="@string/add_row_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml b/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml
new file mode 100644
index 0000000..d408a86
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/autocompletetextview_simple.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <AutoCompleteTextView
+ android:id="@+id/autocompletetextview1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:inputType="text|textAutoComplete"
+ android:completionThreshold="1" />
+ />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml b/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml
new file mode 100644
index 0000000..83f3fcb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_0width_and_weight.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <LinearLayout android:id="@+id/layout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:visibility="gone">
+ <com.android.frameworktest.layout.linear.ExceptionTextView
+ android:id="@+id/routeToField"
+ android:textSize="16sp"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:lines="2"
+ android:autoText="false"
+ android:capitalize="none"
+ android:maxLines="1" />
+ <Button
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="fill_vertical"
+ android:text="@string/side_button_label" />
+ </LinearLayout>
+ <Button android:id="@+id/show"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:text="@string/show" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_buttons.xml b/tests/FrameworkTest/res/layout/baseline_buttons.xml
new file mode 100644
index 0000000..ae942017
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_buttons.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <TextView android:id="@+id/currenttime"
+ android:text="@string/time"
+ android:textSize="12sp"
+ android:textStyle="bold"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content" />
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal"
+ android:gravity="center">
+
+ <ImageButton android:id="@+id/prev"
+ android:src="@drawable/sym_now_playing_skip_backward_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton android:id="@+id/pause"
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton android:id="@+id/next"
+ android:src="@drawable/sym_now_playing_skip_forward_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+
+ <TextView android:id="@+id/totaltime"
+ android:textSize="12sp"
+ android:textStyle="bold"
+ android:gravity="right"
+ android:text="@string/time"
+ android:layout_gravity="bottom"
+ android:layout_weight="1"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/baseline_center_gravity.xml b/tests/FrameworkTest/res/layout/baseline_center_gravity.xml
new file mode 100644
index 0000000..9793ab4
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/baseline_center_gravity.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+ <Button android:id="@+id/button1"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/side_button_label" />
+ <Button android:id="@+id/button2"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/side_button_label" />
+ <Button android:id="@+id/button3"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_gravity="center"
+ android:text="@string/side_button_label" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/brightness_limit.xml b/tests/FrameworkTest/res/layout/brightness_limit.xml
new file mode 100644
index 0000000..46e5767
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/brightness_limit.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Tries to set brightness to 0. See corresponding Java code. -->
+
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/go"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/go"/>
+
diff --git a/tests/FrameworkTest/res/layout/descendant_focusability.xml b/tests/FrameworkTest/res/layout/descendant_focusability.xml
new file mode 100644
index 0000000..6a30d50d
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/descendant_focusability.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+
+ <LinearLayout
+ android:id="@+id/beforeDescendants"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="beforeDescendants"
+ >
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/afterDescendants"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="afterDescendants"
+ >
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+
+ <LinearLayout
+ android:id="@+id/blocksDescendants"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:descendantFocusability="blocksDescendants"
+ >
+ <Button
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/disabled.xml b/tests/FrameworkTest/res/layout/disabled.xml
new file mode 100644
index 0000000..ed7ff06
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/disabled.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/clickableParent"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button android:id="@+id/disabledButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/disabled_button"/>
+
+ <Button android:id="@+id/disabledButtonA"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/disabled_button"/>
+
+ <Button android:id="@+id/disabledButtonB"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/disabled_button"/>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml b/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml
new file mode 100644
index 0000000..ea0cbfa
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/drawable_background_minimum_size.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/change_backgrounds"
+ android:text="@string/change_backgrounds"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <!-- Different views and layouts that should initially be small but still contain
+ some content (hence the minimal text inside each of the layouts). Each of these
+ will each be tested to make sure they expand to at least the minimum size
+ recommended by different backgrounds -->
+
+ <TextView
+ android:id="@+id/text_view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/minimal_text" />
+
+ <LinearLayout
+ android:id="@+id/linear_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/minimal_text" />
+
+ </LinearLayout>
+
+ <RelativeLayout
+ android:id="@+id/relative_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/minimal_text" />
+
+ </RelativeLayout>
+
+ <FrameLayout
+ android:id="@+id/frame_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/minimal_text" />
+
+ </FrameLayout>
+
+ <AbsoluteLayout
+ android:id="@+id/absolute_layout"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/minimal_text" />
+
+ </AbsoluteLayout>
+
+ </LinearLayout>
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/fill_in_wrap.xml b/tests/FrameworkTest/res/layout/fill_in_wrap.xml
new file mode 100644
index 0000000..b61fd30
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/fill_in_wrap.xml
@@ -0,0 +1,64 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:gravity="center_vertical">
+
+ <Button
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:gravity="left|center_vertical"
+ />
+
+ <LinearLayout android:id="@+id/layout"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingLeft="0dip"
+ android:paddingRight="0dip"
+ android:paddingTop="2dip"
+ android:paddingBottom="2dip"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:addStatesFromChildren="true"
+ android:background="@android:drawable/edit_text"
+ android:gravity="center_vertical">
+
+ <EditText android:id="@+id/data"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="fill_parent"
+ android:layout_marginLeft="8dip"
+ android:paddingBottom="4dip"
+ android:layout_gravity="center_vertical"
+ android:background="@null"
+ />
+
+ <ImageButton
+ style="@android:style/Widget.Button.Inset"
+ android:src="@android:drawable/ic_delete"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="2dip"
+ android:gravity="center"
+ />
+
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/focus_after_removal.xml b/tests/FrameworkTest/res/layout/focus_after_removal.xml
new file mode 100644
index 0000000..7cf6cbe
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/focus_after_removal.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <LinearLayout android:id="@+id/leftLayout"
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/topLeftButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/left_top" />
+ <Button android:id="@+id/bottomLeftButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/left_bottom" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/topRightButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/right_top" />
+ <Button android:id="@+id/bottomRightButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/right_bottom" />
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/focus_listener.xml b/tests/FrameworkTest/res/layout/focus_listener.xml
new file mode 100644
index 0000000..a838205
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/focus_listener.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/left"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/left_top" />
+
+ <Button android:id="@+id/right"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginRight="3dip"
+ android:text="@string/left_bottom" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/framelayout_gravity.xml b/tests/FrameworkTest/res/layout/framelayout_gravity.xml
new file mode 100644
index 0000000..ce48825
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/framelayout_gravity.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button android:id="@+id/left"
+ android:layout_gravity="left"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/right"
+ android:layout_gravity="right"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/center_horizontal"
+ android:layout_gravity="center_horizontal"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/left_center_vertical"
+ android:layout_gravity="center_vertical|left"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/right_center_vertical"
+ android:layout_gravity="center_vertical|right"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/center"
+ android:layout_gravity="center"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/left_bottom"
+ android:layout_gravity="bottom|left"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/right_bottom"
+ android:layout_gravity="bottom|right"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/center_horizontal_bottom"
+ android:layout_gravity="bottom|center_horizontal"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/tests/FrameworkTest/res/layout/framelayout_margin.xml b/tests/FrameworkTest/res/layout/framelayout_margin.xml
new file mode 100644
index 0000000..1e14899
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/framelayout_margin.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/parent"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button android:id="@+id/left"
+ android:layout_gravity="left"
+ android:layout_marginLeft="12dip"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/right"
+ android:layout_gravity="right"
+ android:layout_marginRight="12dip"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/top"
+ android:layout_gravity="top|center_horizontal"
+ android:layout_marginTop="12dip"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/bottom"
+ android:layout_gravity="bottom|center_horizontal"
+ android:layout_marginBottom="12dip"
+ android:text="@string/view"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</FrameLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_in_horizontal.xml b/tests/FrameworkTest/res/layout/grid_in_horizontal.xml
new file mode 100644
index 0000000..835dce3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_in_horizontal.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <GridView android:id="@+id/grid"
+ android:layout_width="0dip"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:padding="10dip"
+ android:verticalSpacing="10dp"
+ android:horizontalSpacing="10dp"
+ android:numColumns="auto_fit"
+ android:columnWidth="60dp"
+ android:stretchMode="columnWidth" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_in_vertical.xml b/tests/FrameworkTest/res/layout/grid_in_vertical.xml
new file mode 100644
index 0000000..731bc54
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_in_vertical.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <GridView android:id="@+id/grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:numColumns="auto_fit" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_padding.xml b/tests/FrameworkTest/res/layout/grid_padding.xml
new file mode 100644
index 0000000..bd666e1
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_padding.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<GridView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/grid"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:verticalSpacing="10dp"
+ android:horizontalSpacing="10dp"
+ android:numColumns="auto_fit"
+ android:columnWidth="50dp" />
diff --git a/tests/FrameworkTest/res/layout/grid_scroll_listener.xml b/tests/FrameworkTest/res/layout/grid_scroll_listener.xml
new file mode 100644
index 0000000..c02aed9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_scroll_listener.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <GridView android:id="@+id/grid"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:padding="10dip"
+ android:verticalSpacing="10dp"
+ android:horizontalSpacing="10dp"
+ android:numColumns="auto_fit"
+ android:columnWidth="60dp"
+ android:stretchMode="columnWidth"
+ android:gravity="center"/>
+
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/grid_thrasher.xml b/tests/FrameworkTest/res/layout/grid_thrasher.xml
new file mode 100644
index 0000000..1a260df
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/grid_thrasher.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <GridView android:id="@+id/grid"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="10dip"
+ android:verticalSpacing="10dp"
+ android:horizontalSpacing="10dp"
+ android:numColumns="auto_fit"
+ android:columnWidth="60dp"
+ android:stretchMode="columnWidth"
+ android:gravity="center"/>
+
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/include_button.xml b/tests/FrameworkTest/res/layout/include_button.xml
new file mode 100644
index 0000000..5857fa3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_button.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/included_button"
+ android:text="@string/include_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
diff --git a/tests/FrameworkTest/res/layout/include_button_with_size.xml b/tests/FrameworkTest/res/layout/include_button_with_size.xml
new file mode 100644
index 0000000..0cd8eaa
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_button_with_size.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/included_button"
+ android:text="@string/include_button"
+ android:layout_width="23dip"
+ android:layout_height="23dip" />
diff --git a/tests/FrameworkTest/res/layout/include_tag.xml b/tests/FrameworkTest/res/layout/include_tag.xml
new file mode 100644
index 0000000..d1047f1
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/include_tag.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <include
+ layout="@layout/include_button" />
+
+ <include
+ layout="@layout/include_button"
+ android:id="@+id/included_button_overriden"
+ android:layout_width="237dip"
+ android:layout_height="123dip" />
+
+ <include
+ layout="@layout/include_button"
+ android:id="@+id/included_button_visibility"
+ android:visibility="invisible" />
+
+ <include
+ layout="@layout/include_button_with_size"
+ android:id="@+id/included_button_with_size" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml b/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml
new file mode 100644
index 0000000..d01e7c5
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/inflated_expandablelistview.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ExpandableListView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/elv"
+ android:layout_height="fill_parent"
+ android:layout_width="fill_parent" />
diff --git a/tests/FrameworkTest/res/layout/linear_layout_buttons.xml b/tests/FrameworkTest/res/layout/linear_layout_buttons.xml
new file mode 100644
index 0000000..f60692a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_buttons.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:text="@string/keypad_one"/>
+
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:text="@string/keypad_two"/>
+
+ <Button
+ android:id="@+id/button3"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:text="@string/keypad_three"/>
+
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml b/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml
new file mode 100644
index 0000000..21e7399
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_edittext_then_button.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <EditText
+ android:id="@+id/editText"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"/>
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:text="@string/keypad_one"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_grid.xml b/tests/FrameworkTest/res/layout/linear_layout_grid.xml
new file mode 100644
index 0000000..81f7b15
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_grid.xml
@@ -0,0 +1,101 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <LinearLayout android:id="@+id/column1"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_one"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_two"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_three"/>
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/column2"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_four"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_five"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_six"/>
+ </LinearLayout>
+
+ <LinearLayout android:id="@+id/column3"
+ android:layout_width="fill_parent"
+ android:layout_height="0sp"
+ android:layout_weight="1"
+ android:orientation="horizontal">
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_seven"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_eight"/>
+
+ <Button
+ android:layout_width="0sp"
+ android:layout_height="fill_parent"
+ android:layout_weight="1"
+ android:text="@string/keypad_nine"/>
+ </LinearLayout>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml b/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml
new file mode 100644
index 0000000..10ef2ce
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_listview_height.xml
@@ -0,0 +1,66 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <!-- Outer linear layout providing vertical layout -->
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <!-- The control buttons -->
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" >
+
+ <Button
+ android:id="@+id/button1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/linear_listheight_fixed"/>
+
+ <Button
+ android:id="@+id/button2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/linear_listheight_fill"/>
+
+ <Button
+ android:id="@+id/button3"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/linear_listheight_hide"/>
+ </LinearLayout>
+
+ <!-- The list view -->
+ <ListView
+ android:id="@+id/inner_list"
+ android:layout_width="200dip"
+ android:layout_height="fill_parent"
+ android:background="@android:drawable/spinner_dropdown_background"
+ android:divider="@android:drawable/divider_horizontal_bright" />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml b/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml
new file mode 100644
index 0000000..7ed245b
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_spinner_then_button.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <Spinner android:id="@+id/reminder_value"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.7"
+ android:entries="@array/reminder_minutes_labels"/>
+
+ <Button android:id="@+id/reminder_remove"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="0.3"
+ android:text="@string/show" />
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_textviews.xml b/tests/FrameworkTest/res/layout/linear_layout_textviews.xml
new file mode 100644
index 0000000..84a898c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_textviews.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:background="#FFFF0000"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <EditText
+ android:id="@+id/editText1"
+ android:text="@string/text"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+ <EditText
+ android:id="@+id/editText2"
+ android:text="@string/text"
+ android:layout_width="0dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/linear_layout_weight.xml b/tests/FrameworkTest/res/layout/linear_layout_weight.xml
new file mode 100644
index 0000000..bb138df
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/linear_layout_weight.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:background="#FFFFFFFF"
+ android:orientation="horizontal"
+ android:layout_width="87dip"
+ android:layout_height="wrap_content">
+
+ <View
+ android:id="@+id/child1"
+ android:background="#FFFF0000"
+ android:layout_width="20dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+ <View
+ android:id="@+id/child2"
+ android:background="#FF00FF00"
+ android:layout_width="20dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+ <View
+ android:background="#FF0000FF"
+ android:id="@+id/child3"
+ android:layout_width="20dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+ <View
+ android:background="#FFFF00FF"
+ android:id="@+id/child4"
+ android:layout_width="20dip"
+ android:layout_height="wrap_content"
+ android:layout_weight="1.0" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_dividers.xml b/tests/FrameworkTest/res/layout/list_dividers.xml
new file mode 100644
index 0000000..b56511e6
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_dividers.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ListView android:id="@android:id/list"
+ android:paddingRight="15dip"
+ android:layout_marginLeft="50dip"
+ android:layout_width="150dip"
+ android:layout_height="300dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_filter.xml b/tests/FrameworkTest/res/layout/list_filter.xml
new file mode 100644
index 0000000..cea518c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_filter.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <FrameLayout android:id="@+id/frame"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:drawSelectorOnTop="false" />
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/hide"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hide" />
+
+ <Button android:id="@+id/show"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/show" />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_in_horizontal.xml b/tests/FrameworkTest/res/layout/list_in_horizontal.xml
new file mode 100644
index 0000000..371cb84
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_in_horizontal.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TableRow>
+
+ <ListView android:id="@+id/list" />
+
+ <ImageButton android:src="@drawable/sym_now_playing_pause_1" />
+
+ </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/list_in_vertical.xml b/tests/FrameworkTest/res/layout/list_in_vertical.xml
new file mode 100644
index 0000000..0ea2475
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_in_vertical.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <ListView android:id="@+id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/list_recycler_profiling.xml b/tests/FrameworkTest/res/layout/list_recycler_profiling.xml
new file mode 100644
index 0000000..9678eb7
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_recycler_profiling.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <ListView android:id="@+id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1.0" />
+
+ <ImageButton android:id="@+id/pause"
+ android:src="@drawable/sym_now_playing_pause_1"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_scroll_listener.xml b/tests/FrameworkTest/res/layout/list_scroll_listener.xml
new file mode 100644
index 0000000..001296a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_scroll_listener.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:drawSelectorOnTop="false"/>
+
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml b/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml
new file mode 100644
index 0000000..cf141cc
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_take_focus_from_side.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="fill_parent"
+ android:drawSelectorOnTop="false"/>
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/side_button_label" />
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_thrasher.xml b/tests/FrameworkTest/res/layout/list_thrasher.xml
new file mode 100644
index 0000000..001296a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_thrasher.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:drawSelectorOnTop="false"/>
+
+ <TextView android:id="@+id/text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_button_above.xml b/tests/FrameworkTest/res/layout/list_with_button_above.xml
new file mode 100644
index 0000000..25db016
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_button_above.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Simple layout with a button and a list below, can be used to build more
+ sophisticated test cases by adding stuff to the list programatically.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+
+ <Button android:id="@+id/button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/button_above_list_label"/>
+
+
+ <ListView android:id="@android:id/list"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1"
+ android:paddingTop="2dip"
+ android:drawSelectorOnTop="false"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml b/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml
new file mode 100644
index 0000000..0163d96
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_disappearing_item_bug_item.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- A layout is needed to reprod the bug. -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="?android:attr/listPreferredItemHeight">
+
+ <TextView
+ android:id="@+id/text1"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:textAppearance="?android:attr/textAppearanceLarge"
+ android:gravity="center_vertical"
+ android:paddingLeft="27dip"
+ />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/list_with_empty_view.xml b/tests/FrameworkTest/res/layout/list_with_empty_view.xml
new file mode 100644
index 0000000..00d81a7
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/list_with_empty_view.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <ListView android:id="@android:id/list"
+ android:drawSelectorOnTop="false"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"/>
+
+ <TextView android:id="@+id/empty"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center"
+ android:textSize="36sp"
+ android:textColor="#999"
+ android:visibility="gone"
+ android:text="@string/empty_list" />
+
+</FrameLayout>
diff --git a/tests/FrameworkTest/res/layout/longpress.xml b/tests/FrameworkTest/res/layout/longpress.xml
new file mode 100644
index 0000000..ef3672c
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/longpress.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <View android:id="@+id/simple_view"
+ android:background="@drawable/blue"
+ android:layout_width="20dip"
+ android:layout_height="20dip"
+ android:focusable="true" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/mail_message.xml b/tests/FrameworkTest/res/layout/mail_message.xml
new file mode 100644
index 0000000..ed52751
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/mail_message.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- A layout similar to a gmail message. useful for setting up tests, like
+ a list with a list of messages.-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView android:id="@+id/subject"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <WebView android:id="@+id/body"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/merge_child.xml b/tests/FrameworkTest/res/layout/merge_child.xml
new file mode 100644
index 0000000..9972924
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/merge_child.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</merge>
diff --git a/tests/FrameworkTest/res/layout/merge_tag.xml b/tests/FrameworkTest/res/layout/merge_tag.xml
new file mode 100644
index 0000000..9eec493
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/merge_tag.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <TextView
+ android:text="@string/include_label"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <include layout="@layout/merge_child" />
+
+</merge>
diff --git a/tests/FrameworkTest/res/layout/popup_window_visibility.xml b/tests/FrameworkTest/res/layout/popup_window_visibility.xml
new file mode 100644
index 0000000..21c94bb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/popup_window_visibility.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <FrameLayout android:id="@+id/frame"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Spinner android:id="@+id/spinner"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content" />
+
+ <AutoCompleteTextView android:id="@+id/auto"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+ </FrameLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/hide"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/hide" />
+
+ <Button android:id="@+id/show"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/show" />
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/pre_draw_listener.xml b/tests/FrameworkTest/res/layout/pre_draw_listener.xml
new file mode 100644
index 0000000..d348d9f
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/pre_draw_listener.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+
+ <ScrollView
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="0dip"
+ android:layout_weight="1">
+
+ <view class="com.android.frameworktest.view.PreDrawListener$MyLinearLayout" android:id="@+id/frame"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" />
+
+ </ScrollView>
+
+ <Button android:id="@+id/go"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/go" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_host.xml b/tests/FrameworkTest/res/layout/remote_view_host.xml
new file mode 100644
index 0000000..dc52181
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_host.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml b/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml
new file mode 100644
index 0000000..6a65976
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_bad_1.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linear"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <EditText android:id="@+id/edit"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml b/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml
new file mode 100644
index 0000000..70613c3
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_bad_2.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linear"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <WebView android:id="@+id/web"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/remote_view_test_good.xml b/tests/FrameworkTest/res/layout/remote_view_test_good.xml
new file mode 100644
index 0000000..54f4db9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/remote_view_test_good.xml
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linear"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <TextView android:id="@+id/text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageView android:id="@+id/image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <FrameLayout android:id="@+id/frame"
+ android:layout_width="10dip"
+ android:layout_height="10dip" />
+
+ <RelativeLayout android:id="@+id/relative"
+ android:layout_width="10dip"
+ android:layout_height="10dip" />
+
+ <AbsoluteLayout android:id="@+id/absolute"
+ android:layout_width="10dip"
+ android:layout_height="10dip" />
+
+ <ProgressBar android:id="@+id/progress"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ImageButton android:id="@+id/image_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <Button android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml b/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml
new file mode 100644
index 0000000..d22122d
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scroll_to_rect_with_internal_scroll.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/scroll_view_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates scrolling with a ScrollView. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scrollView"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+
+ <Button android:id="@+id/scrollToBlob"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/scroll_top_button"/>
+
+ <TextView android:id="@+id/blob"
+ android:layout_width="fill_parent"
+ android:layout_height="80dip"
+ android:layout_marginTop="500dip"
+ android:layout_marginBottom="5dip"/>
+
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml b/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml
new file mode 100644
index 0000000..0839b1a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scroll_to_rectangle.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/scroll_view_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates scrolling with a ScrollView. -->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scrollView"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+
+ <Button android:id="@+id/scrollToRectFromTop"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/scroll_top_button"/>
+
+ <Button android:id="@+id/scrollToRectFromTop2"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingBottom="10dip"
+ android:text="@string/scroll_top_button2"/>
+
+ <TextView android:id="@+id/topBlob"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"/>
+
+ <TextView android:id="@+id/childToMakeVisible"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"
+ android:text="@string/scroll_to_me"/>
+
+ <TextView android:id="@+id/bottomBlob"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="5dip"
+ android:layout_marginBottom="5dip"/>
+
+ <Button android:id="@+id/scrollToRectFromBottom2"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:paddingTop="10dip"
+ android:text="@string/scroll_bottom_button2"/>
+
+ <Button android:id="@+id/scrollToRectFromBottom"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/scroll_bottom_button"/>
+
+
+ </LinearLayout>
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml b/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml
new file mode 100644
index 0000000..536d2ed
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scrollview_linear_layout.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scrollView"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ </LinearLayout>
+
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml b/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml
new file mode 100644
index 0000000..79634752
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/scrollview_with_webviews.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/scrollView"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="none">
+
+ <LinearLayout
+ android:id="@+id/layout"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+
+ <WebView android:id="@+id/wb1"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <Button android:id="@+id/button"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ <WebView android:id="@+id/wb2"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"/>
+
+ </LinearLayout>
+
+
+</ScrollView>
diff --git a/tests/FrameworkTest/res/layout/table_layout_cell_span.xml b/tests/FrameworkTest/res/layout/table_layout_cell_span.xml
new file mode 100644
index 0000000..26831e4
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_cell_span.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow>
+ <TextView android:id="@+id/a"
+ android:text="@string/table_layout_a"
+ android:background="#FFFF0000"
+ android:padding="3dip" />
+ <TextView android:id="@+id/b"
+ android:text="@string/table_layout_b"
+ android:background="#FF00FF00"
+ android:padding="3dip" />
+ <TextView android:id="@+id/c"
+ android:text="@string/table_layout_c"
+ android:background="#FF0000FF"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <TextView android:id="@+id/spanThenCell"
+ android:text="@string/table_layout_d"
+ android:layout_span="2"
+ android:gravity="center_horizontal"
+ android:background="#FF0000FF"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_e"
+ android:background="#FF00FF00"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <TextView
+ android:text="@string/table_layout_f"
+ android:background="#FFFF00FF"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_g"
+ android:background="#FF00FF00"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_h"
+ android:background="#FFFF0000"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <TextView
+ android:text="@string/table_layout_a"
+ android:background="#FF00FF00"
+ android:padding="3dip" />
+ <TextView android:id="@+id/cellThenSpan"
+ android:text="@string/table_layout_b"
+ android:layout_span="2"
+ android:gravity="center_horizontal"
+ android:background="#FF0000FF"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <TextView android:id="@+id/span"
+ android:text="@string/table_layout_g"
+ android:layout_span="3"
+ android:gravity="center_horizontal"
+ android:background="#FFC0C0C0"
+ android:padding="3dip" />
+ </TableRow>
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml b/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml
new file mode 100644
index 0000000..91d9128
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_fixed_width.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow>
+ <View android:id="@+id/fixed_height"
+ android:layout_height="48dip"
+ android:background="#FF909090" />
+ <TextView android:id="@+id/fixed_width"
+ android:layout_width="150dip"
+ android:text="@string/table_layout_export"
+ android:background="#FFFF0000"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_export_shortcut"
+ android:background="#FF00FFFF"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <View
+ android:layout_height="48dip"
+ android:background="#FF909090" />
+ <TextView android:id="@+id/non_fixed_width"
+ android:text="@string/table_layout_export"
+ android:background="#FFFF0000"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_export_shortcut"
+ android:background="#FF00FFFF"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml b/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml
new file mode 100644
index 0000000..dee81a5
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_horizontal_gravity.xml
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:stretchColumns="1">
+
+ <TableRow>
+ <TextView android:id="@+id/reference"
+ android:layout_column="1"
+ android:background="#FF0000FF"
+ android:text="@string/table_layout_open"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_open_shortcut"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <!-- Horizontally centers the content of the cell -->
+ <TextView android:id="@+id/center"
+ android:layout_column="1"
+ android:text="@string/table_layout_save_as"
+ android:background="#FFFF0000"
+ android:layout_gravity="center_horizontal"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_save_as_shortcut"
+ android:background="#FFFF00FF"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <View
+ android:layout_height="24dip"
+ android:background="#FF909090" />
+ <!-- Aligns the content of the cell to the bottom right -->
+ <TextView android:id="@+id/bottomRight"
+ android:text="@string/table_layout_export"
+ android:background="#FFFF0000"
+ android:layout_gravity="right|bottom"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_export_shortcut"
+ android:background="#FF00FFFF"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+
+
+ <TableRow>
+ <TextView android:id="@+id/left"
+ android:layout_column="1"
+ android:background="#FF0000FF"
+ android:text="@string/table_layout_open"
+ android:padding="3dip" />
+ <TextView
+ android:text="@string/table_layout_open_shortcut"
+ android:gravity="right"
+ android:padding="3dip" />
+ </TableRow>
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml b/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml
new file mode 100644
index 0000000..6a8b784
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_vertical_gravity.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow>
+ <View android:id="@+id/reference1"
+ android:layout_height="96dip"
+ android:background="#FF909090" />
+ <TextView
+ android:background="#FF0000FF"
+ android:text="@string/table_layout_open"
+ android:padding="3dip" />
+ <TextView android:id="@+id/cell_top"
+ android:background="#FF00FF00"
+ android:layout_gravity="top"
+ android:text="@string/table_layout_open_shortcut"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <View android:id="@+id/reference2"
+ android:layout_height="96dip"
+ android:background="#FF909090" />
+ <TextView
+ android:background="#FF0000FF"
+ android:text="@string/table_layout_open"
+ android:padding="3dip" />
+ <TextView android:id="@+id/cell_center"
+ android:background="#FF00FF00"
+ android:layout_gravity="center_vertical"
+ android:text="@string/table_layout_open_shortcut"
+ android:padding="3dip" />
+ </TableRow>
+
+ <TableRow>
+ <View android:id="@+id/reference3"
+ android:layout_height="96dip"
+ android:background="#FF909090" />
+ <TextView
+ android:background="#FF0000FF"
+ android:text="@string/table_layout_open"
+ android:padding="3dip" />
+ <TextView android:id="@+id/cell_bottom"
+ android:background="#FF00FF00"
+ android:layout_gravity="bottom"
+ android:text="@string/table_layout_open_shortcut"
+ android:padding="3dip" />
+ </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/table_layout_weight.xml b/tests/FrameworkTest/res/layout/table_layout_weight.xml
new file mode 100644
index 0000000..432c04a
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/table_layout_weight.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<TableLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TableRow android:id="@+id/row"
+ android:weightSum="0.9">
+ <View android:id="@+id/cell1"
+ android:layout_width="0dip"
+ android:layout_weight="0.3"
+ android:layout_height="190dip"
+ android:background="#FF0000FF" />
+ <View android:id="@+id/cell2"
+ android:layout_width="0dip"
+ android:layout_weight="0.3"
+ android:layout_height="190dip"
+ android:background="#FFFFFFFF" />
+ <View android:id="@+id/cell3"
+ android:layout_width="0dip"
+ android:layout_weight="0.3"
+ android:layout_height="190dip"
+ android:background="#FFFF0000" />
+ </TableRow>
+
+</TableLayout>
diff --git a/tests/FrameworkTest/res/layout/translucent_background.xml b/tests/FrameworkTest/res/layout/translucent_background.xml
new file mode 100644
index 0000000..6b6e1cf
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/translucent_background.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- Demonstrates an activity with a fancy translucent background.
+ See corresponding Java code com.android.sdk.app.TranslucentBackground.java. -->
+
+<!-- This screen consists of a single text field that displays some text. -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/text"
+ android:layout_width="fill_parent" android:layout_height="fill_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="@string/translucent_background"/>
diff --git a/tests/FrameworkTest/res/layout/viewgroupchildren.xml b/tests/FrameworkTest/res/layout/viewgroupchildren.xml
new file mode 100644
index 0000000..a5bb7cb
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/viewgroupchildren.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates adding/removing views from ViewGroup. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/group"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/viewstub.xml b/tests/FrameworkTest/res/layout/viewstub.xml
new file mode 100644
index 0000000..9a6f376
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/viewstub.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button android:id="@+id/vis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_vis" />
+
+ <ViewStub android:id="@+id/viewStub"
+ android:layout="@layout/linear_layout_buttons"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content" />
+
+ <ViewStub android:id="@+id/viewStubWithId"
+ android:inflatedId="@+id/stub_inflated"
+ android:layout="@layout/linear_layout_buttons"
+ android:layout_width="47dip"
+ android:layout_height="127dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/visibility.xml b/tests/FrameworkTest/res/layout/visibility.xml
new file mode 100644
index 0000000..b4f9d8b
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/visibility.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <LinearLayout
+ android:orientation="vertical"
+ android:background="@drawable/box"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content">
+
+ <TextView android:id="@+id/refUp"
+ android:background="@drawable/red"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_view_1"/>
+
+ <TextView android:id="@+id/victim"
+ android:background="@drawable/green"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_view_2"/>
+
+ <TextView android:id="@+id/refDown"
+ android:background="@drawable/blue"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_view_3"/>
+
+ </LinearLayout>
+
+ <LinearLayout
+ android:orientation="horizontal"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content">
+
+ <Button android:id="@+id/vis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_vis"/>
+
+ <Button android:id="@+id/invis"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_invis"/>
+
+ <Button android:id="@+id/gone"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_gone"/>
+
+ </LinearLayout>
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/weight_sum.xml b/tests/FrameworkTest/res/layout/weight_sum.xml
new file mode 100644
index 0000000..249dc68
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/weight_sum.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:weightSum="1.0"
+ android:gravity="center_horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <Button android:id="@+id/child"
+ android:layout_width="0dip"
+ android:layout_weight="0.5"
+ android:layout_height="wrap_content"
+ android:text="@string/visibility_1_vis"/>
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/with_bitmap_background.xml b/tests/FrameworkTest/res/layout/with_bitmap_background.xml
new file mode 100644
index 0000000..b32d99e
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/with_bitmap_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<LinearLayout android:id="@+id/container" xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="horizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:background="@drawable/bitmap_drawable">
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/layout/zero_sized.xml b/tests/FrameworkTest/res/layout/zero_sized.xml
new file mode 100644
index 0000000..c837bf9
--- /dev/null
+++ b/tests/FrameworkTest/res/layout/zero_sized.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- Demonstrates changing view visibility. See corresponding Java code. -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+
+ <View android:id="@+id/dimension"
+ android:background="#ffff0000"
+ android:layout_width="42dip"
+ android:layout_height="42dip" />
+
+ <View android:id="@+id/noWidth"
+ android:background="#ff00ff00"
+ android:layout_width="0dip"
+ android:layout_height="42dip" />
+
+ <View android:id="@+id/noHeight"
+ android:background="#ff0000ff"
+ android:layout_width="42dip"
+ android:layout_height="0dip" />
+
+ <View android:id="@+id/noDimension"
+ android:background="#ffffffff"
+ android:layout_width="0dip"
+ android:layout_height="0dip" />
+
+</LinearLayout>
diff --git a/tests/FrameworkTest/res/values/arrays.xml b/tests/FrameworkTest/res/values/arrays.xml
new file mode 100644
index 0000000..f76da85
--- /dev/null
+++ b/tests/FrameworkTest/res/values/arrays.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string-array name="reminder_minutes_labels">
+ <item>5 minutes</item>
+ <item>10 minutes</item>
+ <item>15 minutes</item>
+ <item>20 minutes</item>
+ <item>25 minutes</item>
+ <item>30 minutes</item>
+ <item>45 minutes</item>
+ <item>1 hour</item>
+ <item>2 hours</item>
+ <item>3 hours</item>
+ <item>12 hours</item>
+ <item>24 hours</item>
+ <item>2 days</item>
+ <item>1 week</item>
+ </string-array>
+</resources>
diff --git a/tests/FrameworkTest/res/values/attrs.xml b/tests/FrameworkTest/res/values/attrs.xml
new file mode 100644
index 0000000..bf59e74
--- /dev/null
+++ b/tests/FrameworkTest/res/values/attrs.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <declare-styleable name="SelectableRowView">
+ <attr name="numRows" format="integer" />
+ </declare-styleable>
+</resources>
diff --git a/tests/FrameworkTest/res/values/colors.xml b/tests/FrameworkTest/res/values/colors.xml
new file mode 100644
index 0000000..f881660
--- /dev/null
+++ b/tests/FrameworkTest/res/values/colors.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/values/colors.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<resources>
+ <drawable name="red">#ffff0000</drawable>
+ <drawable name="blue">#ff0000ff</drawable>
+ <drawable name="green">#ff00ff00</drawable>
+ <drawable name="yellow">#ffffff00</drawable>
+</resources>
diff --git a/tests/FrameworkTest/res/values/strings.xml b/tests/FrameworkTest/res/values/strings.xml
new file mode 100644
index 0000000..05b57e0
--- /dev/null
+++ b/tests/FrameworkTest/res/values/strings.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">FrameworkTestApplication</string>
+
+ <!-- FocusAfterRemoval -->
+ <string name="left_top">parent GONE</string>
+ <string name="left_bottom">parent INVISIBLE</string>
+ <string name="right_top">me GONE</string>
+ <string name="right_bottom">me INVISIBLE</string>
+
+ <!-- Strings for the 12 key dialer -->
+ <string name="keypad_one">1</string>
+ <string name="keypad_two">"2\nabc"</string>
+ <string name="keypad_three">"3\ndef"</string>
+ <string name="keypad_four">"4\nghi"</string>
+ <string name="keypad_five">"5\njkl"</string>
+ <string name="keypad_six">"6\nmno"</string>
+ <string name="keypad_seven">"7\npqrs"</string>
+ <string name="keypad_eight">"8\ntuv"</string>
+ <string name="keypad_nine">"9\nwxyz"</string>
+ <string name="keypad_zero">0</string>
+ <string name="keypad_star">*</string>
+ <string name="keypad_pound">"#"</string>
+
+
+ <!-- HorizontalGravity -->
+ <string name="table_layout_open">Open\u2026</string>
+ <string name="table_layout_open_shortcut">Ctrl-O</string>
+ <string name="table_layout_save_as">Save As\u2026</string>
+ <string name="table_layout_save_as_shortcut">Ctrl-Shift-S</string>
+ <string name="table_layout_export">Export\u2026</string>
+ <string name="table_layout_export_shortcut">Ctrl-E</string>
+
+ <!-- CellSpan -->
+ <string name="table_layout_a">A</string>
+ <string name="table_layout_b">BB</string>
+ <string name="table_layout_c">CCCC</string>
+ <string name="table_layout_d">D</string>
+ <string name="table_layout_e">E</string>
+ <string name="table_layout_f">F</string>
+ <string name="table_layout_g">G</string>
+ <string name="table_layout_h">H</string>
+
+ <!-- scroll_to_rectangle -->
+ <string name="scroll_top_button">Click to make "hi!" on screen</string>
+ <string name="scroll_top_button2">Click to make blob on screen</string>
+ <string name="scroll_to_me">hi!</string>
+ <string name="scroll_bottom_button2">Click to make blob on screen</string>
+ <string name="scroll_bottom_button">Click to make "hi!" on screen</string>
+
+ <!-- Visibility -->
+ <string name="visibility_1_view_1">View A</string>
+ <string name="visibility_1_view_2">View B</string>
+ <string name="visibility_1_view_3">View C</string>
+ <string name="visibility_1_vis">Visible</string>
+ <string name="visibility_1_invis">Invisible</string>
+ <string name="visibility_1_gone">Gone</string>
+
+ <string name="submit">submit</string>
+ <string name="cancel">cancel</string>
+ <string name="enter_title">enter title</string>
+ <string name="enter_url">enter url</string>
+
+ <!-- List with button above -->
+ <string name="button_above_list_label">Button above list</string>
+
+ <!-- List take focus from side -->
+ <string name="side_button_label">X</string>
+
+ <!-- Linear Layout show/hide & sizing -->
+ <string name="linear_listheight_fixed">Fixed Size</string>
+ <string name="linear_listheight_fill">Fill Screen</string>
+ <string name="linear_listheight_hide">Hide</string>
+
+ <!-- Baseline -->
+ <string name="show">Show</string>
+ <string name="time">00:00:00</string>
+
+ <!-- Drawable -->
+ <string name="minimal_text">a</string>
+ <string name="change_backgrounds">Change backgrounds</string>
+
+ <!-- List with empty view -->
+ <string name="empty_list">Empty list</string>
+ <string name="menu_add">Add</string>
+ <string name="menu_remove">Remove</string>
+
+ <!-- Misc. -->
+ <string name="add_row_button">Add Row</string>
+ <string name="disabled_button">Disabled</string>
+ <string name="translucent_background">Example of how you can make an
+ activity have a translucent background, compositing over
+ whatever is behind it.</string>
+ <string name="text">Lorem ipsum datum carat casus belli honorare</string>
+
+ <string name="hide">Hide</string>
+ <string name="go">Go</string>
+
+ <string name="include_label">Included views below:</string>
+ <string name="include_button">I was included!</string>
+
+ <string name="view">View</string>
+</resources>
diff --git a/tests/FrameworkTest/res/values/styles.xml b/tests/FrameworkTest/res/values/styles.xml
new file mode 100644
index 0000000..7a90197
--- /dev/null
+++ b/tests/FrameworkTest/res/values/styles.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<resources>
+ <style name="Theme" parent="android:Theme">
+ <item name="android:windowAnimationStyle">@style/Animation</item>
+ </style>
+
+ <style name="Animation">
+ <item name="android:activityOpenEnterAnimation">@null</item>
+ <item name="android:activityOpenExitAnimation">@null</item>
+ <item name="android:activityCloseEnterAnimation">@null</item>
+ <item name="android:activityCloseExitAnimation">@null</item>
+ <item name="android:taskOpenEnterAnimation">@null</item>
+ <item name="android:taskOpenExitAnimation">@null</item>
+ <item name="android:taskCloseEnterAnimation">@null</item>
+ <item name="android:taskCloseExitAnimation">@null</item>
+ <item name="android:taskToFrontEnterAnimation">@null</item>
+ <item name="android:taskToFrontExitAnimation">@null</item>
+ <item name="android:taskToBackEnterAnimation">@null</item>
+ <item name="android:taskToBackExitAnimation">@null</item>
+ </style>
+</resources>
diff --git a/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java b/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java
new file mode 100644
index 0000000..af16cf8
--- /dev/null
+++ b/tests/FrameworkTest/src/android/widget/AutoCompleteTextViewSimple.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.AdapterView.OnItemClickListener;
+import android.widget.AdapterView.OnItemSelectedListener;
+
+public class AutoCompleteTextViewSimple extends Activity
+ implements OnItemClickListener, OnItemSelectedListener {
+
+ private final String LOG_TAG = "AutoCompleteTextViewSimple";
+
+ private AutoCompleteTextView mTextView;
+
+ /** These are cleared by resetItemListeners(), and set by the callback listeners */
+ public boolean mItemClickCalled;
+ public int mItemClickPosition;
+ public boolean mItemSelectedCalled;
+ public int mItemSelectedPosition;
+ public boolean mNothingSelectedCalled;
+
+ @Override
+ protected void onCreate(Bundle icicle)
+ {
+ // Be sure to call the super class.
+ super.onCreate(icicle);
+
+ // setup layout & views
+ setContentView(R.layout.autocompletetextview_simple);
+ mTextView = (AutoCompleteTextView) findViewById(R.id.autocompletetextview1);
+
+ // configure callbacks used for monitoring
+ mTextView.setOnItemClickListener(this);
+ mTextView.setOnItemSelectedListener(this);
+ resetItemListeners();
+
+ setStringAdapter(5, "a");
+ }
+
+ /**
+ * @return The AutoCompleteTextView used in this test activity.
+ */
+ public AutoCompleteTextView getTextView() {
+ return mTextView;
+ }
+
+ /**
+ * Set the autocomplete data to an adapter containing 0..n strings with a consistent prefix.
+ */
+ public void setStringAdapter(int numSuggestions, String prefix) {
+ // generate the string array
+ String[] strings = new String[numSuggestions];
+ for (int i = 0; i < numSuggestions; ++i) {
+ strings[i] = prefix + String.valueOf(i);
+ }
+
+ // install it with an adapter
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, strings);
+ mTextView.setAdapter(adapter);
+ }
+
+ /**
+ * For monitoring OnItemClickListener & OnItemSelectedListener
+ *
+ * An alternative here would be to provide a set of pass-through callbacks
+ */
+ public void resetItemListeners() {
+ mItemClickCalled = false;
+ mItemClickPosition = -1;
+ mItemSelectedCalled = false;
+ mItemSelectedPosition = -1;
+ mNothingSelectedCalled = false;
+ }
+
+ /**
+ * Implements OnItemClickListener
+ */
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ Log.d(LOG_TAG, "onItemClick() position " + position);
+ mItemClickCalled = true;
+ mItemClickPosition = position;
+ }
+
+ /**
+ * Implements OnItemSelectedListener
+ */
+ public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+ Log.d(LOG_TAG, "onItemSelected() position " + position);
+ mItemSelectedCalled = true;
+ mItemSelectedPosition = position;
+ }
+
+ /**
+ * Implements OnItemSelectedListener
+ */
+ public void onNothingSelected(AdapterView<?> parent) {
+ Log.d(LOG_TAG, "onNothingSelected()");
+ mNothingSelectedCalled = true;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java b/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java
new file mode 100644
index 0000000..e76f387
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/FrameworkTestApplication.java
@@ -0,0 +1,19 @@
+package com.android.frameworktest;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+/**
+ * Holds little snippets of functionality used as code under test for
+ * instrumentation tests of framework code.
+ */
+public class FrameworkTestApplication extends LauncherActivity {
+
+ protected Intent getTargetIntent() {
+ // TODO: partition into categories by label like the sample code app
+ Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+ targetIntent.addCategory(Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);
+ targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return targetIntent;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java b/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java
new file mode 100644
index 0000000..9492f91
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/activity/TranslucentFancyActivity.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.activity;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+
+/**
+ * <h3>Fancy Translucent Activity</h3>
+ *
+ * <p>This demonstrates the how to write an activity that is translucent,
+ * allowing windows underneath to show through, with a fancy
+ * compositing effect.</p>
+ *
+ * <h4>Demo</h4>
+ * App/Activity/Translucent Fancy
+ *
+ * <h4>Source files</h4>
+ * <table class="LinkTable">
+ * <tr>
+ * <td >src/com/android/samples/app/TranslucentFancyActivity.java</td>
+ * <td >The Translucent Fancy Screen implementation</td>
+ * </tr>
+ * <tr>
+ * <td >/res/any/layout/translucent_background.xml</td>
+ * <td >Defines contents of the screen</td>
+ * </tr>
+ * </table>
+ */
+public class TranslucentFancyActivity extends Activity
+{
+ /**
+ * Initialization of the Activity after it is first created. Must at least
+ * call {@link android.app.Activity#setContentView setContentView()} to
+ * describe what is to be displayed in the screen.
+ */
+ @Override
+ protected void onCreate(Bundle icicle)
+ {
+ // Be sure to call the super class.
+ super.onCreate(icicle);
+
+ // Have the system blur any windows behind this one.
+ getWindow().setFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND,
+ WindowManager.LayoutParams.FLAG_BLUR_BEHIND);
+
+ // See assets/res/any/layout/translucent_background.xml for this
+ // view layout definition, which is being set here as
+ // the content of our screen.
+ setContentView(R.layout.translucent_background);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java
new file mode 100644
index 0000000..e88ebf9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/BitmapDrawable.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+public class BitmapDrawable extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.with_bitmap_background);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java
new file mode 100644
index 0000000..a382995
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/DrawableBgMinSize.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * Views should obey their background {@link Drawable}'s minimum size
+ * requirements ({@link Drawable#getMinimumHeight()} and
+ * {@link Drawable#getMinimumWidth()}) when possible.
+ * <p>
+ * This Activity exercises a few Views with background {@link Drawable}s.
+ */
+public class DrawableBgMinSize extends Activity implements OnClickListener {
+ private boolean mUsingBigBg = false;
+ private Drawable mBackgroundDrawable;
+ private Drawable mBigBackgroundDrawable;
+ private Button mChangeBackgroundsButton;
+
+ private TextView mTextView;
+ private LinearLayout mLinearLayout;
+ private RelativeLayout mRelativeLayout;
+ private FrameLayout mFrameLayout;
+ private AbsoluteLayout mAbsoluteLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.drawable_background_minimum_size);
+
+ mBackgroundDrawable = getResources().getDrawable(R.drawable.drawable_background);
+ mBigBackgroundDrawable = getResources().getDrawable(R.drawable.big_drawable_background);
+
+ mChangeBackgroundsButton = (Button) findViewById(R.id.change_backgrounds);
+ mChangeBackgroundsButton.setOnClickListener(this);
+
+ mTextView = (TextView) findViewById(R.id.text_view);
+ mLinearLayout = (LinearLayout) findViewById(R.id.linear_layout);
+ mRelativeLayout = (RelativeLayout) findViewById(R.id.relative_layout);
+ mFrameLayout = (FrameLayout) findViewById(R.id.frame_layout);
+ mAbsoluteLayout = (AbsoluteLayout) findViewById(R.id.absolute_layout);
+
+ changeBackgrounds(mBackgroundDrawable);
+ }
+
+ private void changeBackgrounds(Drawable newBg) {
+ mTextView.setBackgroundDrawable(newBg);
+ mLinearLayout.setBackgroundDrawable(newBg);
+ mRelativeLayout.setBackgroundDrawable(newBg);
+ mFrameLayout.setBackgroundDrawable(newBg);
+ mAbsoluteLayout.setBackgroundDrawable(newBg);
+ }
+
+ public void onClick(View v) {
+ if (mUsingBigBg) {
+ changeBackgrounds(mBackgroundDrawable);
+ } else {
+ changeBackgrounds(mBigBackgroundDrawable);
+ }
+
+ mUsingBigBg = !mUsingBigBg;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
new file mode 100644
index 0000000..2fcaea3
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/drawable/MutateDrawable.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.drawable;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import com.android.frameworktest.R;
+
+public class MutateDrawable extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+
+ Button ok = new Button(this);
+ ok.setId(R.id.a);
+ ok.setBackgroundDrawable(getResources().getDrawable(
+ R.drawable.sym_now_playing_skip_forward_1));
+
+ Button cancel = new Button(this);
+ cancel.setId(R.id.b);
+ cancel.setBackgroundDrawable(getResources().getDrawable(
+ R.drawable.sym_now_playing_skip_forward_1));
+
+ layout.addView(ok);
+ layout.addView(cancel);
+
+ ok.getBackground().mutate().setAlpha(127);
+
+ setContentView(layout);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java
new file mode 100644
index 0000000..cee1d4d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListSimple.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.expandablelistview;
+
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.MenuItem.OnMenuItemClickListener;
+import android.widget.BaseExpandableListAdapter;
+
+import com.android.frameworktest.util.ExpandableListScenario;
+
+public class ExpandableListSimple extends ExpandableListScenario {
+ private static final int[] NUM_CHILDREN = {4, 3, 2, 1, 0};
+
+ @Override
+ protected void init(ExpandableParams params) {
+ params.setNumChildren(NUM_CHILDREN)
+ .setItemScreenSizeFactor(0.14);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+
+ menu.add("Add item").setOnMenuItemClickListener(new OnMenuItemClickListener() {
+ public boolean onMenuItemClick(MenuItem item) {
+ mGroups.add(0, new MyGroup(2));
+ ((BaseExpandableListAdapter) mAdapter).notifyDataSetChanged();
+ return true;
+ }
+ });
+
+ return true;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java
new file mode 100644
index 0000000..0155f09
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeaders.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.expandablelistview;
+
+import com.android.frameworktest.util.ExpandableListScenario;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ExpandableListView;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ExpandableListWithHeaders extends ExpandableListScenario {
+ private static final int[] sNumChildren = {1, 4, 3, 2, 6};
+ private static final int sNumOfHeadersAndFooters = 12;
+
+ @Override
+ protected void init(ExpandableParams params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumChildren(sNumChildren)
+ .setItemScreenSizeFactor(0.14)
+ .setConnectAdapter(false);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final ExpandableListView expandableListView = getExpandableListView();
+ expandableListView.setItemsCanFocus(true);
+
+ for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+ Button header = new Button(this);
+ header.setText("Header View");
+ expandableListView.addHeaderView(header);
+ }
+
+ for (int i = 0; i < sNumOfHeadersAndFooters; i++) {
+ Button footer = new Button(this);
+ footer.setText("Footer View");
+ expandableListView.addFooterView(footer);
+ }
+
+ // Set adapter here AFTER we set header and footer views
+ setAdapter(expandableListView);
+ }
+
+ /**
+ * @return The number of headers (and the same number of footers)
+ */
+ public int getNumOfHeadersAndFooters() {
+ return sNumOfHeadersAndFooters;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java
new file mode 100644
index 0000000..f1089a1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/expandablelistview/InflatedExpandableListView.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.expandablelistview;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.TextView;
+
+public class InflatedExpandableListView extends Activity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.inflated_expandablelistview);
+
+ ExpandableListView elv = (ExpandableListView) findViewById(R.id.elv);
+ elv.setAdapter(new MyExpandableListAdapter());
+ }
+
+ public class MyExpandableListAdapter extends BaseExpandableListAdapter {
+ // Sample data set. children[i] contains the children (String[]) for groups[i].
+ private String[] groups = { "People Names", "Dog Names", "Cat Names", "Fish Names" };
+ private String[][] children = {
+ { "Arnold", "Barry", "Chuck", "David" },
+ { "Ace", "Bandit", "Cha-Cha", "Deuce" },
+ { "Fluffy", "Snuggles" },
+ { "Goldy", "Bubbles" }
+ };
+
+ public Object getChild(int groupPosition, int childPosition) {
+ return children[groupPosition][childPosition];
+ }
+
+ public long getChildId(int groupPosition, int childPosition) {
+ return childPosition;
+ }
+
+ public int getChildrenCount(int groupPosition) {
+ return children[groupPosition].length;
+ }
+
+ public TextView getGenericView() {
+ // Layout parameters for the ExpandableListView
+ AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, 64);
+
+ TextView textView = new TextView(InflatedExpandableListView.this);
+ textView.setLayoutParams(lp);
+ // Center the text vertically
+ textView.setGravity(Gravity.CENTER_VERTICAL | Gravity.LEFT);
+ // Set the text starting position
+ textView.setPadding(36, 0, 0, 0);
+ return textView;
+ }
+
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ TextView textView = getGenericView();
+ textView.setText(getChild(groupPosition, childPosition).toString());
+ return textView;
+ }
+
+ public Object getGroup(int groupPosition) {
+ return groups[groupPosition];
+ }
+
+ public int getGroupCount() {
+ return groups.length;
+ }
+
+ public long getGroupId(int groupPosition) {
+ return groupPosition;
+ }
+
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ TextView textView = getGenericView();
+ textView.setText(getGroup(groupPosition).toString());
+ return textView;
+ }
+
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java
new file mode 100644
index 0000000..c4e2705
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/AdjacentVerticalRectLists.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.view.ViewGroup;
+
+/**
+ * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
+ * and
+ * {@link android.view.View#requestFocus(int, android.graphics.Rect)}
+ * work together to give a newly focused item a hint about the most interesting
+ * rectangle of the previously focused view. The view taking focus can use this
+ * to set an internal selection more appropriate using this rect.
+ *
+ * This Activity excercises that behavior using three adjacent {@link com.android.frameworktest.util.InternalSelectionView}
+ * that report interesting rects when giving up focus, and use interesting rects
+ * when taking focus to best select the internal row to show as selected.
+ */
+public class AdjacentVerticalRectLists extends Activity {
+
+ private LinearLayout mLayout;
+ private InternalSelectionView mLeftColumn;
+ private InternalSelectionView mMiddleColumn;
+ private InternalSelectionView mRightColumn;
+
+
+ public LinearLayout getLayout() {
+ return mLayout;
+ }
+
+ public InternalSelectionView getLeftColumn() {
+ return mLeftColumn;
+ }
+
+ public InternalSelectionView getMiddleColumn() {
+ return mMiddleColumn;
+ }
+
+ public InternalSelectionView getRightColumn() {
+ return mRightColumn;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(0,
+ ViewGroup.LayoutParams.FILL_PARENT, 1);
+
+ mLeftColumn = new InternalSelectionView(this, 5, "left column");
+ mLeftColumn.setLayoutParams(params);
+ mLeftColumn.setPadding(10, 10, 10, 10);
+ mLayout.addView(mLeftColumn);
+
+ mMiddleColumn = new InternalSelectionView(this, 5, "middle column");
+ mMiddleColumn.setLayoutParams(params);
+ mMiddleColumn.setPadding(10, 10, 10, 10);
+ mLayout.addView(mMiddleColumn);
+
+ mRightColumn = new InternalSelectionView(this, 5, "right column");
+ mRightColumn.setLayoutParams(params);
+ mRightColumn.setPadding(10, 10, 10, 10);
+ mLayout.addView(mRightColumn);
+
+ setContentView(mLayout);
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java
new file mode 100644
index 0000000..f0c1980
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/DescendantFocusability.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class DescendantFocusability extends Activity {
+
+ public ViewGroup beforeDescendants;
+ public Button beforeDescendantsChild;
+
+ public ViewGroup afterDescendants;
+ public Button afterDescendantsChild;
+
+ public ViewGroup blocksDescendants;
+ public Button blocksDescendantsChild;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.descendant_focusability);
+
+ beforeDescendants = (ViewGroup) findViewById(R.id.beforeDescendants);
+ beforeDescendantsChild = (Button) beforeDescendants.getChildAt(0);
+
+ afterDescendants = (ViewGroup) findViewById(R.id.afterDescendants);
+ afterDescendantsChild = (Button) afterDescendants.getChildAt(0);
+
+ blocksDescendants = (ViewGroup) findViewById(R.id.blocksDescendants);
+ blocksDescendantsChild = (Button) blocksDescendants.getChildAt(0);
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java
new file mode 100644
index 0000000..6c5f1c4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/FocusAfterRemoval.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+/**
+ * Exercises cases where elements of the UI are removed (and
+ * focus should go somewhere).
+ */
+public class FocusAfterRemoval extends Activity {
+
+
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.focus_after_removal);
+
+ final LinearLayout left = (LinearLayout) findViewById(R.id.leftLayout);
+
+ // top left makes parent layout GONE
+ Button topLeftButton = (Button) findViewById(R.id.topLeftButton);
+ topLeftButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ left.setVisibility(View.GONE);
+ }
+ });
+
+ // bottom left makes parent layout INVISIBLE
+ // top left makes parent layout GONE
+ Button bottomLeftButton = (Button) findViewById(R.id.bottomLeftButton);
+ bottomLeftButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ left.setVisibility(View.INVISIBLE);
+ }
+ });
+
+ // top right button makes top right button GONE
+ final Button topRightButton = (Button) findViewById(R.id.topRightButton);
+ topRightButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ topRightButton.setVisibility(View.GONE);
+ }
+ });
+
+ // bottom right button makes bottom right button INVISIBLE
+ final Button bottomRightButton = (Button) findViewById(R.id.bottomRightButton);
+ bottomRightButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ bottomRightButton.setVisibility(View.INVISIBLE);
+ }
+ });
+
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java
new file mode 100644
index 0000000..91bd7b4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/GoneParentFocusedChild.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * An activity that helps test the scenario where a parent is
+ * GONE and one of its children has focus; the activity should get
+ * the key event. see bug 945150.
+ */
+public class GoneParentFocusedChild extends Activity {
+ private LinearLayout mGoneGroup;
+ private Button mButton;
+
+ private boolean mUnhandledKeyEvent = false;
+ private LinearLayout mLayout;
+
+ public boolean isUnhandledKeyEvent() {
+ return mUnhandledKeyEvent;
+ }
+
+ public LinearLayout getLayout() {
+ return mLayout;
+ }
+
+ public LinearLayout getGoneGroup() {
+ return mGoneGroup;
+ }
+
+ public Button getButton() {
+ return mButton;
+ }
+
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+
+ mGoneGroup = new LinearLayout(this);
+ mGoneGroup.setOrientation(LinearLayout.HORIZONTAL);
+ mGoneGroup.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mButton = new Button(this);
+ mButton.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+
+ mGoneGroup.addView(mButton);
+ setContentView(mLayout);
+
+ mGoneGroup.setVisibility(View.GONE);
+ mButton.requestFocus();
+ }
+
+ public boolean onKeyUp(int keyCode, KeyEvent event) {
+ mUnhandledKeyEvent = true;
+ return true;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java
new file mode 100644
index 0000000..01a9821
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/HorizontalFocusSearch.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.TextView;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.content.Context;
+
+public class HorizontalFocusSearch extends Activity {
+
+ private LinearLayout mLayout;
+
+ private Button mLeftTall;
+ private Button mMidShort1Top;
+ private Button mMidShort2Bottom;
+ private Button mRightTall;
+
+
+ public LinearLayout getLayout() {
+ return mLayout;
+ }
+
+ public Button getLeftTall() {
+ return mLeftTall;
+ }
+
+ public Button getMidShort1Top() {
+ return mMidShort1Top;
+ }
+
+ public Button getMidShort2Bottom() {
+ return mMidShort2Bottom;
+ }
+
+ public Button getRightTall() {
+ return mRightTall;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.HORIZONTAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mLeftTall = makeTall("left tall");
+ mLayout.addView(mLeftTall);
+
+ mMidShort1Top = addShort(mLayout, "mid(1) top", false);
+ mMidShort2Bottom = addShort(mLayout, "mid(2) bottom", true);
+
+ mRightTall = makeTall("right tall");
+ mLayout.addView(mRightTall);
+
+ setContentView(mLayout);
+ }
+
+ // just to get toString non-sucky
+ private static class MyButton extends Button {
+
+ public MyButton(Context context) {
+ super(context);
+ }
+
+
+ @Override
+ public String toString() {
+ return getText().toString();
+ }
+ }
+
+ private Button makeTall(String label) {
+ Button button = new MyButton(this);
+ button.setText(label);
+ button.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ return button;
+ }
+
+ private Button addShort(LinearLayout root, String label, boolean atBottom) {
+ Button button = new MyButton(this);
+ button.setText(label);
+ button.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 0, // height
+ 490));
+
+ TextView filler = new TextView(this);
+ filler.setText("filler");
+ filler.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 0, // height
+ 510));
+
+ LinearLayout ll = new LinearLayout(this);
+ ll.setOrientation(LinearLayout.VERTICAL);
+ ll.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ if (atBottom) {
+ ll.addView(filler);
+ ll.addView(button);
+ root.addView(ll);
+ } else {
+ ll.addView(button);
+ ll.addView(filler);
+ root.addView(ll);
+ }
+ return button;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java
new file mode 100644
index 0000000..9aec0d5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/LinearLayoutGrid.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import com.android.frameworktest.R;
+
+public class LinearLayoutGrid extends Activity {
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.linear_layout_grid);
+ }
+
+ public ViewGroup getRootView() {
+ return (ViewGroup) findViewById(R.id.layout);
+ }
+
+ public Button getButtonAt(int column, int row) {
+ if (row < 0 || row > 2) {
+ throw new IllegalArgumentException("row out of range");
+ }
+ if (column < 0 || column > 2) {
+ throw new IllegalArgumentException("column out of range");
+ }
+ return (Button) getColumn(column).getChildAt(row);
+ }
+
+
+
+ private LinearLayout getColumn(int column) {
+ switch (column) {
+ case 0:
+ return (LinearLayout) findViewById(R.id.column1);
+ case 1:
+ return (LinearLayout) findViewById(R.id.column2);
+ case 2:
+ return (LinearLayout) findViewById(R.id.column3);
+ default:
+ throw new IllegalArgumentException("column out of range");
+ }
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java
new file mode 100644
index 0000000..0abcebb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfButtons.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+
+/**
+ * A layout with a ListView containing buttons.
+ */
+public class ListOfButtons extends ListActivity {
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_with_button_above);
+ getListView().setItemsCanFocus(true);
+ setListAdapter(new MyAdapter(this, mLabels));
+ }
+
+ String[] mLabels = {
+ "Alabama", "Alaska", "Arizona", "apple sauce!",
+ "California", "Colorado", "Connecticut", "Delaware"
+ };
+
+
+ public String[] getLabels() {
+ return mLabels;
+ }
+
+ public static class MyAdapter extends ArrayAdapter<String> {
+
+
+ public MyAdapter(Context context, String[] labels) {
+ super(context, 0, labels);
+ }
+
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ String label = getItem(position);
+
+ Button button = new Button(parent.getContext());
+ button.setText(label);
+ return button;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return false;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java
new file mode 100644
index 0000000..f59e2b7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfEditTexts.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.*;
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+public class ListOfEditTexts extends Activity {
+
+ private int mLinesPerEditText = 12;
+
+ private ListView mListView;
+ private LinearLayout mLinearLayout;
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // create linear layout
+ mLinearLayout = new LinearLayout(this);
+ mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+ mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ // add a button above
+ Button buttonAbove = new Button(this);
+ buttonAbove.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ buttonAbove.setText("button above list");
+ mLinearLayout.addView(buttonAbove);
+
+ // add a list view to it
+ mListView = new ListView(this);
+ mListView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mListView.setDrawSelectorOnTop(false);
+ mListView.setItemsCanFocus(true);
+ mListView.setLayoutParams((new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 0,
+ 1f)));
+
+ List<String> bodies = Lists.newArrayList(
+ getBody("zero hello, my name is android"),
+ getBody("one i'm a paranoid android"),
+ getBody("two i robot. huh huh."),
+ getBody("three not the g-phone!"));
+
+ mListView.setAdapter(new MyAdapter(this, bodies));
+ mLinearLayout.addView(mListView);
+
+ // add button below
+ Button buttonBelow = new Button(this);
+ buttonBelow.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ buttonBelow.setText("button below list");
+ mLinearLayout.addView(buttonBelow);
+
+ setContentView(mLinearLayout);
+ }
+
+ String getBody(String line) {
+ StringBuilder sb = new StringBuilder((line.length() + 5) * mLinesPerEditText);
+ for (int i = 0; i < mLinesPerEditText; i++) {
+ sb.append(i + 1).append(' ').append(line);
+ if (i < mLinesPerEditText - 1) {
+ sb.append('\n'); // all but last line
+ }
+ }
+ return sb.toString();
+ }
+
+
+ private static class MyAdapter extends ArrayAdapter<String> {
+
+ public MyAdapter(Context context, List<String> bodies) {
+ super(context, 0, bodies);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ String body = getItem(position);
+
+ if (convertView != null) {
+ ((EditText) convertView).setText(body);
+ return convertView;
+ }
+
+ EditText editText = new EditText(getContext());
+ editText.setText(body);
+ return editText;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java
new file mode 100644
index 0000000..4bbca74
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListOfInternalSelectionViews.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ListView;
+import com.android.frameworktest.util.InternalSelectionView;
+
+/**
+ * A list of {@link InternalSelectionView}s paramatarized by the number of items,
+ * how many rows in each item, and how tall each item is.
+ */
+public class ListOfInternalSelectionViews extends Activity {
+
+ private ListView mListView;
+
+
+ // keys for initializing via Intent params
+ public static final String BUNDLE_PARAM_NUM_ITEMS = "com.google.test.numItems";
+ public static final String BUNDLE_PARAM_NUM_ROWS_PER_ITEM = "com.google.test.numRowsPerItem";
+ public static final String BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR = "com.google.test.itemScreenHeightFactor";
+
+ private int mScreenHeight;
+
+ private int mNumItems = 5;
+ private int mNumRowsPerItem = 4;
+ private double mItemScreenSizeFactor = 5 / 4;
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+ /**
+ * Each item is screen height * this factor tall.
+ */
+ public double getItemScreenSizeFactor() {
+ return mItemScreenSizeFactor;
+ }
+
+ /**
+ * @return The number of rows per item.
+ */
+ public int getNumRowsPerItem() {
+ return mNumRowsPerItem;
+ }
+
+ /**
+ * @return The number of items in the list.
+ */
+ public int getNumItems() {
+ return mNumItems;
+ }
+
+ /**
+ * @param position The position
+ * @return The label (closest thing to a value) for the item at position
+ */
+ public String getLabelForPosition(int position) {
+ return "position " + position;
+ }
+
+ /**
+ * Get the currently selected view.
+ */
+ public InternalSelectionView getSelectedView() {
+ return (InternalSelectionView) getListView().getSelectedView();
+ }
+
+ /**
+ * Get the screen height.
+ */
+ public int getScreenHeight() {
+ return mScreenHeight;
+ }
+
+ /**
+ * Initialize a bundle suitable for sending as the params of the intent that
+ * launches this activity.
+ * @param numItems The number of items in the list.
+ * @param numRowsPerItem The number of rows per item.
+ * @param itemScreenHeightFactor see {@link #getScreenHeight()}
+ * @return the intialized bundle.
+ */
+ public static Bundle getBundleFor(int numItems, int numRowsPerItem, double itemScreenHeightFactor) {
+ Bundle bundle = new Bundle();
+ bundle.putInt(BUNDLE_PARAM_NUM_ITEMS, numItems);
+ bundle.putInt(BUNDLE_PARAM_NUM_ROWS_PER_ITEM, numRowsPerItem);
+ bundle.putDouble(BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR, itemScreenHeightFactor);
+ return bundle;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+ Bundle extras = getIntent().getExtras();
+ if (extras != null) {
+ initFromBundle(extras);
+ }
+
+ mListView = new ListView(this);
+ mListView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mListView.setDrawSelectorOnTop(false);
+ mListView.setAdapter(new MyAdapter());
+ mListView.setItemsCanFocus(true);
+ setContentView(mListView);
+ }
+
+ private void initFromBundle(Bundle icicle) {
+
+ int numItems = icicle.getInt(BUNDLE_PARAM_NUM_ITEMS, -1);
+ if (numItems != -1) {
+ mNumItems = numItems;
+ }
+ int numRowsPerItem = icicle.getInt(BUNDLE_PARAM_NUM_ROWS_PER_ITEM, -1);
+ if (numRowsPerItem != -1) {
+ mNumRowsPerItem = numRowsPerItem;
+ }
+ double screenHeightFactor = icicle.getDouble(BUNDLE_PARAM_ITEM_SCREEN_HEIGHT_FACTOR, -1.0);
+ if (screenHeightFactor > 0) {
+ mItemScreenSizeFactor = screenHeightFactor;
+ }
+ }
+
+ private class MyAdapter extends BaseAdapter {
+
+ public int getCount() {
+ return mNumItems;
+ }
+
+ public Object getItem(int position) {
+ return getLabelForPosition(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ InternalSelectionView item =
+ new InternalSelectionView(
+ parent.getContext(),
+ mNumRowsPerItem,
+ getLabelForPosition(position));
+ item.setDesiredHeight((int) (mScreenHeight * mItemScreenSizeFactor));
+ return item;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java
new file mode 100644
index 0000000..730f9aa
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabels.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseAdapter;
+import android.widget.Button;
+import android.widget.TextView;
+
+import com.google.android.collect.Lists;
+import com.android.frameworktest.R;
+
+import java.util.List;
+
+public class ListWithFooterViewAndNewLabels extends ListActivity {
+
+ private MyAdapter mMyAdapter;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_with_button_above);
+
+ Button footerButton = new Button(this);
+ footerButton.setText("hi");
+ footerButton.setLayoutParams(
+ new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ getListView().addFooterView(footerButton);
+
+ mMyAdapter = new MyAdapter(this);
+ setListAdapter(mMyAdapter);
+
+ // not in list
+ Button topButton = (Button) findViewById(R.id.button);
+ topButton.setText("click to add new item");
+ topButton.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ mMyAdapter.addLabel("yo");
+ }
+ });
+
+ mMyAdapter.addLabel("first");
+ }
+
+ /**
+ * An adapter that can take new string labels.
+ */
+ static class MyAdapter extends BaseAdapter {
+
+ private final Context mContext;
+ private List<String> mLabels = Lists.newArrayList();
+
+ public MyAdapter(Context context) {
+ mContext = context;
+ }
+
+ public int getCount() {
+ return mLabels.size();
+ }
+
+ public Object getItem(int position) {
+ return mLabels.get(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ String label = mLabels.get(position);
+
+ LayoutInflater inflater = (LayoutInflater)
+ mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ TextView tv = (TextView) inflater.inflate(
+ android.R.layout.simple_list_item_1,
+ null);
+ tv.setText(label);
+ return tv;
+ }
+
+ public void addLabel(String s) {
+ mLabels.add(s + mLabels.size());
+ notifyDataSetChanged();
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java
new file mode 100644
index 0000000..27c642a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/ListWithMailMessages.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.R;
+import com.google.android.collect.Lists;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.webkit.WebView;
+
+import java.util.List;
+
+public class ListWithMailMessages extends ListActivity {
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.list_with_button_above);
+
+ List<MailMessage> messages = Lists.newArrayList();
+ messages.add(new MailMessage("hello!", "<p>this is a test "
+ + "message, with a bunch of text and stuff.</p>", true));
+
+// String android = "android";
+ String android = "<a href=\"www.android.com\">android</a>";
+
+ String sentance = "all work and no play makes "
+ + android + " a dull... robot!";
+ StringBuffer longBody = new StringBuffer().append("<ol>\n");
+ for (int i = 0; i < 12; i++) {
+ longBody.append("<li>").append(sentance).append("</li>");
+ }
+ longBody.append("</ol>");
+
+ messages.add(new MailMessage("hello2!", longBody.toString(), true));
+ messages.add(new MailMessage("phone number?", "<p>hey man, what's ur "
+ + "contact info? i need to mail you this photo of my two"
+ + " cats, they've gotten soooo fat!</p>", true));
+
+ setListAdapter(new MyAdapter(this, R.layout.mail_message, messages));
+ getListView().setItemsCanFocus(true);
+ }
+
+
+ /**
+ * POJO mail message.
+ */
+ static class MailMessage {
+ private String mSubject;
+ private String mBody;
+ private boolean mFocusable;
+
+
+ public MailMessage(String subject, String body) {
+ this(subject, body, false);
+ }
+
+
+ public MailMessage(String subject, String body, boolean focusable) {
+ mSubject = subject;
+ mBody = body;
+ mFocusable = focusable;
+ }
+
+ public String getSubject() {
+ return mSubject;
+ }
+
+ public void setSubject(String subject) {
+ this.mSubject = subject;
+ }
+
+ public String getBody() {
+ return mBody;
+ }
+
+ public void setBody(String body) {
+ this.mBody = body;
+ }
+
+
+ public boolean isFocusable() {
+ return mFocusable;
+ }
+
+ public void setFocusable(boolean focusable) {
+ mFocusable = focusable;
+ }
+ }
+
+
+ public static class MyAdapter extends ArrayAdapter<MailMessage> {
+
+ public MyAdapter(Context context, int resource,
+ List<MailMessage> objects) {
+ super(context, resource, objects);
+ }
+
+ final String mimeType = "text/html";
+ final String encoding = "utf-8";
+
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ MailMessage message = getItem(position);
+
+ LayoutInflater inflater = (LayoutInflater)
+ getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ LinearLayout messageUi = (LinearLayout) inflater
+ .inflate(R.layout.mail_message, null);
+
+ TextView subject = (TextView) messageUi.findViewById(R.id.subject);
+ subject.setText(message.getSubject());
+
+ WebView body = (WebView) messageUi.findViewById(R.id.body);
+ body.loadData(message.getBody(), mimeType, encoding);
+// body.setText(message.getBody());
+ body.setFocusable(message.isFocusable());
+
+ return messageUi;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java
new file mode 100644
index 0000000..803815b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/RequestFocus.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+/**
+ * Exercises cases where elements of the UI are requestFocus()ed.
+ */
+public class RequestFocus extends Activity {
+ protected final Handler mHandler = new Handler();
+
+ @Override protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.focus_after_removal);
+
+ // bottom right button starts with the focus.
+ final Button bottomRightButton = (Button) findViewById(R.id.bottomRightButton);
+ bottomRightButton.requestFocus();
+ bottomRightButton.setText("I should have focus");
+ }
+
+ public Handler getHandler() {
+ return mHandler;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java b/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java
new file mode 100644
index 0000000..d1b83a3
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/focus/VerticalFocusSearch.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.TextView;
+import android.view.Gravity;
+import android.view.ViewGroup;
+import android.content.Context;
+
+/**
+ * Holds a few buttons of various sizes and horizontal placements in a
+ * vertical layout to excercise some core focus searching.
+ */
+public class VerticalFocusSearch extends Activity {
+
+ private LinearLayout mLayout;
+
+ private Button mTopWide;
+ private Button mMidSkinny1Left;
+ private Button mBottomWide;
+
+ private Button mMidSkinny2Right;
+
+
+ public LinearLayout getLayout() {
+ return mLayout;
+ }
+
+ public Button getTopWide() {
+ return mTopWide;
+ }
+
+ public Button getMidSkinny1Left() {
+ return mMidSkinny1Left;
+ }
+
+ public Button getMidSkinny2Right() {
+ return mMidSkinny2Right;
+ }
+
+ public Button getBottomWide() {
+ return mBottomWide;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setHorizontalGravity(Gravity.LEFT);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mTopWide = makeWide("top wide");
+ mLayout.addView(mTopWide);
+
+ mMidSkinny1Left = addSkinny(mLayout, "mid skinny 1(L)", false);
+
+ mMidSkinny2Right = addSkinny(mLayout, "mid skinny 2(R)", true);
+
+ mBottomWide = makeWide("bottom wide");
+ mLayout.addView(mBottomWide);
+
+ setContentView(mLayout);
+ }
+
+ // just to get toString non-sucky
+ private static class MyButton extends Button {
+
+ public MyButton(Context context) {
+ super(context);
+ }
+
+
+ @Override
+ public String toString() {
+ return getText().toString();
+ }
+ }
+
+ private Button makeWide(String label) {
+ Button button = new MyButton(this);
+ button.setText(label);
+ button.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ return button;
+ }
+
+ /**
+ * Add a skinny button that takes up just less than half of the screen
+ * horizontally.
+ * @param root The layout to add the button to.
+ * @param label The label of the button.
+ * @param atRight Which side to put the button on.
+ * @return The newly created button.
+ */
+ private Button addSkinny(LinearLayout root, String label, boolean atRight) {
+ Button button = new MyButton(this);
+ button.setText(label);
+ button.setLayoutParams(new LinearLayout.LayoutParams(
+ 0, // width
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 480));
+
+ TextView filler = new TextView(this);
+ filler.setText("filler");
+ filler.setLayoutParams(new LinearLayout.LayoutParams(
+ 0, // width
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 520));
+
+ LinearLayout ll = new LinearLayout(this);
+ ll.setOrientation(LinearLayout.HORIZONTAL);
+ ll.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ if (atRight) {
+ ll.addView(filler);
+ ll.addView(button);
+ root.addView(ll);
+ } else {
+ ll.addView(button);
+ ll.addView(filler);
+ root.addView(ll);
+ }
+ return button;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java
new file mode 100644
index 0000000..4c0d23b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridDelete.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+
+import com.android.frameworktest.util.GridScenario;
+
+import java.util.ArrayList;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridDelete extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(1001)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.20)
+ .setVerticalSpacing(20);
+ }
+
+
+
+ @Override
+ protected ListAdapter createAdapter() {
+ return new DeleteAdapter(getInitialNumItems());
+ }
+
+
+
+
+ @Override
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_DEL) {
+ GridView g = getGridView();
+ ((DeleteAdapter)g.getAdapter()).deletePosition(g.getSelectedItemPosition());
+ return true;
+ } else {
+ return super.onKeyDown(keyCode, event);
+ }
+ }
+
+
+
+
+ private class DeleteAdapter extends BaseAdapter {
+
+ private ArrayList<Integer> mData;
+
+ public DeleteAdapter(int initialNumItems) {
+ super();
+ mData = new ArrayList<Integer>(initialNumItems);
+
+ int i;
+ for (i=0; i<initialNumItems; ++i) {
+ mData.add(new Integer(10000 + i));
+ }
+
+ }
+
+ public void deletePosition(int selectedItemPosition) {
+ if (selectedItemPosition >=0 && selectedItemPosition < mData.size()) {
+ mData.remove(selectedItemPosition);
+ notifyDataSetChanged();
+ }
+
+ }
+
+ public int getCount() {
+ return mData.size();
+ }
+
+ public Object getItem(int position) {
+ return mData.get(position);
+ }
+
+ public long getItemId(int position) {
+ return mData.get(position);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ int desiredHeight = getDesiredItemHeight();
+ return createView(mData.get(position), parent, desiredHeight);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java
new file mode 100644
index 0000000..c10a53b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInHorizontal.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid in a horizontal linear layout
+ */
+public class GridInHorizontal extends Activity {
+ Handler mHandler = new Handler();
+ TextView mText;
+ GridView mGridView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.grid_in_horizontal);
+
+ String values[] = new String[1000];
+ int i=0;
+ for(i=0; i<1000; i++) {
+ values[i] = ((Integer)i).toString();
+ }
+
+ mText = (TextView) findViewById(R.id.text);
+ mGridView = (GridView) findViewById(R.id.grid);
+ mGridView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ }
+
+ public GridView getGridView() {
+ return mGridView;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java
new file mode 100644
index 0000000..acde73e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridInVertical.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid in a vertical linear layout
+ */
+public class GridInVertical extends Activity {
+ Handler mHandler = new Handler();
+ TextView mText;
+ GridView mGridView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.grid_in_vertical);
+
+ String values[] = new String[1000];
+ int i=0;
+ for(i=0; i<1000; i++) {
+ values[i] = ((Integer)i).toString();
+ }
+
+ mText = (TextView) findViewById(R.id.text);
+ mGridView = (GridView) findViewById(R.id.grid);
+ mGridView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ }
+
+ public GridView getGridView() {
+ return mGridView;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java
new file mode 100644
index 0000000..41909ac2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridPadding.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a grid with padding
+ */
+public class GridPadding extends Activity {
+ private GridView mGridView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.grid_padding);
+
+ String values[] = new String[1000];
+ for(int i = 0; i < 1000; i++) {
+ values[i] = String.valueOf(i);
+ }
+
+ mGridView = (GridView) findViewById(R.id.grid);
+ mGridView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+ }
+
+ public GridView getGridView() {
+ return mGridView;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java
new file mode 100644
index 0000000..4655230
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridScrollListener.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.AbsListView;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises change notification in a list
+ */
+public class GridScrollListener extends Activity implements AbsListView.OnScrollListener {
+ Handler mHandler = new Handler();
+ TextView mText;
+ GridView mGridView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.grid_scroll_listener);
+
+ String values[] = new String[1000];
+ int i=0;
+ for(i=0; i<1000; i++) {
+ values[i] = ((Integer)i).toString();
+ }
+
+ mText = (TextView) findViewById(R.id.text);
+ mGridView = (GridView) findViewById(R.id.grid);
+ mGridView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ mGridView.setOnScrollListener(this);
+ }
+
+ public GridView getGridView() {
+ return mGridView;
+ }
+
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+ int lastItem = firstVisibleItem + visibleItemCount - 1;
+ mText.setText("Showing " + firstVisibleItem + "-" + lastItem + "/" + totalItemCount);
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java
new file mode 100644
index 0000000..38f629d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelection.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from top scenario, nothing fancy. Items do not
+ * fill the screen.
+ */
+public class GridSetSelection extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(15)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java
new file mode 100644
index 0000000..34aeb75
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from top scenario, nothing fancy. Items do
+ * fill the screen.
+ */
+public class GridSetSelectionMany extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(150)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java
new file mode 100644
index 0000000..6a2445f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from bottom scenario, nothing fancy. Items do not
+ * fill the screen.
+ */
+public class GridSetSelectionStackFromBottom extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(15)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java
new file mode 100644
index 0000000..838c431
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic stacking from bottom scenario, nothing fancy. Items do
+ * fill the screen.
+ */
+public class GridSetSelectionStackFromBottomMany extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(150)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java
new file mode 100644
index 0000000..f7f68f5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSimple.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.graphics.drawable.PaintDrawable;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import com.android.frameworktest.util.GridScenario;
+
+public class GridSimple extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(1000)
+ .setNumColumns(3)
+ .setItemScreenSizeFactor(0.14);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getGridView().setSelector(new PaintDrawable(0xFFFF0000));
+ getGridView().setPadding(0, 0, 0, 0);
+ getGridView().setFadingEdgeLength(64);
+ getGridView().setVerticalFadingEdgeEnabled(true);
+ getGridView().setBackgroundColor(0xFFC0C0C0);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ View view = super.createView(position, parent, desiredHeight);
+ view.setBackgroundColor(0xFF000000);
+ ((TextView) view).setTextSize(16.0f);
+ return view;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java
new file mode 100644
index 0000000..a909bd8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridSingleColumn.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+import android.widget.GridView;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridSingleColumn extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(101)
+ .setNumColumns(1)
+ .setColumnWidth(60)
+ .setItemScreenSizeFactor(0.20)
+ .setVerticalSpacing(20)
+ .setStretchMode(GridView.STRETCH_SPACING);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java
new file mode 100644
index 0000000..304110e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic bottom stacking from bottom scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class GridStackFromBottom extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(15)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java
new file mode 100644
index 0000000..94d801e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridStackFromBottomMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * Basic bottom stacking from bottom scenario, nothing fancy. The grid items do not fit on the
+ * screen (to exercise scrolling.)
+ */
+public class GridStackFromBottomMany extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(54)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.12);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java
new file mode 100644
index 0000000..d628f2d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridThrasher.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+
+import java.util.Random;
+
+/**
+ * Exercises change notification in a list
+ */
+public class GridThrasher extends Activity implements AdapterView.OnItemSelectedListener
+{
+ Handler mHandler = new Handler();
+ ThrashListAdapter mAdapter;
+ Random mRandomizer = new Random();
+ TextView mText;
+
+ Runnable mThrash = new Runnable() {
+ public void run() {
+ mAdapter.bumpVersion();
+ mHandler.postDelayed(mThrash, 500);
+ }
+ };
+
+ private class ThrashListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+
+ /**
+ * Our data, part 1.
+ */
+ private String[] mTitles = new String[100];
+
+ /**
+ * Our data, part 2.
+ */
+ private int[] mVersion = new int[100];
+
+ public ThrashListAdapter(Context context) {
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mTitles = new String[100];
+ mVersion = new int[100];
+
+ int i;
+ for (i=0; i<100; i++) {
+ mTitles[i] = "[" + i + "]";
+ mVersion[i] = 0;
+ }
+ }
+
+ public int getCount() {
+ return mTitles.length;
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+
+ if (convertView == null) {
+ view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+ } else {
+ view = (TextView) convertView;
+ }
+ view.setText(mTitles[position] + " " + mVersion[position]);
+ return view;
+ }
+
+
+ public void bumpVersion() {
+ int position = mRandomizer.nextInt(getCount());
+ mVersion[position]++;
+ notifyDataSetChanged();
+ }
+
+
+ }
+
+ @Override
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.grid_thrasher);
+
+ mText = (TextView) findViewById(R.id.text);
+ mAdapter = new ThrashListAdapter(this);
+ GridView g = (GridView) findViewById(R.id.grid);
+ g.setAdapter(mAdapter);
+
+ mHandler.postDelayed(mThrash, 5000);
+
+ g.setOnItemSelectedListener(this);
+ }
+
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ mText.setText("Position " + position);
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ mText.setText("Nothing");
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java
new file mode 100644
index 0000000..3f6b8d6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacing.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * A grid with vertical spacing between rows
+ */
+public class GridVerticalSpacing extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(101)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.20)
+ .setVerticalSpacing(20);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java
new file mode 100644
index 0000000..1a39ffb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/gridview/GridVerticalSpacingStackFromBottom.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+/**
+ * A grid with vertical spacing between rows that stacks from the bottom
+ */
+public class GridVerticalSpacingStackFromBottom extends GridScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(101)
+ .setNumColumns(4)
+ .setItemScreenSizeFactor(0.20)
+ .setVerticalSpacing(20);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java
new file mode 100644
index 0000000..1383dae
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutGravity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.frame;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class FrameLayoutGravity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.framelayout_gravity);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java
new file mode 100644
index 0000000..0434726
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/frame/FrameLayoutMargin.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.frame;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class FrameLayoutMargin extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.framelayout_margin);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java
new file mode 100644
index 0000000..5087c62
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineAlignmentCenterGravity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.baseline_center_gravity);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
new file mode 100644
index 0000000..3c1d7fd
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeight.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineAlignmentZeroWidthAndWeight extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.baseline_0width_and_weight);
+
+ findViewById(R.id.show).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ findViewById(R.id.layout).setVisibility(View.VISIBLE);
+ }
+ });
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java
new file mode 100644
index 0000000..9bb9bff
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/BaselineButtons.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class BaselineButtons extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.baseline_buttons);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java
new file mode 100644
index 0000000..54f6b98
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/ExceptionTextView.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import junit.framework.Assert;
+
+import android.widget.EditText;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.text.BoringLayout;
+
+
+/**
+ * A special EditText that sets {@link #isFailed()} to true as its internal makeNewLayout() method is called
+ * with a width lower than 0. This is used to fail the unit test in
+ * BaselineAlignmentZeroWidthAndWeightTest.
+ */
+public class ExceptionTextView extends EditText {
+
+ private boolean mFailed = false;
+
+ public ExceptionTextView(Context context) {
+ super(context);
+ }
+
+ public ExceptionTextView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public ExceptionTextView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public boolean isFailed() {
+ return mFailed;
+ }
+
+ @Override
+ protected void makeNewLayout(int w, int hintWidth,
+ BoringLayout.Metrics boring,
+ BoringLayout.Metrics hintMetrics,
+ int ellipsizedWidth, boolean bringIntoView) {
+ if (w < 0) {
+ mFailed = true;
+ w = 100;
+ }
+
+ super.makeNewLayout(w, hintWidth, boring, hintMetrics, ellipsizedWidth,
+ bringIntoView);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java
new file mode 100644
index 0000000..a95cf17
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/FillInWrap.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class FillInWrap extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.fill_in_wrap);
+ ((TextView) findViewById(R.id.data)).setText("1\n2\n3\n4\n5");
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java
new file mode 100644
index 0000000..1308b8b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/HorizontalOrientationVerticalAlignment.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class HorizontalOrientationVerticalAlignment extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.linear_layout_spinner_then_button);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java
new file mode 100644
index 0000000..db868cb
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLEditTextThenButton.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+
+public class LLEditTextThenButton extends Activity {
+ private EditText mEditText;
+ private Button mButton;
+
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.linear_layout_edittext_then_button);
+
+ mLayout = (LinearLayout) findViewById(R.id.layout);
+ mEditText = (EditText) findViewById(R.id.editText);
+ mButton = (Button) findViewById(R.id.button);
+ }
+
+ public LinearLayout getLayout() {
+ return mLayout;
+ }
+
+ public EditText getEditText() {
+ return mEditText;
+ }
+
+ public Button getButton() {
+ return mButton;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java
new file mode 100644
index 0000000..33189e5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons1.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.view.View;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import com.android.frameworktest.R;
+
+/**
+ * One of two simple vertical linear layouts of buttons used to test out
+ * the transistion between touch and focus mode.
+ */
+public class LLOfButtons1 extends Activity {
+
+ private boolean mButtonPressed = false;
+ private Button mFirstButton;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.linear_layout_buttons);
+ mFirstButton = (Button) findViewById(R.id.button1);
+
+ mFirstButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mButtonPressed = true;
+ }
+ });
+
+ }
+
+ public LinearLayout getLayout() {
+ return (LinearLayout) findViewById(R.id.layout);
+ }
+
+ public Button getFirstButton() {
+ return mFirstButton;
+ }
+
+ public boolean buttonClickListenerFired() {
+ return mButtonPressed;
+ }
+
+ public boolean isInTouchMode() {
+ return mFirstButton.isInTouchMode();
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java
new file mode 100644
index 0000000..1e0c97a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfButtons2.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+/**
+ * One of two simple vertical linear layouts of buttons used to test out
+ * the transistion between touch and focus mode.
+ */
+public class LLOfButtons2 extends LLOfButtons1 {
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java
new file mode 100644
index 0000000..201c8f9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LLOfTwoFocusableInTouchMode.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class LLOfTwoFocusableInTouchMode extends Activity {
+
+ private View mButton1;
+ private View mButton2;
+ private View mButton3;
+
+ private boolean mB1Fired = false;
+ private boolean mB2Fired = false;
+ private boolean mB3Fired = false;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.linear_layout_buttons);
+
+ mButton1 = findViewById(R.id.button1);
+ mButton2 = findViewById(R.id.button2);
+ mButton3 = findViewById(R.id.button3);
+
+ mButton1.setFocusableInTouchMode(true);
+ mButton2.setFocusableInTouchMode(true);
+ mButton3.setFocusableInTouchMode(true);
+
+ mButton1.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mB1Fired = true;
+ }
+ });
+
+ mButton2.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mB2Fired = true;
+ }
+ });
+
+ mButton3.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mB3Fired = true;
+ }
+ });
+ }
+
+ public View getButton1() {
+ return mButton1;
+ }
+
+ public View getButton2() {
+ return mButton2;
+ }
+
+ public View getButton3() {
+ return mButton3;
+ }
+
+ public boolean isB1Fired() {
+ return mB1Fired;
+ }
+
+ public boolean isB2Fired() {
+ return mB2Fired;
+ }
+
+ public boolean isB3Fired() {
+ return mB3Fired;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java
new file mode 100644
index 0000000..4877a63
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/LinearLayoutEditTexts.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class LinearLayoutEditTexts extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.linear_layout_textviews);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java
new file mode 100644
index 0000000..0535f00
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/Weight.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Weight extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.linear_layout_weight);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java
new file mode 100644
index 0000000..8b9a497
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/linear/WeightSum.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+
+public class WeightSum extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.weight_sum);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java
new file mode 100644
index 0000000..c490e0f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/AddColumn.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+import android.widget.TextView;
+
+/**
+ * This test adds an extra row with an extra column in the table.
+ */
+public class AddColumn extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.add_column_in_table);
+
+ final Button addRowButton = (Button) findViewById(R.id.add_row_button);
+ addRowButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ final TableLayout table = (TableLayout) findViewById(R.id.table);
+ final TableRow newRow = new TableRow(AddColumn.this);
+ for (int i = 0; i < 4; i++) {
+ final TextView view = new TextView(AddColumn.this);
+ view.setText("Column " + (i + 1));
+ view.setPadding(3, 3, 3, 3);
+ newRow.addView(view, new TableRow.LayoutParams());
+ }
+ table.addView(newRow, new TableLayout.LayoutParams());
+ newRow.requestLayout();
+ }
+ });
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java
new file mode 100644
index 0000000..243efc7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/CellSpan.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells spanning.
+ */
+public class CellSpan extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.table_layout_cell_span);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java
new file mode 100644
index 0000000..2e2defc
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/FixedWidth.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells having a fixed width and height.
+ */
+public class FixedWidth extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.table_layout_fixed_width);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java
new file mode 100644
index 0000000..fdafa12
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/HorizontalGravity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells using a horizontal gravity.
+ */
+public class HorizontalGravity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.table_layout_horizontal_gravity);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java
new file mode 100644
index 0000000..1f161d9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/VerticalGravity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells using a vertical gravity.
+ */
+public class VerticalGravity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.table_layout_vertical_gravity);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java
new file mode 100644
index 0000000..4c3835f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/layout/table/Weight.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * Exercise table layout with cells having a weight.
+ */
+public class Weight extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.table_layout_weight);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java
new file mode 100644
index 0000000..5c38ef0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+
+/**
+ * Most bodacious scenario yet!
+ */
+public class AdjacentListsWithAdjacentISVsInside extends Activity {
+
+ private ListView mLeftListView;
+ private ListView mRightListView;
+
+ public ListView getLeftListView() {
+ return mLeftListView;
+ }
+
+ public ListView getRightListView() {
+ return mRightListView;
+ }
+
+ public InternalSelectionView getLeftIsv() {
+ return (InternalSelectionView)
+ ((ViewGroup) mLeftListView.getChildAt(0)).getChildAt(0);
+ }
+
+ public InternalSelectionView getLeftMiddleIsv() {
+ return (InternalSelectionView)
+ ((ViewGroup) mLeftListView.getChildAt(0)).getChildAt(1);
+ }
+
+ public InternalSelectionView getRightMiddleIsv() {
+ return (InternalSelectionView)
+ ((ViewGroup) mRightListView.getChildAt(0)).getChildAt(0);
+ }
+
+ public InternalSelectionView getRightIsv() {
+ return (InternalSelectionView)
+ ((ViewGroup) mRightListView.getChildAt(0)).getChildAt(1);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ final int desiredHeight = (int) (0.8 * getWindowManager().getDefaultDisplay().getHeight());
+
+ mLeftListView = new ListView(this);
+ mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
+ mLeftListView.setItemsCanFocus(true);
+
+
+ mRightListView = new ListView(this);
+ mRightListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
+ mRightListView.setItemsCanFocus(true);
+
+
+
+ setContentView(combineAdjacent(mLeftListView, mRightListView));
+ }
+
+ private static View combineAdjacent(View... views) {
+ if (views.length < 2) {
+ throw new IllegalArgumentException("you should pass at least 2 views in");
+ }
+
+ final LinearLayout ll = new LinearLayout(views[0].getContext());
+ ll.setOrientation(LinearLayout.HORIZONTAL);
+ final LinearLayout.LayoutParams lp =
+ new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
+
+ for (View view : views) {
+ ll.addView(view, lp);
+ }
+ return ll;
+ }
+
+ static class AdjacentISVAdapter extends BaseAdapter {
+
+ private final int mItemHeight;
+
+ AdjacentISVAdapter(int itemHeight) {
+ mItemHeight = itemHeight;
+ }
+
+ public int getCount() {
+ return 1;
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ final InternalSelectionView isvLeft = new InternalSelectionView(
+ parent.getContext(), 5, "isv left");
+ isvLeft.setDesiredHeight(mItemHeight);
+ final InternalSelectionView isvRight = new InternalSelectionView(
+ parent.getContext(), 5, "isv right");
+ isvRight.setDesiredHeight(mItemHeight);
+ return combineAdjacent(isvLeft, isvRight);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java
new file mode 100644
index 0000000..e729d52
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic bottom gravity scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class ListBottomGravity extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(2)
+ .setItemScreenSizeFactor(0.22);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java
new file mode 100644
index 0000000..1225b9a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListBottomGravityMany.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic bottom gravity scenario, nothing fancy. There are
+ * more items than fit on the screen
+ */
+public class ListBottomGravityMany extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(true)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(10)
+ .setItemScreenSizeFactor(0.22);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java
new file mode 100644
index 0000000..bda2cd1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListButtonsDiagonalAcrossItems.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListItemFactory;
+import static com.android.frameworktest.util.ListItemFactory.Slot;
+import com.android.frameworktest.util.ListScenario;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class ListButtonsDiagonalAcrossItems extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setItemsFocusable(true)
+ .setNumItems(3)
+ .setItemScreenSizeFactor(0.2)
+ .setMustFillScreen(false);
+ }
+
+ public Button getLeftButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(0);
+ }
+
+ public Button getCenterButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(1)).getChildAt(1);
+ }
+
+ public Button getRightButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(2)).getChildAt(2);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent,
+ int desiredHeight) {
+ final Slot slot = position == 0 ? Slot.Left :
+ (position == 1 ? Slot.Middle : Slot.Right);
+ return ListItemFactory.horizontalButtonSlots(
+ parent.getContext(), desiredHeight, slot);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java
new file mode 100644
index 0000000..62045d8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListDividers.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list width dividers and padding.
+ */
+public class ListDividers extends Activity {
+ private ListView mListView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_dividers);
+
+ String values[] = new String[1000];
+ for (int i = 0; i < 1000; i++) {
+ values[i] = ((Integer) i).toString();
+ }
+
+ mListView = (ListView) findViewById(android.R.id.list);
+ mListView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java
new file mode 100644
index 0000000..4ab1eef6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListEndingWithMultipleSeparators.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListEndingWithMultipleSeparators extends ListScenario {
+
+ protected void init(Params params) {
+ params.setItemsFocusable(false)
+ .setNumItems(5)
+ .setItemScreenSizeFactor(0.22)
+ .setPositionUnselectable(3)
+ .setPositionUnselectable(4);
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java
new file mode 100644
index 0000000..b164d86
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListFilter.java
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+
+
+/**
+ * Tests hiding and showing the list filter by hiding and showing an ancestor of the
+ * ListView
+ */
+public class ListFilter extends ListActivity implements OnClickListener {
+
+ private View mFrame;
+ private Button mHide;
+ private Button mShow;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.list_filter);
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, mStrings));
+ getListView().setTextFilterEnabled(true);
+ mFrame = findViewById(R.id.frame);
+
+ mHide = (Button) findViewById(R.id.hide);
+ mHide.setOnClickListener(this);
+
+ mShow = (Button) findViewById(R.id.show);
+ mShow.setOnClickListener(this);
+ }
+
+
+ public void onClick(View v) {
+ mFrame.setVisibility(v == mHide ? View.INVISIBLE : View.VISIBLE);
+ }
+
+ private String[] mStrings = {
+ "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi",
+ "Acorn", "Adelost", "Affidelice au Chablis", "Afuega'l Pitu", "Airag", "Airedale",
+ "Aisy Cendre", "Allgauer Emmentaler", "Alverca", "Ambert", "American Cheese",
+ "Ami du Chambertin", "Anejo Enchilado", "Anneau du Vic-Bilh", "Anthoriro", "Appenzell",
+ "Aragon", "Ardi Gasna", "Ardrahan", "Armenian String", "Aromes au Gene de Marc",
+ "Asadero", "Asiago", "Aubisque Pyrenees", "Autun", "Avaxtskyr", "Baby Swiss",
+ "Babybel", "Baguette Laonnaise", "Bakers", "Baladi", "Balaton", "Bandal", "Banon",
+ "Barry's Bay Cheddar", "Basing", "Basket Cheese", "Bath Cheese", "Bavarian Bergkase",
+ "Baylough", "Beaufort", "Beauvoorde", "Beenleigh Blue", "Beer Cheese", "Bel Paese",
+ "Bergader", "Bergere Bleue", "Berkswell", "Beyaz Peynir", "Bierkase", "Bishop Kennedy",
+ "Blarney", "Bleu d'Auvergne", "Bleu de Gex", "Bleu de Laqueuille",
+ "Bleu de Septmoncel", "Bleu Des Causses", "Blue", "Blue Castello", "Blue Rathgore",
+ "Blue Vein (Australian)", "Blue Vein Cheeses", "Bocconcini", "Bocconcini (Australian)",
+ "Boeren Leidenkaas", "Bonchester", "Bosworth", "Bougon", "Boule Du Roves",
+ "Boulette d'Avesnes", "Boursault", "Boursin", "Bouyssou", "Bra", "Braudostur",
+ "Breakfast Cheese", "Brebis du Lavort", "Brebis du Lochois", "Brebis du Puyfaucon",
+ "Bresse Bleu", "Brick", "Brie", "Brie de Meaux", "Brie de Melun", "Brillat-Savarin",
+ "Brin", "Brin d' Amour", "Brin d'Amour", "Brinza (Burduf Brinza)",
+ "Briquette de Brebis", "Briquette du Forez", "Broccio", "Broccio Demi-Affine",
+ "Brousse du Rove", "Bruder Basil", "Brusselae Kaas (Fromage de Bruxelles)", "Bryndza",
+ "Buchette d'Anjou", "Buffalo", "Burgos", "Butte", "Butterkase", "Button (Innes)",
+ "Buxton Blue", "Cabecou", "Caboc", "Cabrales", "Cachaille", "Caciocavallo", "Caciotta",
+ "Caerphilly", "Cairnsmore", "Calenzana", "Cambazola", "Camembert de Normandie",
+ "Canadian Cheddar", "Canestrato", "Cantal", "Caprice des Dieux", "Capricorn Goat",
+ "Capriole Banon", "Carre de l'Est", "Casciotta di Urbino", "Cashel Blue", "Castellano",
+ "Castelleno", "Castelmagno", "Castelo Branco", "Castigliano", "Cathelain",
+ "Celtic Promise", "Cendre d'Olivet", "Cerney", "Chabichou", "Chabichou du Poitou",
+ "Chabis de Gatine", "Chaource", "Charolais", "Chaumes", "Cheddar",
+ "Cheddar Clothbound", "Cheshire", "Chevres", "Chevrotin des Aravis", "Chontaleno",
+ "Civray", "Coeur de Camembert au Calvados", "Coeur de Chevre", "Colby", "Cold Pack",
+ "Comte", "Coolea", "Cooleney", "Coquetdale", "Corleggy", "Cornish Pepper",
+ "Cotherstone", "Cotija", "Cottage Cheese", "Cottage Cheese (Australian)",
+ "Cougar Gold", "Coulommiers", "Coverdale", "Crayeux de Roncq", "Cream Cheese",
+ "Cream Havarti", "Crema Agria", "Crema Mexicana", "Creme Fraiche", "Crescenza",
+ "Croghan", "Crottin de Chavignol", "Crottin du Chavignol", "Crowdie", "Crowley",
+ "Cuajada", "Curd", "Cure Nantais", "Curworthy", "Cwmtawe Pecorino",
+ "Cypress Grove Chevre", "Danablu (Danish Blue)", "Danbo", "Danish Fontina",
+ "Daralagjazsky", "Dauphin", "Delice des Fiouves", "Denhany Dorset Drum", "Derby",
+ "Dessertnyj Belyj", "Devon Blue", "Devon Garland", "Dolcelatte", "Doolin",
+ "Doppelrhamstufel", "Dorset Blue Vinney", "Double Gloucester", "Double Worcester",
+ "Dreux a la Feuille", "Dry Jack", "Duddleswell", "Dunbarra", "Dunlop", "Dunsyre Blue",
+ "Duroblando", "Durrus", "Dutch Mimolette (Commissiekaas)", "Edam", "Edelpilz",
+ "Emental Grand Cru", "Emlett", "Emmental", "Epoisses de Bourgogne", "Esbareich",
+ "Esrom", "Etorki", "Evansdale Farmhouse Brie", "Evora De L'Alentejo", "Exmoor Blue",
+ "Explorateur", "Feta", "Feta (Australian)", "Figue", "Filetta", "Fin-de-Siecle",
+ "Finlandia Swiss", "Finn", "Fiore Sardo", "Fleur du Maquis", "Flor de Guia",
+ "Flower Marie", "Folded", "Folded cheese with mint", "Fondant de Brebis",
+ "Fontainebleau", "Fontal", "Fontina Val d'Aosta", "Formaggio di capra", "Fougerus",
+ "Four Herb Gouda", "Fourme d' Ambert", "Fourme de Haute Loire", "Fourme de Montbrison",
+ "Fresh Jack", "Fresh Mozzarella", "Fresh Ricotta", "Fresh Truffles", "Fribourgeois",
+ "Friesekaas", "Friesian", "Friesla", "Frinault", "Fromage a Raclette", "Fromage Corse",
+ "Fromage de Montagne de Savoie", "Fromage Frais", "Fruit Cream Cheese",
+ "Frying Cheese", "Fynbo", "Gabriel", "Galette du Paludier", "Galette Lyonnaise",
+ "Galloway Goat's Milk Gems", "Gammelost", "Gaperon a l'Ail", "Garrotxa", "Gastanberra",
+ "Geitost", "Gippsland Blue", "Gjetost", "Gloucester", "Golden Cross", "Gorgonzola",
+ "Gornyaltajski", "Gospel Green", "Gouda", "Goutu", "Gowrie", "Grabetto", "Graddost",
+ "Grafton Village Cheddar", "Grana", "Grana Padano", "Grand Vatel",
+ "Grataron d' Areches", "Gratte-Paille", "Graviera", "Greuilh", "Greve",
+ "Gris de Lille", "Gruyere", "Gubbeen", "Guerbigny", "Halloumi",
+ "Halloumy (Australian)", "Haloumi-Style Cheese", "Harbourne Blue", "Havarti",
+ "Heidi Gruyere", "Hereford Hop", "Herrgardsost", "Herriot Farmhouse", "Herve",
+ "Hipi Iti", "Hubbardston Blue Cow", "Hushallsost", "Iberico", "Idaho Goatster",
+ "Idiazabal", "Il Boschetto al Tartufo", "Ile d'Yeu", "Isle of Mull", "Jarlsberg",
+ "Jermi Tortes", "Jibneh Arabieh", "Jindi Brie", "Jubilee Blue", "Juustoleipa",
+ "Kadchgall", "Kaseri", "Kashta", "Kefalotyri", "Kenafa", "Kernhem", "Kervella Affine",
+ "Kikorangi", "King Island Cape Wickham Brie", "King River Gold", "Klosterkaese",
+ "Knockalara", "Kugelkase", "L'Aveyronnais", "L'Ecir de l'Aubrac", "La Taupiniere",
+ "La Vache Qui Rit", "Laguiole", "Lairobell", "Lajta", "Lanark Blue", "Lancashire",
+ "Langres", "Lappi", "Laruns", "Lavistown", "Le Brin", "Le Fium Orbo", "Le Lacandou",
+ "Le Roule", "Leafield", "Lebbene", "Leerdammer", "Leicester", "Leyden", "Limburger",
+ "Lincolnshire Poacher", "Lingot Saint Bousquet d'Orb", "Liptauer", "Little Rydings",
+ "Livarot", "Llanboidy", "Llanglofan Farmhouse", "Loch Arthur Farmhouse",
+ "Loddiswell Avondale", "Longhorn", "Lou Palou", "Lou Pevre", "Lyonnais", "Maasdam",
+ "Macconais", "Mahoe Aged Gouda", "Mahon", "Malvern", "Mamirolle", "Manchego",
+ "Manouri", "Manur", "Marble Cheddar", "Marbled Cheeses", "Maredsous", "Margotin",
+ "Maribo", "Maroilles", "Mascares", "Mascarpone", "Mascarpone (Australian)",
+ "Mascarpone Torta", "Matocq", "Maytag Blue", "Meira", "Menallack Farmhouse",
+ "Menonita", "Meredith Blue", "Mesost", "Metton (Cancoillotte)", "Meyer Vintage Gouda",
+ "Mihalic Peynir", "Milleens", "Mimolette", "Mine-Gabhar", "Mini Baby Bells", "Mixte",
+ "Molbo", "Monastery Cheeses", "Mondseer", "Mont D'or Lyonnais", "Montasio",
+ "Monterey Jack", "Monterey Jack Dry", "Morbier", "Morbier Cru de Montagne",
+ "Mothais a la Feuille", "Mozzarella", "Mozzarella (Australian)",
+ "Mozzarella di Bufala", "Mozzarella Fresh, in water", "Mozzarella Rolls", "Munster",
+ "Murol", "Mycella", "Myzithra", "Naboulsi", "Nantais", "Neufchatel",
+ "Neufchatel (Australian)", "Niolo", "Nokkelost", "Northumberland", "Oaxaca",
+ "Olde York", "Olivet au Foin", "Olivet Bleu", "Olivet Cendre",
+ "Orkney Extra Mature Cheddar", "Orla", "Oschtjepka", "Ossau Fermier", "Ossau-Iraty",
+ "Oszczypek", "Oxford Blue", "P'tit Berrichon", "Palet de Babligny", "Paneer", "Panela",
+ "Pannerone", "Pant ys Gawn", "Parmesan (Parmigiano)", "Parmigiano Reggiano",
+ "Pas de l'Escalette", "Passendale", "Pasteurized Processed", "Pate de Fromage",
+ "Patefine Fort", "Pave d'Affinois", "Pave d'Auge", "Pave de Chirac", "Pave du Berry",
+ "Pecorino", "Pecorino in Walnut Leaves", "Pecorino Romano", "Peekskill Pyramid",
+ "Pelardon des Cevennes", "Pelardon des Corbieres", "Penamellera", "Penbryn",
+ "Pencarreg", "Perail de Brebis", "Petit Morin", "Petit Pardou", "Petit-Suisse",
+ "Picodon de Chevre", "Picos de Europa", "Piora", "Pithtviers au Foin",
+ "Plateau de Herve", "Plymouth Cheese", "Podhalanski", "Poivre d'Ane", "Polkolbin",
+ "Pont l'Eveque", "Port Nicholson", "Port-Salut", "Postel", "Pouligny-Saint-Pierre",
+ "Pourly", "Prastost", "Pressato", "Prince-Jean", "Processed Cheddar", "Provolone",
+ "Provolone (Australian)", "Pyengana Cheddar", "Pyramide", "Quark",
+ "Quark (Australian)", "Quartirolo Lombardo", "Quatre-Vents", "Quercy Petit",
+ "Queso Blanco", "Queso Blanco con Frutas --Pina y Mango", "Queso de Murcia",
+ "Queso del Montsec", "Queso del Tietar", "Queso Fresco", "Queso Fresco (Adobera)",
+ "Queso Iberico", "Queso Jalapeno", "Queso Majorero", "Queso Media Luna",
+ "Queso Para Frier", "Queso Quesadilla", "Rabacal", "Raclette", "Ragusano", "Raschera",
+ "Reblochon", "Red Leicester", "Regal de la Dombes", "Reggianito", "Remedou",
+ "Requeson", "Richelieu", "Ricotta", "Ricotta (Australian)", "Ricotta Salata", "Ridder",
+ "Rigotte", "Rocamadour", "Rollot", "Romano", "Romans Part Dieu", "Roncal", "Roquefort",
+ "Roule", "Rouleau De Beaulieu", "Royalp Tilsit", "Rubens", "Rustinu", "Saaland Pfarr",
+ "Saanenkaese", "Saga", "Sage Derby", "Sainte Maure", "Saint-Marcellin",
+ "Saint-Nectaire", "Saint-Paulin", "Salers", "Samso", "San Simon", "Sancerre",
+ "Sap Sago", "Sardo", "Sardo Egyptian", "Sbrinz", "Scamorza", "Schabzieger", "Schloss",
+ "Selles sur Cher", "Selva", "Serat", "Seriously Strong Cheddar", "Serra da Estrela",
+ "Sharpam", "Shelburne Cheddar", "Shropshire Blue", "Siraz", "Sirene", "Smoked Gouda",
+ "Somerset Brie", "Sonoma Jack", "Sottocenare al Tartufo", "Soumaintrain",
+ "Sourire Lozerien", "Spenwood", "Sraffordshire Organic", "St. Agur Blue Cheese",
+ "Stilton", "Stinking Bishop", "String", "Sussex Slipcote", "Sveciaost", "Swaledale",
+ "Sweet Style Swiss", "Swiss", "Syrian (Armenian String)", "Tala", "Taleggio", "Tamie",
+ "Tasmania Highland Chevre Log", "Taupiniere", "Teifi", "Telemea", "Testouri",
+ "Tete de Moine", "Tetilla", "Texas Goat Cheese", "Tibet", "Tillamook Cheddar",
+ "Tilsit", "Timboon Brie", "Toma", "Tomme Brulee", "Tomme d'Abondance",
+ "Tomme de Chevre", "Tomme de Romans", "Tomme de Savoie", "Tomme des Chouans", "Tommes",
+ "Torta del Casar", "Toscanello", "Touree de L'Aubier", "Tourmalet",
+ "Trappe (Veritable)", "Trois Cornes De Vendee", "Tronchon", "Trou du Cru", "Truffe",
+ "Tupi", "Turunmaa", "Tymsboro", "Tyn Grug", "Tyning", "Ubriaco", "Ulloa",
+ "Vacherin-Fribourgeois", "Valencay", "Vasterbottenost", "Venaco", "Vendomois",
+ "Vieux Corse", "Vignotte", "Vulscombe", "Waimata Farmhouse Blue",
+ "Washed Rind Cheese (Australian)", "Waterloo", "Weichkaese", "Wellington",
+ "Wensleydale", "White Stilton", "Whitestone Farmhouse", "Wigmore", "Woodside Cabecou",
+ "Xanadu", "Xynotyro", "Yarg Cornish", "Yarra Valley Pyramid", "Yorkshire Blue",
+ "Zamorano", "Zanetti Grana Padano", "Zanetti Parmigiano Reggiano"};
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java
new file mode 100644
index 0000000..28fa21a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListGetSelectedView.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario. This test is made to check that getSelectedView() will return
+ * null in touch mode.
+ */
+public class ListGetSelectedView extends ListScenario {
+ @Override
+ protected void init(Params params) {
+ params.setMustFillScreen(false).setNumItems(2).setItemScreenSizeFactor(0.22);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java
new file mode 100644
index 0000000..93abd78
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHeterogeneous.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * List that has different view types
+ */
+public class ListHeterogeneous extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setNumItems(50)
+ .setItemScreenSizeFactor(1.0 / 8)
+ .setItemsFocusable(true)
+ .setHeaderViewCount(3)
+ .setFooterViewCount(2);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ switch (position % 3) {
+ case 0:
+ return ListItemFactory.text(
+ position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+ case 1:
+ return ListItemFactory.button(
+ position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+ case 2:
+ return ListItemFactory.doubleText(
+ position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+ }
+
+ return null;
+ }
+
+ @Override
+ public View convertView(int position, View convertView, ViewGroup parent) {
+ switch (position % 3) {
+ case 0:
+ return ListItemFactory.convertText(convertView, getValueAtPosition(position), position);
+ case 1:
+ return ListItemFactory.convertButton(convertView, getValueAtPosition(position),
+ position);
+ case 2:
+ return ListItemFactory.convertDoubleText(convertView, getValueAtPosition(position),
+ position);
+ }
+
+ return null;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return position % 3;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 3;
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java
new file mode 100644
index 0000000..c5e1e97
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListHorizontalFocusWithinItemWins.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListItemFactory;
+import static com.android.frameworktest.util.ListItemFactory.Slot;
+import com.android.frameworktest.util.ListScenario;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+public class ListHorizontalFocusWithinItemWins extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setItemsFocusable(true)
+ .setNumItems(2)
+ .setItemScreenSizeFactor(0.2)
+ .setMustFillScreen(false);
+ }
+
+ public Button getTopLeftButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(0);
+ }
+
+ public Button getTopRightButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(0)).getChildAt(2);
+ }
+
+ public Button getBottomMiddleButton() {
+ return (Button) ((ViewGroup) getListView().getChildAt(1)).getChildAt(1);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent,
+ int desiredHeight) {
+ final Context context = parent.getContext();
+ if (position == 0) {
+ return ListItemFactory.horizontalButtonSlots(
+ context, desiredHeight, Slot.Left, Slot.Right);
+ } else if (position == 1) {
+ return ListItemFactory.horizontalButtonSlots(
+ context, desiredHeight, Slot.Middle);
+ } else {
+ throw new IllegalArgumentException("expecting position 0 or 1");
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java
new file mode 100644
index 0000000..2128746
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInHorizontal.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list in a horizontal linear layout
+ */
+public class ListInHorizontal extends Activity {
+ private ListView mListView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_in_horizontal);
+
+ String values[] = new String[1000];
+ for (int i = 0; i < 1000; i++) {
+ values[i] = ((Integer) i).toString();
+ }
+
+ mListView = (ListView) findViewById(R.id.list);
+ mListView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java
new file mode 100644
index 0000000..f4c93c8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInVertical.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.widget.ArrayAdapter;
+import android.widget.GridView;
+import android.widget.TextView;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises a list in a vertical linear layout
+ */
+public class ListInVertical extends Activity {
+ private ListView mListView;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_in_vertical);
+
+ String values[] = new String[1000];
+ for (int i = 0; i < 1000; i++) {
+ values[i] = ((Integer) i).toString();
+ }
+
+ mListView = (ListView) findViewById(R.id.list);
+ mListView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ }
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java
new file mode 100644
index 0000000..e45297e
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListInterleaveFocusables.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.View;
+ import android.view.ViewGroup;
+ import com.google.android.collect.Sets;
+ import com.android.frameworktest.util.ListScenario;
+ import com.android.frameworktest.util.ListItemFactory;
+
+ import java.util.Set;
+
+/**
+ * List that interleaves focusable items.
+ */
+public class ListInterleaveFocusables extends ListScenario {
+
+ private Set<Integer> mFocusablePositions = Sets.newHashSet(1, 3, 6);
+
+ @Override
+ protected void init(Params params) {
+ params.setNumItems(7)
+ .setItemScreenSizeFactor(1.0 / 8)
+ .setItemsFocusable(true)
+ .setMustFillScreen(false);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ if (mFocusablePositions.contains(position)) {
+ return ListItemFactory.button(
+ position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+ } else {
+ return super.createView(position, parent, desiredHeight);
+ }
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return mFocusablePositions.contains(position) ? 0 : 1;
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return 2;
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java
new file mode 100644
index 0000000..e14da5b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusableAboveUnfocusable.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.TextView;
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where the items may befocusable, but the second item isn't actually focusabe.
+ */
+public class ListItemFocusableAboveUnfocusable extends ListScenario {
+
+
+ protected void init(Params params) {
+ params.setNumItems(2)
+ .setItemsFocusable(true)
+ .setItemScreenSizeFactor(0.2)
+ .setMustFillScreen(false);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ if (position == 0) {
+ return ListItemFactory.button(
+ position, parent.getContext(), getValueAtPosition(position), desiredHeight);
+ } else {
+ return super.createView(position, parent, desiredHeight);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java
new file mode 100644
index 0000000..e20f633
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesClose.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+import com.android.frameworktest.util.ListItemFactory;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Each list item has two focusables that are close enough together that
+ * it shouldn't require panning to move focus.
+ */
+public class ListItemFocusablesClose extends ListScenario {
+
+
+ /**
+ * Get the child of a list item.
+ * @param listIndex The index of the currently visible items
+ * @param index The index of the child.
+ */
+ public View getChildOfItem(int listIndex, int index) {
+ return ((ViewGroup) getListView().getChildAt(listIndex)).getChildAt(index);
+
+ }
+
+ @Override
+ protected void init(Params params) {
+ params.setItemsFocusable(true)
+ .setNumItems(2)
+ .setItemScreenSizeFactor(0.55);
+ }
+
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ return ListItemFactory.twoButtonsSeparatedByFiller(
+ position, parent.getContext(), desiredHeight);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java
new file mode 100644
index 0000000..e974478
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemFocusablesFarApart.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.util.ListItemFactory;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where each item is tall with buttons that are farther apart than the screen
+ * size. We don't want to jump over content off screen to the next button, we need to
+ * pan across the intermediate part.
+ */
+public class ListItemFocusablesFarApart extends ListScenario {
+
+
+ @Override
+ protected void init(Params params) {
+ params.setItemsFocusable(true)
+ .setNumItems(2)
+ .setItemScreenSizeFactor(2);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ return ListItemFactory.twoButtonsSeparatedByFiller(
+ position, parent.getContext(), desiredHeight);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java
new file mode 100644
index 0000000..d6c11b7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemISVAndButton.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import com.android.frameworktest.util.InternalSelectionView;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Each item is an internal selection view, a button, and some filler
+ */
+public class ListItemISVAndButton extends ListScenario {
+
+
+ @Override
+ protected void init(Params params) {
+ params.setItemScreenSizeFactor(2.0)
+ .setNumItems(3)
+ .setItemsFocusable(true);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ Context context = parent.getContext();
+
+ final LinearLayout ll = new LinearLayout(context);
+ ll.setOrientation(LinearLayout.VERTICAL);
+
+ final InternalSelectionView isv = new InternalSelectionView(context, 8, "ISV postion " + position);
+ isv.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ desiredHeight - 240));
+ ll.addView(isv);
+
+ final LinearLayout.LayoutParams buttonLp =
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 40);
+ final Button topButton = new Button(context);
+ topButton.setLayoutParams(
+ buttonLp);
+ topButton.setText("button " + position + ")");
+ ll.addView(topButton);
+
+ final TextView filler = new TextView(context);
+ filler.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 200));
+ filler.setText("filler");
+ ll.addView(filler);
+
+
+ return ll;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java
new file mode 100644
index 0000000..a137116
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListItemsExpandOnSelection.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.TextView;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where each item expands by 1.5 when selected.
+ */
+public class ListItemsExpandOnSelection extends ListScenario {
+
+
+ @Override
+ protected void init(Params params) {
+ params.setNumItems(10)
+ .setItemScreenSizeFactor(1.0/5);
+ }
+
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ TextView result = new ExpandWhenSelectedView(parent.getContext(), desiredHeight);
+ result.setHeight(desiredHeight);
+ result.setFocusable(mItemsFocusable);
+ result.setText(getValueAtPosition(position));
+ final AbsListView.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ result.setLayoutParams(lp);
+ return result;
+ }
+
+
+ @Override
+ public View convertView(int position, View convertView, ViewGroup parent) {
+ ((ExpandWhenSelectedView)convertView).setText(getValueAtPosition(position));
+ return convertView;
+ }
+
+
+ static private class ExpandWhenSelectedView extends TextView {
+
+ private final int mDesiredHeight;
+
+ public ExpandWhenSelectedView(Context context, int desiredHeight) {
+ super(context);
+ mDesiredHeight = desiredHeight;
+ }
+
+ @Override
+ public void setSelected(boolean selected) {
+ super.setSelected(selected);
+ if (selected) {
+ setHeight((int) (mDesiredHeight * 1.5));
+ } else {
+ setHeight(mDesiredHeight);
+ }
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java
new file mode 100644
index 0000000..23b76a9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListLastItemPartiallyVisible.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list where the very last item is partially visible, but still requires scrolling
+ * to bring it into view.
+ */
+public class ListLastItemPartiallyVisible extends ListScenario {
+
+ protected void init(Params params) {
+ params.setNumItems(5)
+ .setItemScreenSizeFactor(0.22);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java
new file mode 100644
index 0000000..0cc242f
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListManagedCursor.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.content.Intent;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.Settings;
+import android.provider.Contacts.People;
+import android.view.View;
+import android.widget.AdapterView;
+import android.widget.ListAdapter;
+import android.widget.SimpleCursorAdapter;
+import android.widget.AdapterView.OnItemClickListener;
+
+
+public class ListManagedCursor extends ListActivity implements OnItemClickListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // Get a cursor with all people
+ Cursor c = getContentResolver().query(Settings.System.CONTENT_URI, null, null, null, null);
+ startManagingCursor(c);
+
+ ListAdapter adapter = new SimpleCursorAdapter(this,
+ // Use a template that displays a text view
+ android.R.layout.simple_list_item_1,
+ // Give the cursor to the list adatper
+ c,
+ // Map the NAME column in the people database to...
+ new String[] {People.NAME} ,
+ // The "text1" view defined in the XML template
+ new int[] {android.R.id.text1});
+ setListAdapter(adapter);
+ getListView().setOnItemClickListener(this);
+ }
+
+ public void onItemClick(AdapterView parent, View view, int position, long id) {
+ Intent dummyIntent = new Intent(this, ListSimple.class);
+ startActivity(dummyIntent);
+ }
+}
+
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java
new file mode 100644
index 0000000..475ab31
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsShorterThanScreen.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfItemsShorterThanScreen extends ListScenario {
+
+ protected void init(Params params) {
+ params.setNumItems(5)
+ .setItemScreenSizeFactor(1.1 / 4)
+ .setItemsFocusable(false);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java
new file mode 100644
index 0000000..0d70abf
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfItemsTallerThanScreen.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfItemsTallerThanScreen extends ListScenario {
+
+
+ protected void init(Params params) {
+ params.setNumItems(3)
+ .setItemScreenSizeFactor(4.0 / 3)
+ .setItemsFocusable(false);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java
new file mode 100644
index 0000000..62c5aa7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortShortTallShortShort.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Exposes fading in and out multiple items.
+ */
+public class ListOfShortShortTallShortShort extends ListScenario {
+
+
+ protected void init(Params params) {
+ params.setNumItems(5)
+ .setItemScreenSizeFactor(0.1)
+ .setFadingEdgeScreenSizeFactor(0.22)
+ .setPositionScreenSizeFactorOverride(2, 1.1);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java
new file mode 100644
index 0000000..e60dee7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfShortTallShort.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Two short items separated by one that is taller than the screen.
+ */
+public class ListOfShortTallShort extends ListScenario {
+
+
+ protected void init(Params params) {
+ params.setItemScreenSizeFactor(1.0 / 8)
+ .setNumItems(3)
+ .setPositionScreenSizeFactorOverride(1, 1.2);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java
new file mode 100644
index 0000000..d613c9b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfThinItems.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListOfThinItems extends ListScenario {
+
+ protected void init(Params params) {
+
+ final int numItemsOnScreen = getScreenHeight() / 18;
+
+ params.setNumItems(numItemsOnScreen + 5)
+ .setItemScreenSizeFactor(18.0 / getScreenHeight())
+ .setItemsFocusable(false);
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java
new file mode 100644
index 0000000..0e09190
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListOfTouchables.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Each list item has two focusables that are close enough together that
+ * it shouldn't require panning to move focus.
+ */
+public class ListOfTouchables extends ListScenario {
+
+
+ @Override
+ protected void init(Params params) {
+ params.setItemsFocusable(true)
+ .setItemScreenSizeFactor(0.2)
+ .setNumItems(100);
+ }
+
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ Button b = new Button(this);
+ b.setText("Position " + position);
+ b.setId(position);
+ return b;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java
new file mode 100644
index 0000000..3df3b9a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListRecyclerProfiling.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+import android.widget.ImageButton;
+import android.view.ViewDebug;
+import android.view.View;
+
+import com.android.frameworktest.R;
+
+public class ListRecyclerProfiling extends Activity {
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_recycler_profiling);
+
+ String values[] = new String[1000];
+ for (int i = 0; i < 1000; i++) {
+ values[i] = ((Integer) i).toString();
+ }
+
+ ListView listView = (ListView) findViewById(R.id.list);
+
+ ViewDebug.startRecyclerTracing("SimpleList", listView);
+
+ listView.setAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+ ImageButton stopProfiling = (ImageButton) findViewById(R.id.pause);
+ stopProfiling.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ ViewDebug.stopRecyclerTracing();
+ }
+ });
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java
new file mode 100644
index 0000000..f5e4faf
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListScrollListener.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.ListActivity;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.TextView;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercises change notification in a list
+ */
+public class ListScrollListener extends ListActivity implements AbsListView.OnScrollListener {
+ Handler mHandler = new Handler();
+ TextView mText;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_scroll_listener);
+
+ String values[] = new String[1000];
+ int i=0;
+ for(i=0; i<1000; i++) {
+ values[i] = ((Integer)i).toString();
+ }
+
+ mText = (TextView) findViewById(R.id.text);
+ setListAdapter(new ArrayAdapter<String>(this,
+ android.R.layout.simple_list_item_1, values));
+
+
+ getListView().setOnScrollListener(this);
+ }
+
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ mText.setText("Position " + position);
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ mText.setText("Nothing");
+ }
+
+ public void onScroll(AbsListView view, int firstCell, int cellCount, int itemCount) {
+ int last = firstCell + cellCount - 1;
+ mText.setText("Showing " + firstCell + "-" + last + "/" + itemCount);
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java
new file mode 100644
index 0000000..87888ca
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSetSelection.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+import android.view.KeyEvent;
+import android.view.View;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.Button;
+
+/**
+ * List of 1,000 items used to test calls to setSelection() in touch mode.
+ * Pressing the S key will call setSelection(0) on the list.
+ */
+public class ListSetSelection extends ListScenario {
+ private Button mButton;
+
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(1000)
+ .setItemScreenSizeFactor(0.22);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mButton = new Button(this);
+ mButton.setText("setSelection(0)");
+ mButton.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ getListView().setSelection(0);
+ }
+ });
+
+ getListViewContainer().addView(mButton, new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ }
+
+ public Button getButton() {
+ return mButton;
+ }
+
+ @Override
+ public boolean dispatchKeyEvent(KeyEvent event) {
+ if (event.getKeyCode() == KeyEvent.KEYCODE_S) {
+ getListView().setSelection(0);
+ return true;
+ }
+
+ return super.dispatchKeyEvent(event);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java
new file mode 100644
index 0000000..e7517d6
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListSimple.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.os.Bundle;
+import android.widget.TextView;
+
+public class ListSimple extends ListScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(1000)
+ .setItemScreenSizeFactor(0.14);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getListView().setVerticalScrollBarEnabled(true);
+ getListView().setFadingEdgeLength(12);
+ getListView().setVerticalFadingEdgeEnabled(true);
+ }
+
+ @Override
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ View view = super.createView(position, parent, desiredHeight);
+ view.setBackgroundColor(0xFF191919);
+ ((TextView) view).setTextSize(16.0f);
+ return view;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java
new file mode 100644
index 0000000..e576ea2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTakeFocusFromSide.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Exercises moving focus into the list from the side
+ */
+public class ListTakeFocusFromSide extends ListActivity {
+
+
+ private class ThrashListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+
+ private String[] mTitles = new String[100];
+
+ public ThrashListAdapter(Context context) {
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mTitles = new String[100];
+
+ int i;
+ for (i = 0; i < 100; i++) {
+ mTitles[i] = "[" + i + "]";
+ }
+ }
+
+ public int getCount() {
+ return mTitles.length;
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+
+ if (convertView == null) {
+ view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+ } else {
+ view = (TextView) convertView;
+ }
+ view.setText(mTitles[position]);
+ return view;
+ }
+
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_take_focus_from_side);
+ setListAdapter(new ThrashListAdapter(this));
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java
new file mode 100644
index 0000000..e0b18a2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListThrasher.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+import java.util.Random;
+
+/**
+ * Exercises change notification in a list
+ */
+public class ListThrasher extends ListActivity implements AdapterView.OnItemSelectedListener {
+ Handler mHandler = new Handler();
+ ThrashListAdapter mAdapter;
+ Random mRandomizer = new Random();
+ TextView mText;
+
+ Runnable mThrash = new Runnable() {
+ public void run() {
+ mAdapter.bumpVersion();
+ mHandler.postDelayed(mThrash, 500);
+ }
+ };
+
+ private class ThrashListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+
+ /**
+ * Our data, part 1.
+ */
+ private String[] mTitles = new String[100];
+
+ /**
+ * Our data, part 2.
+ */
+ private int[] mVersion = new int[100];
+
+ public ThrashListAdapter(Context context) {
+ mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mTitles = new String[100];
+ mVersion = new int[100];
+
+ int i;
+ for (i = 0; i < 100; i++) {
+ mTitles[i] = "[" + i + "]";
+ mVersion[i] = 0;
+ }
+ }
+
+ public int getCount() {
+ return mTitles.length;
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+
+ if (convertView == null) {
+ view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+ } else {
+ view = (TextView) convertView;
+ }
+ view.setText(mTitles[position] + " " + mVersion[position]);
+ return view;
+ }
+
+
+ public void bumpVersion() {
+ int position = mRandomizer.nextInt(getCount());
+ mVersion[position]++;
+ notifyDataSetChanged();
+ }
+
+
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.list_thrasher);
+
+ mText = (TextView) findViewById(R.id.text);
+ mAdapter = new ThrashListAdapter(this);
+ setListAdapter(mAdapter);
+
+ mHandler.postDelayed(mThrash, 5000);
+
+ getListView().setOnItemSelectedListener(this);
+ }
+
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ mText.setText("Position " + position);
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ mText.setText("Nothing");
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java
new file mode 100644
index 0000000..6eb65a9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravity.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.view.Gravity;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario, nothing fancy. Items do not
+ * fill the screen
+ */
+public class ListTopGravity extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setMustFillScreen(false)
+ .setNumItems(2)
+ .setItemScreenSizeFactor(0.22);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java
new file mode 100644
index 0000000..8cff8ca
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListTopGravityMany.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic top gravity scenario, nothing fancy. There are
+ * more items than fit on the screen
+ */
+public class ListTopGravityMany extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(10)
+ .setItemScreenSizeFactor(0.22);
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java
new file mode 100644
index 0000000..17222d9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListViewHeight.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+
+public class ListViewHeight extends Activity {
+
+ private View mButton1;
+ private View mButton2;
+ private View mButton3;
+
+ private View mOuterLayout;
+ private ListView mInnerList;
+
+ ArrayAdapter<String> mAdapter;
+ private String[] mStrings = {
+ "Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi" };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.linear_layout_listview_height);
+
+ mButton1 = findViewById(R.id.button1);
+ mButton2 = findViewById(R.id.button2);
+ mButton3 = findViewById(R.id.button3);
+
+ mOuterLayout = findViewById(R.id.layout);
+ mInnerList = (ListView)findViewById(R.id.inner_list);
+
+ mAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line,
+ mStrings);
+
+ // Clicking this button will show the list view and set it to a fixed height
+ // If you then hide the views, there is no problem.
+ mButton1.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ // set listview to fixed height
+ ViewGroup.MarginLayoutParams lp;
+ lp = (ViewGroup.MarginLayoutParams) mInnerList.getLayoutParams();
+ lp.height = 200;
+ mInnerList.setLayoutParams(lp);
+ // enable list adapter
+ mInnerList.setAdapter(mAdapter);
+ // and show it
+ mOuterLayout.setVisibility(View.VISIBLE);
+ }
+ });
+
+ // Clicking this button will show the list view and set it fill_parent height
+ // If you then hide the views, there is an NPE when calculating the ListView height.
+ mButton2.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ // set listview to fill screen
+ ViewGroup.MarginLayoutParams lp;
+ lp = (ViewGroup.MarginLayoutParams) mInnerList.getLayoutParams();
+ lp.height = lp.FILL_PARENT;
+ mInnerList.setLayoutParams(lp);
+ // enable list adapter
+ mInnerList.setAdapter(mAdapter);
+ // and show it
+ mOuterLayout.setVisibility(View.VISIBLE);
+ }
+ });
+
+ // Clicking this button will remove the list adapter and hide the outer enclosing view.
+ // We have to climb all the way to the top because the bug (not checking visibility)
+ // only occurs at the very outer loop of ViewRoot.performTraversals and in the case of
+ // an Activity, this means you have to crawl all the way out to the root view.
+ // In the search manager, it's sufficient to simply show/hide the outer search manager
+ // view to trigger the same bug.
+ mButton3.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mInnerList.setAdapter(null);
+ // hide listview's owner
+ // as it turns out, the owner doesn't take us high enough
+ // because our activity includes a title bar, thus another layer
+ View parent = (View) mOuterLayout.getParent(); // FrameLayout (app container)
+ View grandpa = (View) parent.getParent(); // LinearLayout (title+app)
+ View great = (View) grandpa.getParent(); // PhoneWindow.DecorView
+ great.setVisibility(View.GONE);
+ }
+ });
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java
new file mode 100644
index 0000000..3a968af
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithDisappearingItemBug.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.database.Cursor;
+import android.os.Bundle;
+import android.provider.Contacts.People;
+import android.view.animation.AlphaAnimation;
+import android.view.animation.Animation;
+import android.view.animation.AnimationSet;
+import android.view.animation.LayoutAnimationController;
+import android.view.animation.TranslateAnimation;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+import android.widget.SimpleCursorAdapter;
+import android.widget.Toast;
+
+/**
+ * See 1080989. You need some contacts for this adapter.
+ */
+public class ListWithDisappearingItemBug extends ListActivity {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ Toast.makeText(this, "Make sure you rotate screen to see bug", Toast.LENGTH_LONG).show();
+
+ // Get a cursor with all people
+ Cursor c = getContentResolver().query(People.CONTENT_URI, null, null, null, null);
+ startManagingCursor(c);
+
+ ListAdapter adapter = new SimpleCursorAdapter(this,
+ // Use a template that displays a text view
+ R.layout.list_with_disappearing_item_bug_item,
+ // Give the cursor to the list adatper
+ c,
+ // Map the NAME column in the people database to...
+ new String[] {People.NAME} ,
+ // The "text1" view defined in the XML template
+ new int[] {R.id.text1});
+ setListAdapter(adapter);
+
+ AnimationSet set = new AnimationSet(true);
+
+ Animation animation = new AlphaAnimation(0.0f, 1.0f);
+ animation.setDuration(50);
+ set.addAnimation(animation);
+
+ animation = new TranslateAnimation(
+ Animation.RELATIVE_TO_SELF, 0.0f,Animation.RELATIVE_TO_SELF, 0.0f,
+ Animation.RELATIVE_TO_SELF, -1.0f,Animation.RELATIVE_TO_SELF, 0.0f
+ );
+ animation.setDuration(100);
+ set.addAnimation(animation);
+
+ LayoutAnimationController controller =
+ new LayoutAnimationController(set, 0.5f);
+ ListView listView = getListView();
+ listView.setLayoutAnimation(controller);
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java
new file mode 100644
index 0000000..b5cac2a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEditTextHeader.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * A list view with a single edit text in a header.
+ */
+public class ListWithEditTextHeader extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setHeaderViewCount(1)
+ .setHeaderFocusable(true)
+ .setItemsFocusable(true)
+ .setNumItems(6)
+ .setItemScreenSizeFactor(0.2);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java
new file mode 100644
index 0000000..6f43551
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithEmptyView.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ArrayAdapter;
+
+
+/**
+ * Tests using an empty view with a list */
+public class ListWithEmptyView extends ListActivity {
+
+ private class CarefulAdapter<T> extends ArrayAdapter<T> {
+
+ public CarefulAdapter(Context context, int textViewResourceId) {
+ super(context, textViewResourceId);
+ // TODO Auto-generated constructor stub
+ }
+
+ @Override
+ public long getItemId(int position) {
+ if (position < 0 || position >= this.getCount()) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return super.getItemId(position);
+ }
+
+
+ }
+
+ public static final int MENU_ADD = Menu.FIRST + 1;
+ public static final int MENU_REMOVE = Menu.FIRST + 2;
+
+ private CarefulAdapter<String> mAdapter;
+
+ private int mNextItem = 0;
+
+ private View mEmptyView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ mAdapter = new CarefulAdapter<String>(this,
+ android.R.layout.simple_list_item_1);
+ setContentView(R.layout.list_with_empty_view);
+ setListAdapter(mAdapter);
+
+ mEmptyView = findViewById(R.id.empty);
+ getListView().setEmptyView(mEmptyView);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ super.onCreateOptionsMenu(menu);
+ menu.add(0, MENU_ADD, 0, R.string.menu_add)
+ .setIcon(android.R.drawable.ic_menu_add);
+ menu.add(0, MENU_REMOVE, 0, R.string.menu_remove)
+ .setIcon(android.R.drawable.ic_menu_delete);
+ return true;
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ switch (item.getItemId()) {
+ case MENU_ADD:
+ String str = "Item + " + mNextItem++;
+ mAdapter.add(str);
+ return true;
+ case MENU_REMOVE:
+ if (mAdapter.getCount() > 0) {
+ mAdapter.remove(mAdapter.getItem(0));
+ }
+ return true;
+ }
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ public View getEmptyView() {
+ return mEmptyView;
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
new file mode 100644
index 0000000..4ad72fd
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithFirstScreenUnSelectable.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * The first item is unselectable, and takes up the whole screen.
+ */
+public class ListWithFirstScreenUnSelectable extends ListScenario {
+
+ @Override
+ protected void init(Params params) {
+ params.setItemScreenSizeFactor(1.2)
+ .setNumItems(2)
+ .setPositionsUnselectable(0);
+
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java
new file mode 100644
index 0000000..d523094
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithHeaders.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ListWithHeaders extends ListScenario {
+ @Override
+ protected void init(Params params) {
+ params.setStackFromBottom(false)
+ .setStartingSelectionPosition(-1)
+ .setNumItems(24)
+ .setItemScreenSizeFactor(0.14);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final ListView listView = getListView();
+ listView.setItemsCanFocus(true);
+
+ for (int i = 0; i < 12; i++) {
+ Button header = new Button(this);
+ header.setText("Header View");
+ listView.addHeaderView(header);
+ }
+
+ for (int i = 0; i < 12; i++) {
+ Button footer = new Button(this);
+ footer.setText("Footer View");
+ listView.addFooterView(footer);
+ }
+
+ final ListAdapter adapter = listView.getAdapter();
+ listView.setAdapter(adapter);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java
new file mode 100644
index 0000000..ecfc793
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithNoFadingEdge.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListWithNoFadingEdge extends ListScenario {
+
+ protected void init(Params params) {
+ params.setFadingEdgeScreenSizeFactor(0.0)
+ .setNumItems(10)
+ .setItemScreenSizeFactor(0.2);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java
new file mode 100644
index 0000000..71525c0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOffScreenNextSelectable.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Pressing down from position 0 requires looking past positions 1, 2 and 3 to
+ * an offscreen item to know that it is the next selectable.
+ */
+public class ListWithOffScreenNextSelectable extends ListScenario {
+
+
+ protected void init(Params params) {
+ params.setItemsFocusable(false)
+ .setNumItems(5)
+ .setItemScreenSizeFactor(0.25)
+ .setPositionUnselectable(1)
+ .setPositionUnselectable(2)
+ .setPositionUnselectable(3);
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java
new file mode 100644
index 0000000..2683040
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithOnItemSelectedAction.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.widget.TextView;
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * The header text view echos the value of the selected item by using (indirectly)
+ * the {@link android.widget.AdapterView.OnItemSelectedListener}.
+ */
+public class ListWithOnItemSelectedAction extends ListScenario {
+ protected void init(Params params) {
+ params.setNumItems(8)
+ .setItemScreenSizeFactor(0.2)
+ .includeHeaderAboveList(true);
+
+ }
+
+ @Override
+ protected void positionSelected(int positon) {
+ if (positon != getListView().getSelectedItemPosition()) {
+ throw new IllegalStateException("something is fishy... the selected postion does not " +
+ "match what the list reports.");
+ }
+ setHeaderValue(
+ ((TextView) getListView().getSelectedView()).getText().toString());
+
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java
new file mode 100644
index 0000000..a2f3dc2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithScreenOfNoSelectables.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+public class ListWithScreenOfNoSelectables extends ListScenario {
+
+ protected void init(Params params) {
+ params.setNumItems(10)
+ .setItemScreenSizeFactor(0.2)
+ .setPositionsUnselectable(1, 2, 3, 4, 5, 6, 7, 8, 9);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java
new file mode 100644
index 0000000..71ce4e7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/listview/ListWithSeparators.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.util.ListScenario;
+
+/**
+ * Basic separator scenario, nothing fancy.
+ */
+public class ListWithSeparators extends ListScenario {
+
+ protected void init(Params params) {
+ params.setItemsFocusable(false)
+ .setNumItems(5)
+ .setItemScreenSizeFactor(0.22)
+ .setPositionUnselectable(0)
+ .setPositionUnselectable(2);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java
new file mode 100644
index 0000000..13c7552
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/ListContextMenu.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.R;
+
+import android.app.ListActivity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+import android.view.ContextMenu.ContextMenuInfo;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.TextView;
+
+/**
+ * Exercises context menus in lists
+ */
+public class ListContextMenu extends ListActivity implements View.OnCreateContextMenuListener
+{
+ static final String TAG = "ListContextMenu";
+
+ ThrashListAdapter mAdapter;
+
+ private class ThrashListAdapter extends BaseAdapter {
+ private LayoutInflater mInflater;
+
+ private String[] mTitles = new String[100];
+
+ public ThrashListAdapter(Context context) {
+ mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ mTitles = new String[100];
+
+ int i;
+ for (i=0; i<100; i++) {
+ mTitles[i] = "[" + i + "]";
+ }
+ }
+
+ public int getCount() {
+ return mTitles.length;
+ }
+
+ public Object getItem(int position) {
+ return position;
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView view;
+
+ if (convertView == null) {
+ view = (TextView) mInflater.inflate(android.R.layout.simple_list_item_1, null);
+ } else {
+ view = (TextView) convertView;
+ }
+ view.setText("List item " + mTitles[position]);
+ return view;
+ }
+
+ }
+
+ @Override
+ public void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+
+ mAdapter = new ThrashListAdapter(this);
+ getListView().setOnCreateContextMenuListener(this);
+ setListAdapter(mAdapter);
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ MenuItem item = menu.add(0, 0, 0, "Really long menu item name");
+ item.setTitleCondensed("Long name");
+ item.setIcon(R.drawable.black_square);
+
+ SubMenu sm = menu.addSubMenu(0, 0, 0, "The 2nd item, a sub menu").setIcon(R.drawable.black_square_stretchable);
+ item = sm.getItem();
+ item.setTitleCondensed("Sub menu");
+ sm.add(1, 0, 0, "Subitem 1");
+ sm.add(1, 0, 0, "Subitem 2");
+ sm.add(1, 0, 0, "Subitem 3");
+ sm.setGroupCheckable(1, true, true);
+ menu.add(0, 0, 0, "Item 3");
+ menu.add(0, 0, 0, "Item 4");
+ menu.add(0, 0, 0, "Item 5");
+ menu.add(0, 0, 0, "Item 6");
+ menu.add(0, 0, 0, "Item 7");
+ menu.add(0, 0, 0, "Item 8");
+ menu.add(0, 0, 0, "Item 9");
+ sm = menu.addSubMenu(0, 0, 0, "Item 10 SM");
+ sm.add(0, 0, 0, "Subitem 1");
+ sm.add(0, 0, 0, "Subitem 2");
+ sm.add(0, 0, 0, "Subitem 3");
+ sm.add(0, 0, 0, "Subitem 4");
+ sm.add(0, 0, 0, "Subitem 5");
+ sm.add(0, 0, 0, "Subitem 6");
+ sm.add(0, 0, 0, "Subitem 7");
+ sm.add(0, 0, 0, "Subitem 8");
+
+ return true;
+ }
+
+ public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
+
+ AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo)menuInfo;
+
+ String text = ((TextView) info.targetView).getText().toString();
+ if (text.contains("[0]")) {
+ menu.setHeaderTitle("This is a test of the title and the icon").setHeaderIcon(
+ android.R.drawable.sym_def_app_icon);
+ } else if (text.contains("[1]")) {
+ menu.setHeaderTitle("This is a test of just the title");
+ } else {
+ TextView textView = new TextView(this);
+ textView.setText("This is a test of a custom View");
+ menu.setHeaderView(textView);
+ }
+
+ menu.add(0, 0, 0, "Test 1");
+ SubMenu sm = menu.addSubMenu(0, 0, 0, "Test 1.5 SM");
+ sm.add(0, 0, 0, "CM Subitem 1");
+ sm.add(0, 0, 0, "CM Subitem 2");
+ sm.add(0, 0, 0, "CM Subitem 3");
+ menu.add(0, 0, 0, "Test 2");
+ menu.add(0, 0, 0, "Test 3");
+ menu.add(0, 0, 0, "Test 4");
+ menu.add(0, 0, 0, "Test 5");
+ menu.add(0, 0, 0, "Test 6");
+ menu.add(0, 0, 0, "Test 7");
+ menu.add(0, 0, 0, "Test 8");
+ menu.add(0, 0, 0, "Test 9");
+ menu.add(0, 0, 0, "Test 10");
+ menu.add(0, 0, 0, "Test 11");
+ menu.add(0, 0, 0, "Test 12");
+ menu.add(0, 0, 0, "Test 13");
+ menu.add(0, 0, 0, "Test 14");
+ menu.add(0, 0, 0, "Test 15");
+ menu.add(0, 0, 0, "Test 16");
+ menu.add(0, 0, 0, "Test 17");
+ menu.add(0, 0, 0, "Test 18");
+ menu.add(0, 0, 0, "Test 19");
+ menu.add(0, 0, 0, "Test 20");
+ menu.add(0, 0, 0, "Test 21");
+ menu.add(0, 0, 0, "Test 22");
+ menu.add(0, 0, 0, "Test 23");
+ menu.add(0, 0, 0, "Test 24");
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item) {
+ Log.i(TAG, "Options item " + item.toString() + " selected.");
+
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onOptionsMenuClosed(Menu menu) {
+ Log.i(TAG, "Options menu closed");
+ }
+
+ @Override
+ public boolean onContextItemSelected(MenuItem item) {
+ Log.i(TAG, "Context item " + item.toString() + " selected.");
+
+ return super.onContextItemSelected(item);
+ }
+
+ @Override
+ public void onContextMenuClosed(Menu menu) {
+ Log.i(TAG, "Context menu closed");
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java
new file mode 100644
index 0000000..6ed6433
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayout.java
@@ -0,0 +1,65 @@
+/**
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.menus.MenuScenario.Params;
+
+import android.os.Bundle;
+import android.view.Menu;
+import android.widget.Button;
+
+public class MenuLayout extends MenuScenario {
+ private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+ private static final String SHORT_TITLE = "Item";
+
+ private Button mButton;
+
+ @Override
+ protected void onInitParams(Params params) {
+ super.onInitParams(params);
+ params
+ .setNumItems(2)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE);
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+
+ /*
+ * This activity is meant to try a bunch of different menu layouts. So,
+ * we recreate the menu every time it is prepared.
+ */
+ menu.clear();
+ onCreateOptionsMenu(menu);
+
+ return true;
+ }
+
+ public Button getButton() {
+ return mButton;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mButton = new Button(this);
+ setContentView(mButton);
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java
new file mode 100644
index 0000000..8a98610
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutLandscape.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+/**
+ * An activity (inherits from MenuLayout) that shows in landscape.
+ */
+public class MenuLayoutLandscape extends MenuLayout {
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java
new file mode 100644
index 0000000..71e7e49
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuLayoutPortrait.java
@@ -0,0 +1,24 @@
+/**
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+/**
+ * An activity (inherits from MenuLayout) that shows in portrait.
+ */
+public class MenuLayoutPortrait extends MenuLayout {
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java
new file mode 100644
index 0000000..4df9b1b
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuScenario.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.util.ListScenario;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuBuilder.MenuAdapter;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * Utility base class for creating various Menu scenarios. Configurable by the
+ * number of menu items. Used @link {@link ListScenario} as a reference.
+ */
+public class MenuScenario extends Activity implements MenuItem.OnMenuItemClickListener {
+ private Params mParams = new Params();
+ private Menu mMenu;
+ private MenuItem[] mItems;
+ private boolean[] mWasItemClicked;
+ private MenuAdapter[] mMenuAdapters = new MenuAdapter[MenuBuilder.NUM_TYPES];
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ dispatchInitParams();
+ }
+
+ private void dispatchInitParams() {
+ onInitParams(mParams);
+ onParamsChanged();
+ }
+
+ public void setParams(Params params) {
+ mParams = params;
+ onParamsChanged();
+ }
+
+ public void onParamsChanged() {
+ mItems = new MenuItem[mParams.numItems];
+ mWasItemClicked = new boolean[mParams.numItems];
+ }
+
+ @Override
+ public boolean onCreateOptionsMenu(Menu menu) {
+ // Safe to hold on to
+ mMenu = menu;
+
+ if (!mParams.shouldShowMenu) return false;
+
+ MenuItem item;
+ for (int i = 0; i < mParams.numItems; i++) {
+ if ((item = onAddMenuItem(menu, i)) == null) {
+ // Add a default item for this position if the subclasses
+ // haven't
+ CharSequence givenTitle = mParams.itemTitles.get(i);
+ item = menu.add(0, 0, 0, (givenTitle != null) ? givenTitle : ("Item " + i));
+ }
+
+ if (item != null) {
+ mItems[i] = item;
+
+ if (mParams.listenForClicks) {
+ item.setOnMenuItemClickListener(this);
+ }
+ }
+
+ }
+
+ return true;
+ }
+
+ @Override
+ public boolean onPrepareOptionsMenu(Menu menu) {
+ // Safe to hold on to
+ mMenu = menu;
+
+ return mParams.shouldShowMenu;
+ }
+
+ /**
+ * Override this to add an item to the menu.
+ *
+ * @param itemPosition The position of the item to add (only for your
+ * reference).
+ * @return The item that was added to the menu, or null if nothing was
+ * added.
+ */
+ protected MenuItem onAddMenuItem(Menu menu, int itemPosition) {
+ return null;
+ }
+
+ /**
+ * Override this to set the parameters for the scenario. Call through to super first.
+ *
+ * @param params
+ */
+ protected void onInitParams(Params params) {
+ }
+
+ public Menu getMenu() {
+ return mMenu;
+ }
+
+ public boolean onMenuItemClick(MenuItem item) {
+ final int position = findItemPosition(item);
+ if (position < 0) return false;
+
+ mWasItemClicked[position] = true;
+
+ return true;
+ }
+
+ public boolean wasItemClicked(int position) {
+ return mWasItemClicked[position];
+ }
+
+ /**
+ * Finds the position for a given Item.
+ *
+ * @param item The item to find.
+ * @return The position, or -1 if not found.
+ */
+ public int findItemPosition(MenuItem item) {
+ // Could create reverse mapping, but optimizations aren't important (yet :P)
+ for (int i = 0; i < mParams.numItems; i++) {
+ if (mItems[i] == item) return i;
+ }
+
+ return -1;
+ }
+
+ /**
+ * @see MenuBuilder#getMenuAdapter(int)
+ */
+ public MenuAdapter getMenuAdapter(int menuType) {
+ if (mMenuAdapters[menuType] == null) {
+ mMenuAdapters[menuType] = ((MenuBuilder) mMenu).getMenuAdapter(menuType);
+ }
+
+ return mMenuAdapters[menuType];
+ }
+
+ /**
+ * Gets a menu view. Call this after you're sure it has been shown,
+ * otherwise it may not have the proper layout_* attributes set.
+ *
+ * @param menuType The type of menu.
+ * @return The MenuView for that type.
+ */
+ public View getMenuView(int menuType) {
+ return ((MenuBuilder) mMenu).getMenuView(menuType, null);
+ }
+
+ /**
+ * Gets the menu item view for a given position.
+ *
+ * @param menuType The type of menu.
+ * @param position The position of the item.
+ * @return The menu item view for the given item in the given menu type.
+ */
+ public View getItemView(int menuType, int position) {
+ return getMenuAdapter(menuType).getView(position, null, null);
+ }
+
+ public static class Params {
+ // Using as data structure, so no m prefix
+ private boolean shouldShowMenu = true;
+ private int numItems = 10;
+ private boolean listenForClicks = true;
+ private SparseArray<CharSequence> itemTitles = new SparseArray<CharSequence>();
+
+ public Params setShouldShowMenu(boolean shouldShowMenu) {
+ this.shouldShowMenu = shouldShowMenu;
+ return this;
+ }
+
+ public Params setNumItems(int numItems) {
+ this.numItems = numItems;
+ return this;
+ }
+
+ public Params setListenForClicks(boolean listenForClicks) {
+ this.listenForClicks = listenForClicks;
+ return this;
+ }
+
+ public Params setItemTitle(int itemPos, CharSequence title) {
+ itemTitles.put(itemPos, title);
+ return this;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java
new file mode 100644
index 0000000..d7468f5
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/menus/MenuWith1Item.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import android.os.Bundle;
+import android.widget.Button;
+
+public class MenuWith1Item extends MenuScenario {
+
+ private Button mButton;
+
+ @Override
+ protected void onInitParams(Params params) {
+ super.onInitParams(params);
+
+ params.setNumItems(1);
+ }
+
+ public Button getButton() {
+ return mButton;
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mButton = new Button(this);
+ setContentView(mButton);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java b/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java
new file mode 100644
index 0000000..8663f06
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/performance/InvalidateCycle.java
@@ -0,0 +1,49 @@
+package com.android.frameworktest.performance;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Debug;
+import android.os.Handler;
+import android.view.View;
+import android.view.ViewGroup;
+import android.content.Context;
+import android.graphics.Canvas;
+
+public class InvalidateCycle extends Activity {
+ private boolean mStartProfiling;
+ private InvalidateCycle.AutoInvalidateView mView;
+
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mView = new AutoInvalidateView(this);
+ mView.setLayoutParams(new ViewGroup.LayoutParams(16, 16));
+ setContentView(mView);
+
+ new Handler().postDelayed(new Runnable() {
+ public void run() {
+ mStartProfiling = true;
+ android.util.Log.d("Performance", "Profiling started");
+ Debug.startMethodTracing("invalidateCycle");
+ mView.invalidate();
+ }
+ }, 15000);
+ }
+
+ private class AutoInvalidateView extends View {
+ private boolean mFirstDraw;
+
+ public AutoInvalidateView(Context context) {
+ super(context);
+ }
+
+ protected void onDraw(Canvas canvas) {
+ if (mStartProfiling && !mFirstDraw) {
+ Debug.stopMethodTracing();
+ android.util.Log.d("Performance", "Profiling ended");
+ mFirstDraw = true;
+ }
+ canvas.drawColor(0xFFFF0000);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java
new file mode 100644
index 0000000..986b800
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionView.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.util.InternalSelectionView;
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+
+/**
+ * A button above a tall internal selection view, wrapped in a scroll view.
+ */
+public class ButtonAboveTallInternalSelectionView extends ScrollViewScenario {
+
+ private final int mNumRowsInIsv = 5;
+
+
+ public Button getButtonAbove() {
+ return getContentChildAt(0);
+ }
+
+ public InternalSelectionView getIsv() {
+ return getContentChildAt(1);
+ }
+
+
+ protected void init(Params params) {
+ params.addButton("howdy", 0.1f)
+ .addInternalSelectionView(mNumRowsInIsv, 1.1f)
+ .addButton("below", 0.1f);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java
new file mode 100644
index 0000000..ed098aa
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ButtonsWithTallTextViewInBetween.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Two buttons sandwiching a tall text view (good for testing panning across
+ * before getting to next button).
+ */
+public class ButtonsWithTallTextViewInBetween extends ScrollViewScenario {
+
+ public Button getTopButton() {
+ return getContentChildAt(0);
+ }
+
+ public TextView getMiddleFiller() {
+ return getContentChildAt(1);
+ }
+
+ public Button getBottomButton() {
+ LinearLayout ll = getContentChildAt(2);
+ return (Button) ll.getChildAt(0);
+ }
+
+ protected void init(Params params) {
+
+ params.addButton("top button", 0.2f)
+ .addTextView("middle filler", 1.51f)
+ .addVerticalLLOfButtons("bottom", 1, 0.2f);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java
new file mode 100644
index 0000000..affd3c7
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisible.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.graphics.Rect;
+import android.view.View;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * A screen with some scenarios that exercise {@link ScrollView}'s implementation
+ * of {@link android.view.ViewGroup#requestChildRectangleOnScreen}:
+ * <li>Scrolling to something off screen (from top and from bottom)
+ * <li>Scrolling to bring something that is larger than the screen on screen
+ * (from top and from bottom).
+ */
+public class RequestRectangleVisible extends Activity {
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.scroll_to_rectangle);
+
+ final Rect rect = new Rect();
+ final View childToMakeVisible = findViewById(R.id.childToMakeVisible);
+
+ final TextView topBlob = (TextView) findViewById(R.id.topBlob);
+ final TextView bottomBlob = (TextView) findViewById(R.id.bottomBlob);
+
+ // estimate to get blobs larger than screen
+ int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
+ int numLinesForScreen = screenHeight / 18;
+
+ for (int i = 0; i < numLinesForScreen; i++) {
+ topBlob.append(i + " another line in the blob\n");
+ bottomBlob.append(i + " another line in the blob\n");
+ }
+
+ findViewById(R.id.scrollToRectFromTop).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ rect.set(0, 0, childToMakeVisible.getLeft(), childToMakeVisible.getHeight());
+ childToMakeVisible.requestRectangleOnScreen(rect, true);
+ }
+ });
+
+ findViewById(R.id.scrollToRectFromTop2).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ rect.set(0, 0, topBlob.getWidth(), topBlob.getHeight());
+ topBlob.requestRectangleOnScreen(rect, true);
+ }
+ });
+
+ findViewById(R.id.scrollToRectFromBottom).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ rect.set(0, 0, childToMakeVisible.getLeft(), childToMakeVisible.getHeight());
+ childToMakeVisible.requestRectangleOnScreen(rect, true);
+ }
+ });
+
+ findViewById(R.id.scrollToRectFromBottom2).setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+ rect.set(0, 0, bottomBlob.getWidth(), bottomBlob.getHeight());
+ bottomBlob.requestRectangleOnScreen(rect, true);
+ }
+ });
+
+ }
+
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java
new file mode 100644
index 0000000..0a8dc30
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScroll.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.Button;
+import android.view.View;
+import android.graphics.Rect;
+
+public class RequestRectangleVisibleWithInternalScroll extends Activity {
+
+ private int scrollYofBlob = 52;
+
+ private TextView mTextBlob;
+ private Button mScrollToBlob;
+
+
+ public int getScrollYofBlob() {
+ return scrollYofBlob;
+ }
+
+
+ public TextView getTextBlob() {
+ return mTextBlob;
+ }
+
+
+ public Button getScrollToBlob() {
+ return mScrollToBlob;
+ }
+
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ setContentView(R.layout.scroll_to_rect_with_internal_scroll);
+
+ mTextBlob = (TextView) findViewById(R.id.blob);
+ mTextBlob.scrollBy(0, scrollYofBlob);
+
+
+ mScrollToBlob = (Button) findViewById(R.id.scrollToBlob);
+ mScrollToBlob.setOnClickListener(new View.OnClickListener() {
+
+ public void onClick(View v) {
+
+ // the rect we want to make visible is offset to match
+ // the internal scroll
+ Rect rect = new Rect();
+ rect.set(0, 0, 0, mTextBlob.getHeight());
+ rect.offset(0, mTextBlob.getScrollY());
+ mTextBlob.requestRectangleOnScreen(rect);
+ }
+ });
+ }
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java
new file mode 100644
index 0000000..4763ab1
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabels.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.widget.Button;
+
+
+/**
+ * Basic scroll view example
+ */
+public class ScrollViewButtonsAndLabels extends Activity {
+
+ private ScrollView mScrollView;
+ private LinearLayout mLinearLayout;
+
+ private int mNumGroups = 10;
+
+
+ public ScrollView getScrollView() {
+ return mScrollView;
+ }
+
+ public LinearLayout getLinearLayout() {
+ return mLinearLayout;
+ }
+
+ public int getNumButtons() {
+ return mNumGroups;
+ }
+
+ public Button getButton(int groupNum) {
+ if (groupNum > mNumGroups) {
+ throw new IllegalArgumentException("groupNum > " + mNumGroups);
+ }
+ return (Button) mLinearLayout.getChildAt(2*groupNum);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.scrollview_linear_layout);
+
+
+ // estimated ratio to get enough buttons so a couple are off screen
+ int screenHeight = getWindowManager().getDefaultDisplay().getHeight();
+ mNumGroups = screenHeight / 30;
+
+ mScrollView = (ScrollView) findViewById(R.id.scrollView);
+ mLinearLayout = (LinearLayout) findViewById(R.id.layout);
+
+ LinearLayout.LayoutParams p = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ );
+
+ for (int i = 0; i < mNumGroups; i++) {
+ // want button to be first and last
+ if (i > 0) {
+ TextView textView = new TextView(this);
+ textView.setText("Text View " + i);
+ mLinearLayout.addView(textView, p);
+ }
+
+ Button button = new Button(this);
+ button.setText("Button " + (i + 1));
+ mLinearLayout.addView(button, p);
+ }
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java
new file mode 100644
index 0000000..b903382
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/ShortButtons.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * A series of short buttons, some of which are embedded within another
+ * layout.
+ */
+public class ShortButtons extends ScrollViewScenario {
+
+ private final int mNumButtons = 10;
+ protected final float mButtonHeightFactor = 0.2f;
+
+ public int getNumButtons() {
+ return mNumButtons;
+ }
+
+ public Button getButtonAt(int index) {
+ if (index < 3) {
+ return getContentChildAt(index);
+ } else {
+ LinearLayout ll = getContentChildAt(3);
+ return (Button) ll.getChildAt(index - 3);
+ }
+ }
+
+ @Override
+ protected void init(Params params) {
+ final int numButtonsInSubLayout = getNumButtons() - 3;
+ params.addButtons(3, "top-level", mButtonHeightFactor)
+ .addVerticalLLOfButtons("embedded",
+ numButtonsInSubLayout,
+ numButtonsInSubLayout * mButtonHeightFactor);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java b/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java
new file mode 100644
index 0000000..8b2e4f9
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/scroll/TallTextAboveButton.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.util.ScrollViewScenario;
+
+/**
+ * An (unfocusable) text view that takes up more than the height
+ * of the screen followed by a button.
+ */
+public class TallTextAboveButton extends ScrollViewScenario {
+
+ protected void init(Params params) {
+ params.addTextView("top tall", 1.1f)
+ .addButton("button", 0.2f);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java
new file mode 100644
index 0000000..b812181
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/settings/BrightnessLimit.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.settings;
+
+import android.os.IHardwareService;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.provider.Settings;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+
+/**
+ * Tries to set the brightness to 0. Should be silently thwarted by the framework.
+ */
+public class BrightnessLimit extends Activity implements OnClickListener {
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.brightness_limit);
+
+ Button b = (Button) findViewById(R.id.go);
+ b.setOnClickListener(this);
+ }
+
+ public void onClick(View v) {
+ IHardwareService hardware = IHardwareService.Stub.asInterface(
+ ServiceManager.getService("hardware"));
+ if (hardware != null) {
+ try {
+ hardware.setScreenBacklight(0);
+ } catch (RemoteException darn) {
+
+ }
+ }
+ Settings.System.putInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, 0);
+ }
+}
+
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java b/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java
new file mode 100644
index 0000000..19113da
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/settings/RingtonePickerActivityLauncher.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.settings;
+
+import com.android.internal.app.RingtonePickerActivity;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * Activity that will launch the RingtonePickerActivity as a subactivity, and
+ * waits for its result.
+ */
+public class RingtonePickerActivityLauncher extends Activity {
+
+ private static final String TAG = "RingtonePickerActivityLauncher";
+
+ public boolean resultReceived = false;
+
+ public int resultCode;
+ public Intent result;
+
+ public Uri pickedUri;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(android.R.layout.simple_list_item_1);
+ }
+
+ /**
+ * Launches the {@link RingtonePickerActivity} and blocks until it returns.
+ *
+ * @param showDefault {@link RingtonePickerActivity#EXTRA_SHOW_DEFAULT}
+ * @param existingUri {@link RingtonePickerActivity#EXTRA_EXISTING_URI}
+ * @param filterColumns {@link RingtonePickerActivity#EXTRA_RINGTONE_COLUMNS}
+ */
+ public void launchRingtonePickerActivity(boolean showDefault, Uri existingUri,
+ int types) {
+ Intent intent = new Intent(RingtoneManager.ACTION_RINGTONE_PICKER);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_SHOW_DEFAULT, showDefault);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_EXISTING_URI, existingUri);
+ intent.putExtra(RingtoneManager.EXTRA_RINGTONE_TYPE, types);
+ startActivityForResult(intent, 0);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ super.onActivityResult(requestCode, resultCode, data);
+
+ resultReceived = true;
+
+ this.resultCode = resultCode;
+ this.result = data;
+
+ if (data != null) {
+ this.pickedUri = data.getParcelableExtra(RingtoneManager.EXTRA_RINGTONE_PICKED_URI);
+ }
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java
new file mode 100644
index 0000000..f72cbe8
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ExpandableListScenario.java
@@ -0,0 +1,387 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+import android.widget.ListView;
+import android.widget.TextView;
+
+/**
+ * Utility base class for creating various Expandable List scenarios.
+ * <p>
+ * WARNING: A lot of the features are mixed between ListView's expected position
+ * (flat list position) and an ExpandableListView's expected position. You must add/change
+ * features as you need them.
+ *
+ * @see ListScenario
+ */
+public abstract class ExpandableListScenario extends ListScenario {
+ protected ExpandableListAdapter mAdapter;
+ protected List<MyGroup> mGroups;
+
+ @Override
+ protected ListView createListView() {
+ return new ExpandableListView(this);
+ }
+
+ @Override
+ protected Params createParams() {
+ return new ExpandableParams();
+ }
+
+ @Override
+ protected void setAdapter(ListView listView) {
+ ((ExpandableListView) listView).setAdapter(mAdapter = createAdapter());
+ }
+
+ protected ExpandableListAdapter createAdapter() {
+ return new MyAdapter();
+ }
+
+ @Override
+ protected void readAndValidateParams(Params params) {
+ ExpandableParams expandableParams = (ExpandableParams) params;
+
+ int[] numChildren = expandableParams.mNumChildren;
+
+ mGroups = new ArrayList<MyGroup>(numChildren.length);
+ for (int i = 0; i < numChildren.length; i++) {
+ mGroups.add(new MyGroup(numChildren[i]));
+ }
+
+ expandableParams.superSetNumItems();
+
+ super.readAndValidateParams(params);
+ }
+
+ /**
+ * Get the ExpandableListView widget.
+ * @return The main widget.
+ */
+ public ExpandableListView getExpandableListView() {
+ return (ExpandableListView) super.getListView();
+ }
+
+ public static class ExpandableParams extends Params {
+ private int[] mNumChildren;
+
+ /**
+ * Sets the number of children per group.
+ *
+ * @param numChildrenPerGroup The number of children per group.
+ */
+ public ExpandableParams setNumChildren(int[] numChildren) {
+ mNumChildren = numChildren;
+ return this;
+ }
+
+ /**
+ * Sets the number of items on the superclass based on the number of
+ * groups and children per group.
+ */
+ private ExpandableParams superSetNumItems() {
+ int numItems = 0;
+
+ if (mNumChildren != null) {
+ for (int i = mNumChildren.length - 1; i >= 0; i--) {
+ numItems += mNumChildren[i];
+ }
+ }
+
+ super.setNumItems(numItems);
+
+ return this;
+ }
+
+ @Override
+ public Params setNumItems(int numItems) {
+ throw new IllegalStateException("Use setNumGroups and setNumChildren instead.");
+ }
+
+ @Override
+ public ExpandableParams setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
+ return (ExpandableParams) super.setFadingEdgeScreenSizeFactor(fadingEdgeScreenSizeFactor);
+ }
+
+ @Override
+ public ExpandableParams setItemScreenSizeFactor(double itemScreenSizeFactor) {
+ return (ExpandableParams) super.setItemScreenSizeFactor(itemScreenSizeFactor);
+ }
+
+ @Override
+ public ExpandableParams setItemsFocusable(boolean itemsFocusable) {
+ return (ExpandableParams) super.setItemsFocusable(itemsFocusable);
+ }
+
+ @Override
+ public ExpandableParams setMustFillScreen(boolean fillScreen) {
+ return (ExpandableParams) super.setMustFillScreen(fillScreen);
+ }
+
+ @Override
+ public ExpandableParams setPositionScreenSizeFactorOverride(int position, double itemScreenSizeFactor) {
+ return (ExpandableParams) super.setPositionScreenSizeFactorOverride(position, itemScreenSizeFactor);
+ }
+
+ @Override
+ public ExpandableParams setPositionUnselectable(int position) {
+ return (ExpandableParams) super.setPositionUnselectable(position);
+ }
+
+ @Override
+ public ExpandableParams setStackFromBottom(boolean stackFromBottom) {
+ return (ExpandableParams) super.setStackFromBottom(stackFromBottom);
+ }
+
+ @Override
+ public ExpandableParams setStartingSelectionPosition(int startingSelectionPosition) {
+ return (ExpandableParams) super.setStartingSelectionPosition(startingSelectionPosition);
+ }
+
+ @Override
+ public ExpandableParams setConnectAdapter(boolean connectAdapter) {
+ return (ExpandableParams) super.setConnectAdapter(connectAdapter);
+ }
+ }
+
+ /**
+ * Gets a string for the value of some item.
+ * @param packedPosition The position of the item.
+ * @return The string.
+ */
+ public final String getValueAtPosition(long packedPosition) {
+ final int type = ExpandableListView.getPackedPositionType(packedPosition);
+
+ if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+ return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
+ .children.get(ExpandableListView.getPackedPositionChild(packedPosition))
+ .name;
+ } else if (type == ExpandableListView.PACKED_POSITION_TYPE_GROUP) {
+ return mGroups.get(ExpandableListView.getPackedPositionGroup(packedPosition))
+ .name;
+ } else {
+ throw new IllegalStateException("packedPosition is not a valid position.");
+ }
+ }
+
+ /**
+ * Whether a particular position is out of bounds.
+ *
+ * @param packedPosition The packed position.
+ * @return Whether it's out of bounds.
+ */
+ private boolean isOutOfBounds(long packedPosition) {
+ final int type = ExpandableListView.getPackedPositionType(packedPosition);
+
+ if (type == ExpandableListView.PACKED_POSITION_TYPE_NULL) {
+ throw new IllegalStateException("packedPosition is not a valid position.");
+ }
+
+ final int group = ExpandableListView.getPackedPositionGroup(packedPosition);
+ if (group >= mGroups.size() || group < 0) {
+ return true;
+ }
+
+ if (type == ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
+ final int child = ExpandableListView.getPackedPositionChild(packedPosition);
+ if (child >= mGroups.get(group).children.size() || child < 0) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets a view for the packed position, possibly reusing the convertView.
+ *
+ * @param packedPosition The position to get a view for.
+ * @param convertView Optional view to convert.
+ * @param parent The future parent.
+ * @return A view.
+ */
+ private View getView(long packedPosition, View convertView, ViewGroup parent) {
+ if (isOutOfBounds(packedPosition)) {
+ throw new IllegalStateException("position out of range for adapter!");
+ }
+
+ final ExpandableListView elv = getExpandableListView();
+ final int flPos = elv.getFlatListPosition(packedPosition);
+
+ if (convertView != null) {
+ ((TextView) convertView).setText(getValueAtPosition(packedPosition));
+ convertView.setId(flPos);
+ return convertView;
+ }
+
+ int desiredHeight = getHeightForPosition(flPos);
+ return createView(packedPosition, flPos, parent, desiredHeight);
+ }
+
+ /**
+ * Create a view for a group or child position.
+ *
+ * @param packedPosition The packed position (has type, group pos, and optionally child pos).
+ * @param flPos The flat list position (the position that the ListView goes by).
+ * @param parent The parent view.
+ * @param desiredHeight The desired height.
+ * @return A view.
+ */
+ protected View createView(long packedPosition, int flPos, ViewGroup parent, int desiredHeight) {
+ TextView result = new TextView(parent.getContext());
+ result.setHeight(desiredHeight);
+ result.setText(getValueAtPosition(packedPosition));
+ final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ result.setLayoutParams(lp);
+ result.setGravity(Gravity.CENTER_VERTICAL);
+ result.setPadding(36, 0, 0, 0);
+ result.setId(flPos);
+ return result;
+ }
+
+ /**
+ * Returns a group index containing either the number of children or at
+ * least one child.
+ *
+ * @param numChildren The group must have this amount, or -1 if using
+ * atLeastOneChild.
+ * @param atLeastOneChild The group must have at least one child, or false
+ * if using numChildren.
+ * @return A group index with the requirements.
+ */
+ public int findGroupWithNumChildren(int numChildren, boolean atLeastOneChild) {
+ final ExpandableListAdapter adapter = mAdapter;
+
+ for (int i = adapter.getGroupCount() - 1; i >= 0; i--) {
+ final int curNumChildren = adapter.getChildrenCount(i);
+
+ if (numChildren == curNumChildren || atLeastOneChild && curNumChildren > 0) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public List<MyGroup> getGroups() {
+ return mGroups;
+ }
+
+ public ExpandableListAdapter getAdapter() {
+ return mAdapter;
+ }
+
+ /**
+ * Simple expandable list adapter.
+ */
+ protected class MyAdapter extends BaseExpandableListAdapter {
+ public Object getChild(int groupPosition, int childPosition) {
+ return getValueAtPosition(ExpandableListView.getPackedPositionForChild(groupPosition,
+ childPosition));
+ }
+
+ public long getChildId(int groupPosition, int childPosition) {
+ return mGroups.get(groupPosition).children.get(childPosition).id;
+ }
+
+ public int getChildrenCount(int groupPosition) {
+ return mGroups.get(groupPosition).children.size();
+ }
+
+ public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
+ View convertView, ViewGroup parent) {
+ return getView(ExpandableListView.getPackedPositionForChild(groupPosition,
+ childPosition), convertView, parent);
+ }
+
+ public Object getGroup(int groupPosition) {
+ return getValueAtPosition(ExpandableListView.getPackedPositionForGroup(groupPosition));
+ }
+
+ public int getGroupCount() {
+ return mGroups.size();
+ }
+
+ public long getGroupId(int groupPosition) {
+ return mGroups.get(groupPosition).id;
+ }
+
+ public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
+ ViewGroup parent) {
+ return getView(ExpandableListView.getPackedPositionForGroup(groupPosition),
+ convertView, parent);
+ }
+
+ public boolean isChildSelectable(int groupPosition, int childPosition) {
+ return true;
+ }
+
+ public boolean hasStableIds() {
+ return true;
+ }
+
+ }
+
+ public static class MyGroup {
+ private static long mNextId = 1000;
+
+ String name;
+ long id = mNextId++;
+ List<MyChild> children;
+
+ public MyGroup(int numChildren) {
+ name = "Group " + id;
+ children = new ArrayList<MyChild>(numChildren);
+ for (int i = 0; i < numChildren; i++) {
+ children.add(new MyChild());
+ }
+ }
+ }
+
+ public static class MyChild {
+ private static long mNextId = 2000;
+
+ String name;
+ long id = mNextId++;
+
+ public MyChild() {
+ name = "Child " + id;
+ }
+ }
+
+ @Override
+ protected final void init(Params params) {
+ init((ExpandableParams) params);
+ }
+
+ /**
+ * @see ListScenario#init
+ */
+ protected abstract void init(ExpandableParams params);
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java
new file mode 100644
index 0000000..746cf23
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/GridScenario.java
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AbsListView;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.GridView;
+import android.widget.ListAdapter;
+import android.widget.TextView;
+
+import com.google.android.collect.Maps;
+
+import java.util.Map;
+
+/**
+ * Utility base class for creating various GridView scenarios. Configurable by the number
+ * of items, how tall each item should be (in relation to the screen height), and
+ * what item should start with selection.
+ */
+public abstract class GridScenario extends Activity {
+
+ private GridView mGridView;
+
+ private int mNumItems;
+
+ private int mStartingSelectionPosition;
+ private double mItemScreenSizeFactor;
+ private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+ private int mScreenHeight;
+
+ private boolean mStackFromBottom;
+
+ private int mColumnWidth;
+
+ private int mNumColumns;
+
+ private int mStretchMode;
+
+ private int mVerticalSpacing;
+
+ public GridView getGridView() {
+ return mGridView;
+ }
+
+ protected int getScreenHeight() {
+ return mScreenHeight;
+ }
+
+ /**
+ * @return The initial number of items in the grid as specified by the scenario.
+ * This number may change over time.
+ */
+ protected int getInitialNumItems() {
+ return mNumItems;
+ }
+
+ /**
+ * @return The desired height of 1 item, ignoring overrides
+ */
+ public int getDesiredItemHeight() {
+ return (int) (mScreenHeight * mItemScreenSizeFactor);
+ }
+
+ /**
+ * Better way to pass in optional params than a honkin' paramater list :)
+ */
+ public static class Params {
+ private int mNumItems = 4;
+ private int mStartingSelectionPosition = -1;
+ private double mItemScreenSizeFactor = 1 / 5;
+
+ private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+ private boolean mStackFromBottom = false;
+ private boolean mMustFillScreen = true;
+
+ private int mColumnWidth = 0;
+ private int mNumColumns = GridView.AUTO_FIT;
+ private int mStretchMode = GridView.STRETCH_COLUMN_WIDTH;
+ private int mVerticalSpacing = 0;
+
+ /**
+ * Set the number of items in the grid.
+ */
+ public Params setNumItems(int numItems) {
+ mNumItems = numItems;
+ return this;
+ }
+
+ /**
+ * Set the position that starts selected.
+ *
+ * @param startingSelectionPosition The selected position within the adapter's data set.
+ * Pass -1 if you do not want to force a selection.
+ * @return
+ */
+ public Params setStartingSelectionPosition(int startingSelectionPosition) {
+ mStartingSelectionPosition = startingSelectionPosition;
+ return this;
+ }
+
+ /**
+ * Set the factor that determines how tall each item is in relation to the
+ * screen height.
+ */
+ public Params setItemScreenSizeFactor(double itemScreenSizeFactor) {
+ mItemScreenSizeFactor = itemScreenSizeFactor;
+ return this;
+ }
+
+ /**
+ * Override the item screen size factor for a particular item. Useful for
+ * creating grids with non-uniform item height.
+ * @param position The position in the grid.
+ * @param itemScreenSizeFactor The screen size factor to use for the height.
+ */
+ public Params setPositionScreenSizeFactorOverride(
+ int position, double itemScreenSizeFactor) {
+ mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor);
+ return this;
+ }
+
+ /**
+ * Sets the stacking direction
+ * @param stackFromBottom
+ * @return
+ */
+ public Params setStackFromBottom(boolean stackFromBottom) {
+ mStackFromBottom = stackFromBottom;
+ return this;
+ }
+
+ /**
+ * Sets whether the sum of the height of the grid items must be at least the
+ * height of the grid view.
+ */
+ public Params setMustFillScreen(boolean fillScreen) {
+ mMustFillScreen = fillScreen;
+ return this;
+ }
+
+ /**
+ * Sets the individual width of each column.
+ *
+ * @param requestedWidth the width in pixels of the column
+ */
+ public Params setColumnWidth(int requestedWidth) {
+ mColumnWidth = requestedWidth;
+ return this;
+ }
+
+ /**
+ * Sets the number of columns in the grid.
+ */
+ public Params setNumColumns(int numColumns) {
+ mNumColumns = numColumns;
+ return this;
+ }
+
+ /**
+ * Sets the stretch mode.
+ */
+ public Params setStretchMode(int stretchMode) {
+ mStretchMode = stretchMode;
+ return this;
+ }
+
+ /**
+ * Sets the spacing between rows in the grid
+ */
+ public Params setVerticalSpacing(int verticalSpacing) {
+ mVerticalSpacing = verticalSpacing;
+ return this;
+ }
+ }
+
+ /**
+ * How each scenario customizes its behavior.
+ * @param params
+ */
+ protected abstract void init(Params params);
+
+ /**
+ * Override this to provide an different adapter for your scenario
+ * @return The adapter that this scenario will use
+ */
+ protected ListAdapter createAdapter() {
+ return new MyAdapter();
+ }
+
+ /**
+ * Override this if you want to know when something has been selected (perhaps
+ * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has
+ * been triggered).
+ */
+ @SuppressWarnings({ "UnusedDeclaration" })
+ protected void positionSelected(int positon) {
+
+ }
+
+ /**
+ * Override this if you want to know that nothing is selected.
+ */
+ protected void nothingSelected() {
+
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // turn off title bar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+ mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+ final Params params = new Params();
+ init(params);
+
+ readAndValidateParams(params);
+
+ mGridView = new GridView(this);
+ mGridView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mGridView.setDrawSelectorOnTop(false);
+ if (mNumColumns >= GridView.AUTO_FIT) {
+ mGridView.setNumColumns(mNumColumns);
+ }
+ if (mColumnWidth > 0) {
+ mGridView.setColumnWidth(mColumnWidth);
+ }
+ if (mVerticalSpacing > 0) {
+ mGridView.setVerticalSpacing(mVerticalSpacing);
+ }
+ mGridView.setStretchMode(mStretchMode);
+ mGridView.setAdapter(createAdapter());
+ if (mStartingSelectionPosition >= 0) {
+ mGridView.setSelection(mStartingSelectionPosition);
+ }
+ mGridView.setPadding(10, 10, 10, 10);
+ mGridView.setStackFromBottom(mStackFromBottom);
+
+ mGridView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ positionSelected(position);
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ nothingSelected();
+ }
+ });
+
+ setContentView(mGridView);
+ }
+
+
+
+ /**
+ * Read in and validate all of the params passed in by the scenario.
+ * @param params
+ */
+ private void readAndValidateParams(Params params) {
+ if (params.mMustFillScreen ) {
+ double totalFactor = 0.0;
+ for (int i = 0; i < params.mNumItems; i++) {
+ if (params.mOverrideItemScreenSizeFactors.containsKey(i)) {
+ totalFactor += params.mOverrideItemScreenSizeFactors.get(i);
+ } else {
+ totalFactor += params.mItemScreenSizeFactor;
+ }
+ }
+ if (totalFactor < 1.0) {
+ throw new IllegalArgumentException("grid items must combine to be at least " +
+ "the height of the screen. this is not the case with " + params.mNumItems
+ + " items and " + params.mItemScreenSizeFactor + " screen factor and " +
+ "screen height of " + mScreenHeight);
+ }
+ }
+
+ mNumItems = params.mNumItems;
+ mStartingSelectionPosition = params.mStartingSelectionPosition;
+ mItemScreenSizeFactor = params.mItemScreenSizeFactor;
+
+ mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors);
+
+ mStackFromBottom = params.mStackFromBottom;
+ mColumnWidth = params.mColumnWidth;
+ mNumColumns = params.mNumColumns;
+ mStretchMode = params.mStretchMode;
+ mVerticalSpacing = params.mVerticalSpacing;
+ }
+
+ public final String getValueAtPosition(int position) {
+ return "postion " + position;
+ }
+
+ /**
+ * Create a view for a grid item. Override this to create a custom view beyond
+ * the simple focusable / unfocusable text view.
+ * @param position The position.
+ * @param parent The parent
+ * @param desiredHeight The height the view should be to respect the desired item
+ * to screen height ratio.
+ * @return a view for the grid.
+ */
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ TextView result = new TextView(parent.getContext());
+ result.setHeight(desiredHeight);
+ result.setText(getValueAtPosition(position));
+ final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ result.setLayoutParams(lp);
+ result.setId(position);
+ result.setBackgroundColor(0x55ffffff);
+ return result;
+ }
+
+
+
+ private class MyAdapter extends BaseAdapter {
+ public int getCount() {
+ return mNumItems;
+ }
+
+ public Object getItem(int position) {
+ return getValueAtPosition(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ if (convertView != null) {
+ ((TextView) convertView).setText(getValueAtPosition(position));
+ convertView.setId(position);
+ return convertView;
+ }
+
+ int desiredHeight = getDesiredItemHeight();
+ if (mOverrideItemScreenSizeFactors.containsKey(position)) {
+ desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position));
+ }
+ return createView(position, parent, desiredHeight);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java b/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java
new file mode 100644
index 0000000..e500b94
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/InternalSelectionView.java
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import com.android.frameworktest.R;
+
+import android.view.View;
+import android.view.KeyEvent;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.Paint;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.Color;
+import android.util.AttributeSet;
+
+
+
+/**
+ * A view that has a known number of selectable rows, and maintains a notion of which
+ * row is selected. The rows take up the
+ * entire width of the view. The height of the view is divided evenly among
+ * the rows.
+ *
+ * Notice what this view does to be a good citizen w.r.t its internal selection:
+ * 1) calls {@link View#requestRectangleOnScreen} each time the selection changes due to
+ * internal navigation.
+ * 2) implements {@link View#getFocusedRect} by filling in the rectangle of the currently
+ * selected row
+ * 3) overrides {@link View#onFocusChanged} and sets selection appropriately according to
+ * the previously focused rectangle.
+ */
+public class InternalSelectionView extends View {
+
+ private Paint mPainter = new Paint();
+ private Paint mTextPaint = new Paint();
+ private Rect mTempRect = new Rect();
+
+ private int mNumRows = 5;
+ private int mSelectedRow = 0;
+ private final int mEstimatedPixelHeight = 10;
+
+ private Integer mDesiredHeight = null;
+ private String mLabel = null;
+
+ public InternalSelectionView(Context context, int numRows, String label) {
+ super(context);
+ mNumRows = numRows;
+ mLabel = label;
+ init();
+ }
+
+ public InternalSelectionView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ TypedArray a =
+ context.obtainStyledAttributes(
+ attrs, R.styleable.SelectableRowView);
+ mNumRows = a.getInt(R.styleable.SelectableRowView_numRows, 5);
+ init();
+ }
+
+ private void init() {
+ setFocusable(true);
+ mTextPaint.setAntiAlias(true);
+ mTextPaint.setTextSize(10);
+ mTextPaint.setColor(Color.WHITE);
+ }
+
+ public int getNumRows() {
+ return mNumRows;
+ }
+
+ public int getSelectedRow() {
+ return mSelectedRow;
+ }
+
+ public void setDesiredHeight(int desiredHeight) {
+ mDesiredHeight = desiredHeight;
+ }
+
+ public String getLabel() {
+ return mLabel;
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ setMeasuredDimension(
+ measureWidth(widthMeasureSpec),
+ measureHeight(heightMeasureSpec));
+ }
+
+ private int measureWidth(int measureSpec) {
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ int desiredWidth = 300 + mPaddingLeft + mPaddingRight;
+ if (specMode == MeasureSpec.EXACTLY) {
+ // We were told how big to be
+ return specSize;
+ } else if (specMode == MeasureSpec.AT_MOST) {
+ return desiredWidth < specSize ? desiredWidth : specSize;
+ } else {
+ return desiredWidth;
+ }
+ }
+
+ private int measureHeight(int measureSpec) {
+ int specMode = MeasureSpec.getMode(measureSpec);
+ int specSize = MeasureSpec.getSize(measureSpec);
+
+ int desiredHeight = mDesiredHeight != null ?
+ mDesiredHeight :
+ mNumRows * mEstimatedPixelHeight + mPaddingTop + mPaddingBottom;
+ if (specMode == MeasureSpec.EXACTLY) {
+ // We were told how big to be
+ return specSize;
+ } else if (specMode == MeasureSpec.AT_MOST) {
+ return desiredHeight < specSize ? desiredHeight : specSize;
+ } else {
+ return desiredHeight;
+ }
+ }
+
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+
+ int rowHeight = getRowHeight();
+
+ int rectTop = mPaddingTop;
+ int rectLeft = mPaddingLeft;
+ int rectRight = getWidth() - mPaddingRight;
+ for (int i = 0; i < mNumRows; i++) {
+
+ mPainter.setColor(Color.BLACK);
+ mPainter.setAlpha(0x20);
+
+ // draw background rect
+ mTempRect.set(rectLeft, rectTop, rectRight, rectTop + rowHeight);
+ canvas.drawRect(mTempRect, mPainter);
+
+ // draw forground rect
+ if (i == mSelectedRow && hasFocus()) {
+ mPainter.setColor(Color.RED);
+ mPainter.setAlpha(0xF0);
+ mTextPaint.setAlpha(0xFF);
+ } else {
+ mPainter.setColor(Color.BLACK);
+ mPainter.setAlpha(0x40);
+ mTextPaint.setAlpha(0xF0);
+ }
+ mTempRect.set(rectLeft + 2, rectTop + 2,
+ rectRight - 2, rectTop + rowHeight - 2);
+ canvas.drawRect(mTempRect, mPainter);
+
+ // draw text to help when visually inspecting
+ canvas.drawText(
+ Integer.toString(i),
+ rectLeft + 2,
+ rectTop + 2 - (int) mTextPaint.ascent(),
+ mTextPaint);
+
+ rectTop += rowHeight;
+ }
+ }
+
+ private int getRowHeight() {
+ return (getHeight() - mPaddingTop - mPaddingBottom) / mNumRows;
+ }
+
+ public void getRectForRow(Rect rect, int row) {
+ final int rowHeight = getRowHeight();
+ final int top = mPaddingTop + row * rowHeight;
+ rect.set(mPaddingLeft,
+ top,
+ getWidth() - mPaddingRight,
+ top + rowHeight);
+ }
+
+
+ void ensureRectVisible() {
+ getRectForRow(mTempRect, mSelectedRow);
+ requestRectangleOnScreen(mTempRect);
+ }
+
+
+ /* (non-Javadoc)
+ * @see android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)
+ */
+ public boolean onKeyDown(int keyCode, KeyEvent event) {
+ switch(event.getKeyCode()) {
+ case KeyEvent.KEYCODE_DPAD_UP:
+ if (mSelectedRow > 0) {
+ mSelectedRow--;
+ invalidate();
+ ensureRectVisible();
+ return true;
+ }
+ break;
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ if (mSelectedRow < (mNumRows - 1)) {
+ mSelectedRow++;
+ invalidate();
+ ensureRectVisible();
+ return true;
+ }
+ break;
+ }
+ return false;
+ }
+
+
+ @Override
+ public void getFocusedRect(Rect r) {
+ getRectForRow(r, mSelectedRow);
+ }
+
+ @Override
+ protected void onFocusChanged(boolean focused, int direction,
+ Rect previouslyFocusedRect) {
+ super.onFocusChanged(focused, direction, previouslyFocusedRect);
+
+ if (focused) {
+ switch (direction) {
+ case View.FOCUS_DOWN:
+ mSelectedRow = 0;
+ break;
+ case View.FOCUS_UP:
+ mSelectedRow = mNumRows - 1;
+ break;
+ case View.FOCUS_LEFT: // fall through
+ case View.FOCUS_RIGHT:
+ // set the row that is closest to the rect
+ if (previouslyFocusedRect != null) {
+ int y = previouslyFocusedRect.top
+ + (previouslyFocusedRect.height() / 2);
+ int yPerRow = getHeight() / mNumRows;
+ mSelectedRow = y / yPerRow;
+ } else {
+ mSelectedRow = 0;
+ }
+ break;
+ default:
+ // can't gleam any useful information about what internal
+ // selection should be...
+ return;
+ }
+ invalidate();
+ }
+ }
+
+ @Override
+ public String toString() {
+ if (mLabel != null) {
+ return mLabel;
+ }
+ return super.toString();
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java b/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java
new file mode 100644
index 0000000..06feab4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/KeyUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.InstrumentationTestCase;
+import android.view.Gravity;
+import android.view.KeyCharacterMap;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+/**
+ * Reusable methods for generating key events.
+ * <p>
+ * Definitions:
+ * <li> Tap refers to pushing and releasing a button (down and up event).
+ * <li> Chord refers to pushing a modifier key, tapping a regular key, and
+ * releasing the modifier key.
+ */
+public class KeyUtils {
+ /**
+ * Simulates tapping the menu key.
+ *
+ * @param test The test case that is being run.
+ */
+ public static void tapMenuKey(ActivityInstrumentationTestCase test) {
+ final Instrumentation inst = test.getInstrumentation();
+
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU));
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU));
+ }
+
+ /**
+ * Simulates chording the menu key.
+ *
+ * @param test The test case that is being run.
+ * @param shortcutKey The shortcut key to tap while chording the menu key.
+ */
+ public static void chordMenuKey(ActivityInstrumentationTestCase test, char shortcutKey) {
+ final Instrumentation inst = test.getInstrumentation();
+
+ final KeyEvent pushMenuKey = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_MENU);
+ final KeyCharacterMap keyCharMap = KeyCharacterMap.load(pushMenuKey.getDeviceId());
+ final KeyEvent shortcutKeyEvent = keyCharMap.getEvents(new char[] { shortcutKey })[0];
+ final int shortcutKeyCode = shortcutKeyEvent.getKeyCode();
+
+ inst.sendKeySync(pushMenuKey);
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, shortcutKeyCode));
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, shortcutKeyCode));
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_MENU));
+ }
+
+ /**
+ * Simulates a long click via the keyboard.
+ *
+ * @param test The test case that is being run.
+ */
+ public static void longClick(ActivityInstrumentationTestCase test) {
+ final Instrumentation inst = test.getInstrumentation();
+
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_DPAD_CENTER));
+ try {
+ Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.5f));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ inst.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_DPAD_CENTER));
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java
new file mode 100644
index 0000000..4327a8a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListItemFactory.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import android.content.Context;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.AbsListView;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Reusable methods for creating more complex list items.
+ */
+public class ListItemFactory {
+
+ /**
+ * Create a view with a button at the top and bottom, with filler in between.
+ * The filler is sized to take up any space left over within desiredHeight.
+ *
+ * @param position The position within the list.
+ * @param context The context.
+ * @param desiredHeight The desired height of the entire view.
+ * @return The created view.
+ */
+ public static View twoButtonsSeparatedByFiller(int position, Context context, int desiredHeight) {
+ if (desiredHeight < 90) {
+ throw new IllegalArgumentException("need at least 90 pixels of height " +
+ "to create the two buttons and leave 10 pixels for the filler");
+ }
+
+ final LinearLayout ll = new LinearLayout(context);
+ ll.setOrientation(LinearLayout.VERTICAL);
+
+ final LinearLayout.LayoutParams buttonLp =
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 50);
+
+ final Button topButton = new Button(context);
+ topButton.setLayoutParams(
+ buttonLp);
+ topButton.setText("top (position " + position + ")");
+ ll.addView(topButton);
+
+ final TextView middleFiller = new TextView(context);
+ middleFiller.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ desiredHeight - 100));
+ middleFiller.setText("filler");
+ ll.addView(middleFiller);
+
+ final Button bottomButton = new Button(context);
+ bottomButton.setLayoutParams(buttonLp);
+ bottomButton.setText("bottom (position " + position + ")");
+ ll.addView(bottomButton);
+ ll.setTag("twoButtons");
+ return ll;
+ }
+
+ public enum Slot {
+ Left,
+ Middle,
+ Right
+ }
+
+ /**
+ * Create a horizontal linear layout divided into thirds (with some margins
+ * separating the thirds), filled with buttons into some slots.
+ * @param context The context.
+ * @param desiredHeight The height of the LL.
+ * @param slots Which slots to fill with buttons.
+ * @return The linear layout.
+ */
+ public static View horizontalButtonSlots(Context context, int desiredHeight, Slot... slots) {
+
+ final LinearLayout ll = new LinearLayout(context);
+ ll.setOrientation(LinearLayout.HORIZONTAL);
+
+ final LinearLayout.LayoutParams lp
+ = new LinearLayout.LayoutParams(0, desiredHeight);
+ lp.setMargins(10, 0, 10, 0);
+ lp.weight = 0.33f;
+
+ boolean left = false;
+ boolean middle = false;
+ boolean right = false;
+ for (Slot slot : slots) {
+ switch (slot) {
+ case Left:
+ left = true;
+ break;
+ case Middle:
+ middle = true;
+ break;
+ case Right:
+ right = true;
+ break;
+ }
+ }
+
+ if (left) {
+ final Button button = new Button(context);
+ button.setText("left");
+ ll.addView(button, lp);
+ } else {
+ ll.addView(new View(context), lp);
+ }
+
+ if (middle) {
+ final Button button = new Button(context);
+ button.setText("center");
+ ll.addView(button, lp);
+ } else {
+ ll.addView(new View(context), lp);
+ }
+
+ if (right) {
+ final Button button = new Button(context);
+ button.setText("right");
+ ll.addView(button, lp);
+ } else {
+ ll.addView(new View(context), lp);
+ }
+
+ return ll;
+ }
+
+
+ /**
+ * Create a button ready to be a list item.
+ *
+ * @param position The position within the list.
+ * @param context The context.
+ * @param text The text of the button
+ * @param desiredHeight The desired height of the button
+ * @return The created view.
+ */
+ public static View button(int position, Context context, String text, int desiredHeight) {
+ TextView result = new Button(context);
+ result.setHeight(desiredHeight);
+ result.setText(text);
+ final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ result.setLayoutParams(lp);
+ result.setId(position);
+ result.setTag("button");
+ return result;
+ }
+
+ /**
+ * Convert an existing button view to display the data at a new position.
+ *
+ * @param convertView Non-null Button created by {@link #button}
+ * @param text The text of the button
+ * @param position The position withion the list
+ * @return The converted view
+ */
+ public static View convertButton(View convertView, String text, int position) {
+ if (((String) convertView.getTag()).equals("button")) {
+ ((Button) convertView).setText(text);
+ convertView.setId(position);
+ return convertView;
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Create a text view ready to be a list item.
+ *
+ * @param position The position within the list.
+ * @param context The context.
+ * @param text The text to display
+ * @param desiredHeight The desired height of the text view
+ * @return The created view.
+ */
+ public static View text(int position, Context context, String text, int desiredHeight) {
+ TextView result = new TextView(context);
+ result.setHeight(desiredHeight);
+ result.setText(text);
+ final ViewGroup.LayoutParams lp = new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT);
+ result.setLayoutParams(lp);
+ result.setId(position);
+ result.setTag("text");
+ return result;
+ }
+
+ /**
+ * Convert an existing text view to display the data at a new position.
+ *
+ * @param convertView Non-null TextView created by {@link #text}
+ * @param text The text to display
+ * @param position The position withion the list
+ * @return The converted view
+ */
+ public static View convertText(View convertView, String text, int position) {
+ if(convertView.getTag() != null && ((String) convertView.getTag()).equals("text")) {
+ ((TextView) convertView).setText(text);
+ convertView.setId(position);
+ return convertView;
+
+ } else {
+ return null;
+ }
+ }
+
+ /**
+ * Create a text view ready to be a list item.
+ *
+ * @param position The position within the list.
+ * @param context The context.
+ * @param text The text of the button
+ * @param desiredHeight The desired height of the button
+ * @return The created view.
+ */
+ public static View doubleText(int position, Context context, String text, int desiredHeight) {
+ final LinearLayout ll = new LinearLayout(context);
+ ll.setOrientation(LinearLayout.HORIZONTAL);
+
+ final AbsListView.LayoutParams lp =
+ new AbsListView.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ desiredHeight);
+ ll.setLayoutParams(lp);
+ ll.setId(position);
+
+ TextView t1 = new TextView(context);
+ t1.setHeight(desiredHeight);
+ t1.setText(text);
+ t1.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
+ final ViewGroup.LayoutParams lp1 = new LinearLayout.LayoutParams(
+ 0,
+ ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f);
+ ll.addView(t1, lp1);
+
+ TextView t2 = new TextView(context);
+ t2.setHeight(desiredHeight);
+ t2.setText(text);
+ t2.setGravity(Gravity.RIGHT | Gravity.CENTER_VERTICAL);
+ final ViewGroup.LayoutParams lp2 = new LinearLayout.LayoutParams(
+ 0,
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ 1.0f);
+
+ ll.addView(t2, lp2);
+ ll.setTag("double");
+ return ll;
+ }
+
+
+ /**
+ * Convert an existing button view to display the data at a new position.
+ *
+ * @param convertView Non-null view created by {@link #doubleText}
+ * @param text The text of the button
+ * @param position The position withion the list
+ * @return The converted view
+ */
+ public static View convertDoubleText(View convertView, String text, int position) {
+ if (((String) convertView.getTag()).equals("double")) {
+ TextView t1 = (TextView) ((LinearLayout) convertView).getChildAt(0);
+ TextView t2 = (TextView) ((LinearLayout) convertView).getChildAt(1);
+ t1.setText(text);
+ t2.setText(text);
+ convertView.setId(position);
+ return convertView;
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java
new file mode 100644
index 0000000..5889658
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListScenario.java
@@ -0,0 +1,662 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.google.android.collect.Maps;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Utility base class for creating various List scenarios. Configurable by the number
+ * of items, how tall each item should be (in relation to the screen height), and
+ * what item should start with selection.
+ */
+public abstract class ListScenario extends Activity {
+
+ private ListView mListView;
+ private TextView mHeaderTextView;
+
+ private int mNumItems;
+ protected boolean mItemsFocusable;
+
+ private int mStartingSelectionPosition;
+ private double mItemScreenSizeFactor;
+ private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+ private int mScreenHeight;
+
+ // whether to include a text view above the list
+ private boolean mIncludeHeader;
+
+ // separators
+ private Set<Integer> mUnselectableItems = new HashSet<Integer>();
+
+ private boolean mStackFromBottom;
+
+ private int mClickedPosition = -1;
+
+ private int mLongClickedPosition = -1;
+
+ private int mConvertMisses = 0;
+
+ private int mHeaderViewCount;
+ private boolean mHeadersFocusable;
+
+ private int mFooterViewCount;
+ private LinearLayout mLinearLayout;
+
+ public ListView getListView() {
+ return mListView;
+ }
+
+ protected int getScreenHeight() {
+ return mScreenHeight;
+ }
+
+ /**
+ * Return whether the item at position is selectable (i.e is a separator).
+ * (external users can access this info using the adapter)
+ */
+ private boolean isItemAtPositionSelectable(int position) {
+ return !mUnselectableItems.contains(position);
+ }
+
+ /**
+ * Better way to pass in optional params than a honkin' paramater list :)
+ */
+ public static class Params {
+ private int mNumItems = 4;
+ private boolean mItemsFocusable = false;
+ private int mStartingSelectionPosition = 0;
+ private double mItemScreenSizeFactor = 1 / 5;
+ private Double mFadingEdgeScreenSizeFactor = null;
+
+ private Map<Integer, Double> mOverrideItemScreenSizeFactors = Maps.newHashMap();
+
+ // separators
+ private List<Integer> mUnselectableItems = new ArrayList<Integer>(8);
+ // whether to include a text view above the list
+ private boolean mIncludeHeader = false;
+ private boolean mStackFromBottom = false;
+ public boolean mMustFillScreen = true;
+ private int mHeaderViewCount;
+ private boolean mHeaderFocusable = false;
+ private int mFooterViewCount;
+
+ private boolean mConnectAdapter = true;
+
+ /**
+ * Set the number of items in the list.
+ */
+ public Params setNumItems(int numItems) {
+ mNumItems = numItems;
+ return this;
+ }
+
+ /**
+ * Set whether the items are focusable.
+ */
+ public Params setItemsFocusable(boolean itemsFocusable) {
+ mItemsFocusable = itemsFocusable;
+ return this;
+ }
+
+ /**
+ * Set the position that starts selected.
+ *
+ * @param startingSelectionPosition The selected position within the adapter's data set.
+ * Pass -1 if you do not want to force a selection.
+ * @return
+ */
+ public Params setStartingSelectionPosition(int startingSelectionPosition) {
+ mStartingSelectionPosition = startingSelectionPosition;
+ return this;
+ }
+
+ /**
+ * Set the factor that determines how tall each item is in relation to the
+ * screen height.
+ */
+ public Params setItemScreenSizeFactor(double itemScreenSizeFactor) {
+ mItemScreenSizeFactor = itemScreenSizeFactor;
+ return this;
+ }
+
+ /**
+ * Override the item screen size factor for a particular item. Useful for
+ * creating lists with non-uniform item height.
+ * @param position The position in the list.
+ * @param itemScreenSizeFactor The screen size factor to use for the height.
+ */
+ public Params setPositionScreenSizeFactorOverride(
+ int position, double itemScreenSizeFactor) {
+ mOverrideItemScreenSizeFactors.put(position, itemScreenSizeFactor);
+ return this;
+ }
+
+ /**
+ * Set a position as unselectable (a.k.a a separator)
+ * @param position
+ * @return
+ */
+ public Params setPositionUnselectable(int position) {
+ mUnselectableItems.add(position);
+ return this;
+ }
+
+ /**
+ * Set positions as unselectable (a.k.a a separator)
+ */
+ public Params setPositionsUnselectable(int ...positions) {
+ for (int pos : positions) {
+ setPositionUnselectable(pos);
+ }
+ return this;
+ }
+
+ /**
+ * Include a header text view above the list.
+ * @param includeHeader
+ * @return
+ */
+ public Params includeHeaderAboveList(boolean includeHeader) {
+ mIncludeHeader = includeHeader;
+ return this;
+ }
+
+ /**
+ * Sets the stacking direction
+ * @param stackFromBottom
+ * @return
+ */
+ public Params setStackFromBottom(boolean stackFromBottom) {
+ mStackFromBottom = stackFromBottom;
+ return this;
+ }
+
+ /**
+ * Sets whether the sum of the height of the list items must be at least the
+ * height of the list view.
+ */
+ public Params setMustFillScreen(boolean fillScreen) {
+ mMustFillScreen = fillScreen;
+ return this;
+ }
+
+ /**
+ * Set the factor for the fading edge length.
+ */
+ public Params setFadingEdgeScreenSizeFactor(double fadingEdgeScreenSizeFactor) {
+ mFadingEdgeScreenSizeFactor = fadingEdgeScreenSizeFactor;
+ return this;
+ }
+
+ /**
+ * Set the number of header views to appear within the list
+ */
+ public Params setHeaderViewCount(int headerViewCount) {
+ mHeaderViewCount = headerViewCount;
+ return this;
+ }
+
+ /**
+ * Set whether the headers should be focusable.
+ * @param headerFocusable Whether the headers should be focusable (i.e
+ * created as edit texts rather than text views).
+ */
+ public Params setHeaderFocusable(boolean headerFocusable) {
+ mHeaderFocusable = headerFocusable;
+ return this;
+ }
+
+ /**
+ * Set the number of footer views to appear within the list
+ */
+ public Params setFooterViewCount(int footerViewCount) {
+ mFooterViewCount = footerViewCount;
+ return this;
+ }
+
+ /**
+ * Sets whether the {@link ListScenario} will automatically set the
+ * adapter on the list view. If this is false, the client MUST set it
+ * manually (this is useful when adding headers to the list view, which
+ * must be done before the adapter is set).
+ */
+ public Params setConnectAdapter(boolean connectAdapter) {
+ mConnectAdapter = connectAdapter;
+ return this;
+ }
+ }
+
+ /**
+ * How each scenario customizes its behavior.
+ * @param params
+ */
+ protected abstract void init(Params params);
+
+ /**
+ * Override this if you want to know when something has been selected (perhaps
+ * more importantly, that {@link android.widget.AdapterView.OnItemSelectedListener} has
+ * been triggered).
+ */
+ protected void positionSelected(int positon) {
+ }
+
+ /**
+ * Override this if you want to know that nothing is selected.
+ */
+ protected void nothingSelected() {
+ }
+
+ /**
+ * Override this if you want to know when something has been clicked (perhaps
+ * more importantly, that {@link android.widget.AdapterView.OnItemClickListener} has
+ * been triggered).
+ */
+ protected void positionClicked(int position) {
+ setClickedPosition(position);
+ }
+
+ /**
+ * Override this if you want to know when something has been long clicked (perhaps
+ * more importantly, that {@link android.widget.AdapterView.OnItemLongClickListener} has
+ * been triggered).
+ */
+ protected void positionLongClicked(int position) {
+ setLongClickedPosition(position);
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ // for test stability, turn off title bar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+
+ mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+
+ final Params params = createParams();
+ init(params);
+
+ readAndValidateParams(params);
+
+
+ mListView = createListView();
+ mListView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mListView.setDrawSelectorOnTop(false);
+
+ for (int i=0; i<mHeaderViewCount; i++) {
+ TextView header = mHeadersFocusable ?
+ new EditText(this) :
+ new TextView(this);
+ header.setText("Header: " + i);
+ mListView.addHeaderView(header);
+ }
+
+ for (int i=0; i<mFooterViewCount; i++) {
+ TextView header = new TextView(this);
+ header.setText("Footer: " + i);
+ mListView.addFooterView(header);
+ }
+
+ if (params.mConnectAdapter) {
+ setAdapter(mListView);
+ }
+
+ mListView.setItemsCanFocus(mItemsFocusable);
+ if (mStartingSelectionPosition >= 0) {
+ mListView.setSelection(mStartingSelectionPosition);
+ }
+ mListView.setPadding(0, 0, 0, 0);
+ mListView.setStackFromBottom(mStackFromBottom);
+ mListView.setDivider(null);
+
+ mListView.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
+ public void onItemSelected(AdapterView parent, View v, int position, long id) {
+ positionSelected(position);
+ }
+
+ public void onNothingSelected(AdapterView parent) {
+ nothingSelected();
+ }
+ });
+
+ mListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
+ public void onItemClick(AdapterView parent, View v, int position, long id) {
+ positionClicked(position);
+ }
+ });
+
+ // set the fading edge length porportionally to the screen
+ // height for test stability
+ if (params.mFadingEdgeScreenSizeFactor != null) {
+ mListView.setFadingEdgeLength((int) (params.mFadingEdgeScreenSizeFactor * mScreenHeight));
+ } else {
+ mListView.setFadingEdgeLength((int) ((64.0 / 480) * mScreenHeight));
+ }
+
+ if (mIncludeHeader) {
+ mLinearLayout = new LinearLayout(this);
+
+ mHeaderTextView = new TextView(this);
+ mHeaderTextView.setText("hi");
+ mHeaderTextView.setLayoutParams(new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT));
+ mLinearLayout.addView(mHeaderTextView);
+
+ mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+ mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mListView.setLayoutParams((new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 0,
+ 1f)));
+
+ mLinearLayout.addView(mListView);
+ setContentView(mLinearLayout);
+ } else {
+ mLinearLayout = new LinearLayout(this);
+ mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+ mLinearLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+ mListView.setLayoutParams((new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ 0,
+ 1f)));
+ mLinearLayout.addView(mListView);
+ setContentView(mLinearLayout);
+ }
+ }
+
+ /**
+ * Returns the LinearLayout containing the ListView in this scenario.
+ *
+ * @return The LinearLayout in which the ListView is held.
+ */
+ protected LinearLayout getListViewContainer() {
+ return mLinearLayout;
+ }
+
+ /**
+ * Attaches a long press listener. You can find out which views were clicked by calling
+ * {@link #getLongClickedPosition()}.
+ */
+ public void enableLongPress() {
+ mListView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
+ public boolean onItemLongClick(AdapterView parent, View v, int position, long id) {
+ positionLongClicked(position);
+ return true;
+ }
+ });
+ }
+
+ /**
+ * @return The newly created ListView widget.
+ */
+ protected ListView createListView() {
+ return new ListView(this);
+ }
+
+ /**
+ * @return The newly created Params object.
+ */
+ protected Params createParams() {
+ return new Params();
+ }
+
+ /**
+ * Sets an adapter on a ListView.
+ *
+ * @param listView The ListView to set the adapter on.
+ */
+ protected void setAdapter(ListView listView) {
+ listView.setAdapter(new MyAdapter());
+ }
+
+ /**
+ * Read in and validate all of the params passed in by the scenario.
+ * @param params
+ */
+ protected void readAndValidateParams(Params params) {
+ if (params.mMustFillScreen ) {
+ double totalFactor = 0.0;
+ for (int i = 0; i < params.mNumItems; i++) {
+ if (params.mOverrideItemScreenSizeFactors.containsKey(i)) {
+ totalFactor += params.mOverrideItemScreenSizeFactors.get(i);
+ } else {
+ totalFactor += params.mItemScreenSizeFactor;
+ }
+ }
+ if (totalFactor < 1.0) {
+ throw new IllegalArgumentException("list items must combine to be at least " +
+ "the height of the screen. this is not the case with " + params.mNumItems
+ + " items and " + params.mItemScreenSizeFactor + " screen factor and " +
+ "screen height of " + mScreenHeight);
+ }
+ }
+
+ mNumItems = params.mNumItems;
+ mItemsFocusable = params.mItemsFocusable;
+ mStartingSelectionPosition = params.mStartingSelectionPosition;
+ mItemScreenSizeFactor = params.mItemScreenSizeFactor;
+
+ mOverrideItemScreenSizeFactors.putAll(params.mOverrideItemScreenSizeFactors);
+
+ mUnselectableItems.addAll(params.mUnselectableItems);
+ mIncludeHeader = params.mIncludeHeader;
+ mStackFromBottom = params.mStackFromBottom;
+ mHeaderViewCount = params.mHeaderViewCount;
+ mHeadersFocusable = params.mHeaderFocusable;
+ mFooterViewCount = params.mFooterViewCount;
+ }
+
+ public final String getValueAtPosition(int position) {
+ return isItemAtPositionSelectable(position)
+ ?
+ "position " + position:
+ "------- " + position;
+ }
+
+ /**
+ * @return The height that will be set for a particular position.
+ */
+ public int getHeightForPosition(int position) {
+ int desiredHeight = (int) (mScreenHeight * mItemScreenSizeFactor);
+ if (mOverrideItemScreenSizeFactors.containsKey(position)) {
+ desiredHeight = (int) (mScreenHeight * mOverrideItemScreenSizeFactors.get(position));
+ }
+ return desiredHeight;
+ }
+
+
+ /**
+ * @return The contents of the header above the list.
+ * @throws IllegalArgumentException if there is no header.
+ */
+ public final String getHeaderValue() {
+ if (!mIncludeHeader) {
+ throw new IllegalArgumentException("no header above list");
+ }
+ return mHeaderTextView.getText().toString();
+ }
+
+ /**
+ * @param value What to put in the header text view
+ * @throws IllegalArgumentException if there is no header.
+ */
+ protected final void setHeaderValue(String value) {
+ if (!mIncludeHeader) {
+ throw new IllegalArgumentException("no header above list");
+ }
+ mHeaderTextView.setText(value);
+ }
+
+ /**
+ * Create a view for a list item. Override this to create a custom view beyond
+ * the simple focusable / unfocusable text view.
+ * @param position The position.
+ * @param parent The parent
+ * @param desiredHeight The height the view should be to respect the desired item
+ * to screen height ratio.
+ * @return a view for the list.
+ */
+ protected View createView(int position, ViewGroup parent, int desiredHeight) {
+ return ListItemFactory.text(position, parent.getContext(), getValueAtPosition(position),
+ desiredHeight);
+ }
+
+ /**
+ * Convert a non-null view.
+ */
+ public View convertView(int position, View convertView, ViewGroup parent) {
+ return ListItemFactory.convertText(convertView, getValueAtPosition(position), position);
+ }
+
+ public void setClickedPosition(int clickedPosition) {
+ mClickedPosition = clickedPosition;
+ }
+
+ public int getClickedPosition() {
+ return mClickedPosition;
+ }
+
+ public void setLongClickedPosition(int longClickedPosition) {
+ mLongClickedPosition = longClickedPosition;
+ }
+
+ public int getLongClickedPosition() {
+ return mLongClickedPosition;
+ }
+
+ /**
+ * Have a child of the list view call {@link View#requestRectangleOnScreen(android.graphics.Rect)}.
+ * @param childIndex The index into the viewgroup children (i.e the children that are
+ * currently visible).
+ * @param rect The rectangle, in the child's coordinates.
+ */
+ public void requestRectangleOnScreen(int childIndex, final Rect rect) {
+ final View child = getListView().getChildAt(childIndex);
+
+ child.post(new Runnable() {
+ public void run() {
+ child.requestRectangleOnScreen(rect);
+ }
+ });
+ }
+
+ /**
+ * Return an item type for the specified position in the adapter. Override if your
+ * adapter creates more than one type.
+ */
+ public int getItemViewType(int position) {
+ return 0;
+ }
+
+ /**
+ * Return an the number of types created by the adapter. Override if your
+ * adapter creates more than one type.
+ */
+ public int getViewTypeCount() {
+ return 1;
+ }
+
+ /**
+ * @return The number of times convertView failed
+ */
+ public int getConvertMisses() {
+ return mConvertMisses;
+ }
+
+ private class MyAdapter extends BaseAdapter {
+
+ public int getCount() {
+ return mNumItems;
+ }
+
+ public Object getItem(int position) {
+ return getValueAtPosition(position);
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ @Override
+ public boolean areAllItemsEnabled() {
+ return mUnselectableItems.isEmpty();
+ }
+
+ @Override
+ public boolean isEnabled(int position) {
+ return isItemAtPositionSelectable(position);
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ View result = null;
+ if (position >= mNumItems || position < 0) {
+ throw new IllegalStateException("position out of range for adapter!");
+ }
+
+ if (convertView != null) {
+ result = convertView(position, convertView, parent);
+ if (result == null) {
+ mConvertMisses++;
+ }
+ }
+
+ if (result == null) {
+ int desiredHeight = getHeightForPosition(position);
+ result = createView(position, parent, desiredHeight);
+ }
+ return result;
+ }
+
+ @Override
+ public int getItemViewType(int position) {
+ return ListScenario.this.getItemViewType(position);
+ }
+
+ @Override
+ public int getViewTypeCount() {
+ return ListScenario.this.getViewTypeCount();
+ }
+
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java
new file mode 100644
index 0000000..1a05fac
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ListUtil.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import android.app.Instrumentation;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+
+/**
+ * Various useful stuff for instrumentation testing listview.
+ */
+public class ListUtil {
+
+
+ private final ListView mListView;
+ private final Instrumentation mInstrumentation;
+
+ /**
+ * @param listView The listview to act on
+ * @param instrumentation The instrumentation to use.
+ */
+ public ListUtil(ListView listView, Instrumentation instrumentation) {
+ mListView = listView;
+ mInstrumentation = instrumentation;
+ }
+
+ /**
+ * Set the selected position of the list view.
+ * @param pos The desired position.
+ */
+ public final void setSelectedPosition(final int pos) {
+ mListView.post(new Runnable() {
+ public void run() {
+ mListView.setSelection(pos);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ }
+
+ /**
+ * Get the top of the list.
+ */
+ public final int getListTop() {
+ return mListView.getListPaddingTop();
+ }
+
+ /**
+ * Get the bottom of the list.
+ */
+ public final int getListBottom() {
+ return mListView.getHeight() - mListView.getListPaddingBottom();
+ }
+
+ /**
+ * Arrow (up or down as appropriate) to the desired position in the list.
+ * @param desiredPos The desired position
+ * @throws IllegalStateException if the position can't be reached within 20 presses.
+ */
+ public final void arrowScrollToSelectedPosition(int desiredPos) {
+ if (desiredPos > mListView.getSelectedItemPosition()) {
+ arrowDownToSelectedPosition(desiredPos);
+ } else {
+ arrowUpToSelectedPosition(desiredPos);
+ }
+ }
+
+ private void arrowDownToSelectedPosition(int position) {
+ int maxDowns = 20;
+ while(mListView.getSelectedItemPosition() < position && --maxDowns > 0) {
+ mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ if (position != mListView.getSelectedItemPosition()) {
+ throw new IllegalStateException("couldn't get to item after 20 downs");
+ }
+
+ }
+
+ private void arrowUpToSelectedPosition(int position) {
+ int maxUps = 20;
+ while(mListView.getSelectedItemPosition() > position && --maxUps > 0) {
+ mInstrumentation.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ if (position != mListView.getSelectedItemPosition()) {
+ throw new IllegalStateException("couldn't get to item after 20 ups");
+ }
+ }
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java b/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java
new file mode 100644
index 0000000..aa17194
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/ScrollViewScenario.java
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import com.google.android.collect.Lists;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import java.util.List;
+
+/**
+ * Utility base class for creating scroll view scenarios, allowing you to add
+ * a series of different kinds of views arranged vertically, taking up a
+ * specified amount of the screen height.
+ */
+public abstract class ScrollViewScenario extends Activity {
+
+ /**
+ * Holds content of scroll view
+ */
+ private LinearLayout mLinearLayout;
+
+ /**
+ * The actual scroll view
+ */
+ private ScrollView mScrollView;
+
+
+ /**
+ * What we need of each view that the user wants: the view, and the ratio
+ * to the screen height for its desired height.
+ */
+ private interface ViewFactory {
+ View create(final Context context);
+
+ float getHeightRatio();
+ }
+
+ /**
+ * Partially implement ViewFactory given a height ratio.
+ */
+ private static abstract class ViewFactoryBase implements ViewFactory {
+
+ private float mHeightRatio;
+
+ @SuppressWarnings({"UnusedDeclaration"})
+ private ViewFactoryBase() {throw new UnsupportedOperationException("don't call this!");}
+
+ protected ViewFactoryBase(float heightRatio) {
+ mHeightRatio = heightRatio;
+ }
+
+ public float getHeightRatio() {
+ return mHeightRatio;
+ }
+ }
+
+ /**
+ * Builder for selecting the views to be vertically arranged in the scroll
+ * view.
+ */
+ @SuppressWarnings({"JavaDoc"})
+ public static class Params {
+
+ List<ViewFactory> mViewFactories = Lists.newArrayList();
+
+ /**
+ * Add a text view.
+ * @param text The text of the text view.
+ * @param heightRatio The view's height will be this * the screen height.
+ */
+ public Params addTextView(final String text, float heightRatio) {
+ mViewFactories.add(new ViewFactoryBase(heightRatio) {
+ public View create(final Context context) {
+ final TextView tv = new TextView(context);
+ tv.setText(text);
+ return tv;
+ }
+ });
+ return this;
+ }
+
+ /**
+ * Add multiple text views.
+ * @param numViews the number of views to add.
+ * @param textPrefix The text to prepend to each text view.
+ * @param heightRatio The view's height will be this * the screen height.
+ */
+ public Params addTextViews(int numViews, String textPrefix, float heightRatio) {
+ for (int i = 0; i < numViews; i++) {
+ addTextView(textPrefix + i, heightRatio);
+ }
+ return this;
+ }
+
+ /**
+ * Add a button.
+ * @param text The text of the button.
+ * @param heightRatio The view's height will be this * the screen height.
+ */
+ public Params addButton(final String text, float heightRatio) {
+ mViewFactories.add(new ViewFactoryBase(heightRatio) {
+ public View create(final Context context) {
+ final Button button = new Button(context);
+ button.setText(text);
+ return button;
+ }
+ });
+ return this;
+ }
+
+ /**
+ * Add multiple buttons.
+ * @param numButtons the number of views to add.
+ * @param textPrefix The text to prepend to each button.
+ * @param heightRatio The view's height will be this * the screen height.
+ */
+ public Params addButtons(int numButtons, String textPrefix, float heightRatio) {
+ for (int i = 0; i < numButtons; i++) {
+ addButton(textPrefix + i, heightRatio);
+ }
+ return this;
+ }
+
+ /**
+ * Add an {@link InternalSelectionView}.
+ * @param numRows The number of rows in the internal selection view.
+ * @param heightRatio The view's height will be this * the screen height.
+ */
+ public Params addInternalSelectionView(final int numRows, float heightRatio) {
+ mViewFactories.add(new ViewFactoryBase(heightRatio) {
+ public View create(final Context context) {
+ return new InternalSelectionView(context, numRows, "isv");
+ }
+ });
+ return this;
+ }
+
+ /**
+ * Add a sublayout of buttons as a single child of the scroll view.
+ * @param numButtons The number of buttons in the sub layout
+ * @param heightRatio The layout's height will be this * the screen height.
+ */
+ public Params addVerticalLLOfButtons(final String prefix, final int numButtons, float heightRatio) {
+ mViewFactories.add(new ViewFactoryBase(heightRatio) {
+
+ public View create(Context context) {
+ final LinearLayout ll = new LinearLayout(context);
+ ll.setOrientation(LinearLayout.VERTICAL);
+
+ // fill width, equally weighted on height
+ final LinearLayout.LayoutParams lp =
+ new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, 0, 1f);
+ for (int i = 0; i < numButtons; i++) {
+ final Button button = new Button(context);
+ button.setText(prefix + i);
+ ll.addView(button, lp);
+ }
+
+ return ll;
+ }
+ });
+ return this;
+ }
+ }
+
+ /**
+ * Override this and initialized the views in the scroll view.
+ * @param params Used to configure the contents of the scroll view.
+ */
+ protected abstract void init(Params params);
+
+ public LinearLayout getLinearLayout() {
+ return mLinearLayout;
+ }
+
+ public ScrollView getScrollView() {
+ return mScrollView;
+ }
+
+ /**
+ * Get the child contained within the vertical linear layout of the
+ * scroll view.
+ * @param index The index within the linear layout.
+ * @return the child within the vertical linear layout of the scroll view
+ * at the specified index.
+ */
+ @SuppressWarnings({"unchecked"})
+ public <T extends View> T getContentChildAt(int index) {
+ return (T) mLinearLayout.getChildAt(index);
+ }
+
+ /**
+ * Hook for changing how scroll view's are created.
+ */
+ @SuppressWarnings({"JavaDoc"})
+ protected ScrollView createScrollView() {
+ return new ScrollView(this);
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // for test stability, turn off title bar
+ requestWindowFeature(Window.FEATURE_NO_TITLE);
+ int screenHeight = getWindowManager().getDefaultDisplay().getHeight()
+ - 25;
+ mLinearLayout = new LinearLayout(this);
+ mLinearLayout.setOrientation(LinearLayout.VERTICAL);
+
+ // initialize params
+ final Params params = new Params();
+ init(params);
+
+ // create views specified by params
+ for (ViewFactory viewFactory : params.mViewFactories) {
+ final LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ (int) (viewFactory.getHeightRatio() * screenHeight));
+ mLinearLayout.addView(viewFactory.create(this), lp);
+ }
+
+ mScrollView = createScrollView();
+ mScrollView.addView(mLinearLayout, new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ // no animation to speed up tests
+ mScrollView.setSmoothScrollingEnabled(false);
+
+ setContentView(mScrollView);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java b/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java
new file mode 100644
index 0000000..66adb17
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/util/TouchModeFlexibleAsserts.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.util;
+
+import junit.framework.Assert;
+
+import android.test.InstrumentationTestCase;
+import android.test.TouchUtils;
+import android.view.View;
+
+/**
+ * When entering touch mode via touch, the tests can be flaky. These asserts
+ * are more flexible (allowing up to MAX_ATTEMPTS touches to enter touch mode via touch or
+ * tap) until we can find a way to solve the flakiness.
+ */
+public class TouchModeFlexibleAsserts {
+
+ private static int MAX_ATTEMPTS = 2;
+
+ private static int MAX_DELAY_MILLIS = 2000;
+
+ public static void assertInTouchModeAfterClick(InstrumentationTestCase test, View viewToTouch) {
+ int numAttemptsAtTouchMode = 0;
+ while (numAttemptsAtTouchMode < MAX_ATTEMPTS &&
+ !viewToTouch.isInTouchMode()) {
+ TouchUtils.clickView(test, viewToTouch);
+ numAttemptsAtTouchMode++;
+ }
+ Assert.assertTrue("even after " + MAX_ATTEMPTS + " clicks, did not enter "
+ + "touch mode", viewToTouch.isInTouchMode());
+ //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode);
+ }
+
+ public static void assertInTouchModeAfterTap(InstrumentationTestCase test, View viewToTouch) {
+ int numAttemptsAtTouchMode = 0;
+ while (numAttemptsAtTouchMode < MAX_ATTEMPTS &&
+ !viewToTouch.isInTouchMode()) {
+ TouchUtils.tapView(test, viewToTouch);
+ numAttemptsAtTouchMode++;
+ }
+ Assert.assertTrue("even after " + MAX_ATTEMPTS + " taps, did not enter "
+ + "touch mode", viewToTouch.isInTouchMode());
+ //Assert.assertEquals("number of touches to enter touch mode", 1, numAttemptsAtTouchMode);
+ }
+
+ public static void assertNotInTouchModeAfterKey(InstrumentationTestCase test, int keyCode, View checkForTouchMode) {
+ test.sendKeys(keyCode);
+ int amountLeft = MAX_DELAY_MILLIS;
+
+ while (checkForTouchMode.isInTouchMode() && amountLeft > 0) {
+ amountLeft -= 200;
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ Assert.assertFalse("even after waiting " + MAX_DELAY_MILLIS + " millis after "
+ + "pressing key event, still in touch mode", checkForTouchMode.isInTouchMode());
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java b/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java
new file mode 100644
index 0000000..6f5eb00
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/BigCache.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.view.ViewGroup;
+import android.view.View;
+import android.view.Display;
+import android.view.ViewConfiguration;
+
+/**
+ * This activity contains two Views, one as big as the screen, one much larger. The large one
+ * should not be able to activate its drawing cache.
+ */
+public class BigCache extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ final LinearLayout testBed = new LinearLayout(this);
+ testBed.setOrientation(LinearLayout.VERTICAL);
+ testBed.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
+
+ final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize();
+ final Display display = getWindowManager().getDefaultDisplay();
+ final int screenWidth = display.getWidth();
+ final int screenHeight = display.getHeight();
+
+ final View tiny = new View(this);
+ tiny.setId(R.id.a);
+ tiny.setBackgroundColor(0xFFFF0000);
+ tiny.setLayoutParams(new LinearLayout.LayoutParams(screenWidth, screenHeight));
+
+ final View large = new View(this);
+ large.setId(R.id.b);
+ large.setBackgroundColor(0xFF00FF00);
+ // Compute the height of the view assuming a cache size based on ARGB8888
+ final int height = 2 * (cacheSize / 2) / screenWidth;
+ large.setLayoutParams(new LinearLayout.LayoutParams(screenWidth, height));
+
+ final ScrollView scroller = new ScrollView(this);
+ scroller.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.FILL_PARENT));
+
+ testBed.addView(tiny);
+ testBed.addView(large);
+ scroller.addView(testBed);
+
+ setContentView(scroller);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java
new file mode 100644
index 0000000..1f1f4f4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Disabled.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.app.Activity;
+
+/**
+ * Exercise View's disabled state.
+ */
+public class Disabled extends Activity implements OnClickListener {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.disabled);
+
+ // Find our buttons
+ Button disabledButton = (Button) findViewById(R.id.disabledButton);
+ disabledButton.setEnabled(false);
+
+ // Find our buttons
+ Button disabledButtonA = (Button) findViewById(R.id.disabledButtonA);
+ disabledButtonA.setOnClickListener(this);
+ }
+
+ public void onClick(View v) {
+ Button disabledButtonB = (Button) findViewById(R.id.disabledButtonB);
+ disabledButtonB.setEnabled(!disabledButtonB.isEnabled());
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java b/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java
new file mode 100644
index 0000000..1cbf05a
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/GlobalFocusChange.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewTreeObserver;
+import android.view.View;
+
+public class GlobalFocusChange extends Activity implements ViewTreeObserver.OnGlobalFocusChangeListener {
+ public View mOldFocus;
+ public View mNewFocus;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.focus_listener);
+ findViewById(R.id.left).getViewTreeObserver().addOnGlobalFocusChangeListener(this);
+ }
+
+ public void reset() {
+ mOldFocus = mNewFocus = null;
+ }
+
+ public void onGlobalFocusChanged(View oldFocus, View newFocus) {
+ mOldFocus = oldFocus;
+ mNewFocus = newFocus;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java
new file mode 100644
index 0000000..fc36e37
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Include.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+
+/**
+ * Exercise <include /> tag in XML files.
+ */
+public class Include extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.include_tag);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java
new file mode 100644
index 0000000..f3483fc
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Longpress.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2006 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class Longpress extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.longpress);
+ }
+}
+
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java
new file mode 100644
index 0000000..9596e91
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Merge.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.widget.LinearLayout;
+import android.view.ViewGroup;
+import android.view.LayoutInflater;
+
+/**
+ * Exercise <merge /> tag in XML files.
+ */
+public class Merge extends Activity {
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ LayoutInflater.from(this).inflate(R.layout.merge_tag, mLayout);
+
+ setContentView(mLayout);
+ }
+
+ public ViewGroup getLayout() {
+ return mLayout;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java b/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java
new file mode 100644
index 0000000..f4d477d4
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/PopupWindowVisibility.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.ArrayAdapter;
+import android.widget.AutoCompleteTextView;
+import android.widget.Button;
+import android.widget.Spinner;
+
+import com.android.frameworktest.R;
+
+/**
+ * Tests views with popupWindows becoming invisible
+ */
+public class PopupWindowVisibility extends Activity implements OnClickListener {
+
+ private View mFrame;
+ private Button mHide;
+ private Button mShow;
+
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.popup_window_visibility);
+
+ mFrame = findViewById(R.id.frame);
+
+ mHide = (Button) findViewById(R.id.hide);
+ mHide.setOnClickListener(this);
+
+ mShow = (Button) findViewById(R.id.show);
+ mShow.setOnClickListener(this);
+
+ Spinner spinner = (Spinner) findViewById(R.id.spinner);
+ ArrayAdapter<String> spinnerAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_spinner_item, mStrings);
+ spinnerAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
+ spinner.setAdapter(spinnerAdapter);
+
+ ArrayAdapter<String> autoAdapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.auto);
+ textView.setAdapter(autoAdapter);
+ }
+
+
+ public void onClick(View v) {
+ mFrame.setVisibility(v == mHide ? View.INVISIBLE : View.VISIBLE);
+ }
+ private static final String[] mStrings = {
+ "Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"
+ };
+
+ static final String[] COUNTRIES = new String[] {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+ "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+ "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java b/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java
new file mode 100644
index 0000000..cb456b2
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/PreDrawListener.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.app.Activity;
+import android.content.Context;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+import com.android.frameworktest.R;
+
+
+/**
+ * Tests views with popupWindows becoming invisible
+ */
+public class PreDrawListener extends Activity implements OnClickListener {
+
+ private MyLinearLayout mFrame;
+
+
+ static public class MyLinearLayout extends LinearLayout implements
+ ViewTreeObserver.OnPreDrawListener {
+
+ public boolean mCancelNextDraw;
+
+ public MyLinearLayout(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public MyLinearLayout(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ getViewTreeObserver().addOnPreDrawListener(this);
+ }
+
+ public boolean onPreDraw() {
+ if (mCancelNextDraw) {
+ Button b = new Button(this.getContext());
+ b.setText("Hello");
+ addView(b, new LinearLayout.LayoutParams(LayoutParams.FILL_PARENT,
+ LayoutParams.WRAP_CONTENT));
+ mCancelNextDraw = false;
+ return false;
+ }
+ return true;
+ }
+
+ }
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.pre_draw_listener);
+
+ mFrame = (MyLinearLayout) findViewById(R.id.frame);
+
+ Button mGoButton = (Button) findViewById(R.id.go);
+ mGoButton.setOnClickListener(this);
+ }
+
+
+ public void onClick(View v) {
+ mFrame.mCancelNextDraw = true;
+ mFrame.invalidate();
+ }
+
+
+
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java b/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java
new file mode 100644
index 0000000..146c0ab
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/RemoteViewsActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+import com.android.frameworktest.R;
+
+/**
+ * Exercise RemoteViews -- especially filtering
+ */
+public class RemoteViewsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.remote_view_host);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java b/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java
new file mode 100644
index 0000000..c8c3c28
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/RunQueue.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.widget.TextView;
+import android.view.View;
+import android.view.ViewTreeObserver;
+import com.android.frameworktest.R;
+
+/**
+ * Tests views using post*() and getViewTreeObserver() before onAttachedToWindow().
+ */
+public class RunQueue extends Activity implements ViewTreeObserver.OnGlobalLayoutListener {
+ public boolean runnableRan = false;
+ public boolean runnableCancelled = true;
+ public boolean globalLayout = false;
+ public ViewTreeObserver viewTreeObserver;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ TextView textView = new TextView(this);
+ textView.setText("RunQueue");
+ textView.setId(R.id.simple_view);
+
+ setContentView(textView);
+ final View view = findViewById(R.id.simple_view);
+
+ view.post(new Runnable() {
+ public void run() {
+ runnableRan = true;
+ }
+ });
+
+ final Runnable runnable = new Runnable() {
+ public void run() {
+ runnableCancelled = false;
+ }
+ };
+ view.post(runnable);
+ view.post(runnable);
+ view.post(runnable);
+ view.post(runnable);
+ view.removeCallbacks(runnable);
+
+ viewTreeObserver = view.getViewTreeObserver();
+ viewTreeObserver.addOnGlobalLayoutListener(this);
+ }
+
+ public void onGlobalLayout() {
+ globalLayout = true;
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java b/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java
new file mode 100644
index 0000000..2b0db9d
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/StubbedView.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+import android.view.View;
+
+/**
+ * Exercise <ViewStub /> tag in XML files.
+ */
+public class StubbedView extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.viewstub);
+
+ findViewById(R.id.vis).setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ final View view = findViewById(R.id.viewStub);
+ if (view != null) {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
+ });
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java b/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java
new file mode 100644
index 0000000..163e03c
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/ViewGroupChildren.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.app.Activity;
+
+/**
+ * Exercise ViewGroup's ability to add and remove children.
+ */
+public class ViewGroupChildren extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.viewgroupchildren);
+ }
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java b/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java
new file mode 100644
index 0000000..e068620
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/Visibility.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.widget.Button;
+import android.view.View;
+import android.app.Activity;
+
+/**
+ * Exercise View's ability to change their visibility: GONE, INVISIBLE and
+ * VISIBLE.
+ */
+public class Visibility extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.visibility);
+
+ // Find the view whose visibility will change
+ mVictim = findViewById(R.id.victim);
+
+ // Find our buttons
+ Button visibleButton = (Button) findViewById(R.id.vis);
+ Button invisibleButton = (Button) findViewById(R.id.invis);
+ Button goneButton = (Button) findViewById(R.id.gone);
+
+ // Wire each button to a click listener
+ visibleButton.setOnClickListener(mVisibleListener);
+ invisibleButton.setOnClickListener(mInvisibleListener);
+ goneButton.setOnClickListener(mGoneListener);
+ }
+
+
+ View.OnClickListener mVisibleListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mVictim.setVisibility(View.VISIBLE);
+ }
+ };
+
+ View.OnClickListener mInvisibleListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mVictim.setVisibility(View.INVISIBLE);
+ }
+ };
+
+ View.OnClickListener mGoneListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ mVictim.setVisibility(View.GONE);
+ }
+ };
+
+ private View mVictim;
+}
diff --git a/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java b/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java
new file mode 100644
index 0000000..e858fc0
--- /dev/null
+++ b/tests/FrameworkTest/src/com/android/frameworktest/view/ZeroSized.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+
+import android.os.Bundle;
+import android.app.Activity;
+
+/**
+ * This activity contains Views with various widths and heights. The goal is to exercise the
+ * drawing cache when width is null, height is null or both.
+ */
+public class ZeroSized extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.zero_sized);
+ }
+}
diff --git a/tests/FrameworkTest/tests/Android.mk b/tests/FrameworkTest/tests/Android.mk
new file mode 100644
index 0000000..5c54684
--- /dev/null
+++ b/tests/FrameworkTest/tests/Android.mk
@@ -0,0 +1,17 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := FrameworkTestTests
+
+LOCAL_INSTRUMENTATION_FOR := FrameworkTest
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/FrameworkTest/tests/AndroidManifest.xml b/tests/FrameworkTest/tests/AndroidManifest.xml
new file mode 100644
index 0000000..65aaebb
--- /dev/null
+++ b/tests/FrameworkTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworktest.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ This declares that this app uses the instrumentation test runner targeting
+ the package of com.android.frameworktest. To run the tests use the command:
+ "adb shell am instrument -w com.android.frameworktest.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.frameworktest"
+ android:label="framework tests"/>
+
+</manifest>
diff --git a/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
new file mode 100644
index 0000000..aa3d186
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/AbstractTableMergerTest.java
@@ -0,0 +1,578 @@
+package android.content;
+
+import com.google.android.collect.Lists;
+import com.google.android.collect.Sets;
+
+import android.database.Cursor;
+import android.database.sqlite.SQLiteDatabase;
+import android.net.Uri;
+import android.test.AndroidTestCase;
+import android.text.TextUtils;
+
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.SortedSet;
+
+/** Unit test for {@link android.content.AbstractTableMerger}. */
+public class AbstractTableMergerTest extends AndroidTestCase {
+ MockSyncableContentProvider mRealProvider;
+ MockSyncableContentProvider mTempProvider;
+ MockTableMerger mMerger;
+ MockSyncContext mSyncContext;
+
+ static final String TABLE_NAME = "items";
+ static final String DELETED_TABLE_NAME = "deleted_items";
+ static final Uri CONTENT_URI = Uri.parse("content://testdata");
+ static final Uri TABLE_URI = Uri.withAppendedPath(CONTENT_URI, TABLE_NAME);
+ static final Uri DELETED_TABLE_URI = Uri.withAppendedPath(CONTENT_URI, DELETED_TABLE_NAME);
+
+ private final String ACCOUNT = "account@goo.com";
+
+ private final ArrayList<Expectation> mExpectations = Lists.newArrayList();
+
+ static class Expectation {
+ enum Type {
+ UPDATE,
+ INSERT,
+ DELETE,
+ RESOLVE
+ }
+
+ Type mType;
+ ContentValues mValues;
+ Long mLocalRowId;
+
+ Expectation(Type type, Long localRowId, ContentValues values) {
+ mType = type;
+ mValues = values;
+ mLocalRowId = localRowId;
+ if (type == Type.DELETE) {
+ assertNull(values);
+ } else {
+ assertFalse(values.containsKey("_id"));
+ }
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mSyncContext = new MockSyncContext();
+ mRealProvider = new MockSyncableContentProvider();
+ mTempProvider = mRealProvider.getTemporaryInstance();
+ mMerger = new MockTableMerger(mRealProvider.getDatabase(),
+ TABLE_NAME, TABLE_URI, DELETED_TABLE_NAME, DELETED_TABLE_URI);
+ mExpectations.clear();
+ }
+
+ ContentValues newValues(String data, String syncId, String syncAccount,
+ String syncTime, String syncVersion, Long syncLocalId) {
+ ContentValues values = new ContentValues();
+ if (data != null) values.put("data", data);
+ if (syncTime != null) values.put("_sync_time", syncTime);
+ if (syncVersion != null) values.put("_sync_version", syncVersion);
+ if (syncId != null) values.put("_sync_id", syncId);
+ if (syncAccount != null) values.put("_sync_account", syncAccount);
+ values.put("_sync_local_id", syncLocalId);
+ values.put("_sync_dirty", 0);
+ return values;
+ }
+
+ ContentValues newDeletedValues(String syncId, String syncAccount, String syncVersion,
+ Long syncLocalId) {
+ ContentValues values = new ContentValues();
+ if (syncVersion != null) values.put("_sync_version", syncVersion);
+ if (syncId != null) values.put("_sync_id", syncId);
+ if (syncAccount != null) values.put("_sync_account", syncAccount);
+ if (syncLocalId != null) values.put("_sync_local_id", syncLocalId);
+ return values;
+ }
+
+ ContentValues newModifyData(String data) {
+ ContentValues values = new ContentValues();
+ values.put("data", data);
+ values.put("_sync_dirty", 1);
+ return values;
+ }
+
+ // Want to test adding, changing, deleting entries to a provider that has extra entries
+ // before and after the entries being changed.
+ public void testInsert() {
+ // add rows to the real provider
+ // add new row to the temp provider
+ final ContentValues row1 = newValues("d1", "si1", ACCOUNT, "st1", "sv1", null);
+ mTempProvider.insert(TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.INSERT, null /* syncLocalId */, row1));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testUpdateWithLocalId() {
+ // add rows to the real provider
+ // add new row to the temp provider that matches an unsynced row in the real provider
+ final ContentValues row1 = newValues("d1", "si1", ACCOUNT, "st1", "sv1", 11L);
+ mTempProvider.insert(TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.UPDATE, 11L, row1));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testUpdateWithoutLocalId() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+ // add new row to the temp provider that matches an unsynced row in the real provider
+ final ContentValues row1 = newValues("d2", "si1", ACCOUNT, "st2", "sv2", null);
+ mTempProvider.insert(TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.UPDATE, ContentUris.parseId(i1), row1));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testResolve() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+ mRealProvider.update(TABLE_URI, newModifyData("d2"), null, null);
+
+ // add row to the temp provider that matches a dirty, synced row in the real provider
+ final ContentValues row1 = newValues("d3", "si1", ACCOUNT, "st2", "sv2", null);
+ mTempProvider.insert(TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.RESOLVE, ContentUris.parseId(i1), row1));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testResolveWithLocalId() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+ mRealProvider.update(TABLE_URI, newModifyData("d2"), null, null);
+
+ // add row to the temp provider that matches a dirty, synced row in the real provider
+ ContentValues row1 = newValues("d2", "si1", ACCOUNT, "st2", "sv2", ContentUris.parseId(i1));
+ mTempProvider.insert(TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.UPDATE, ContentUris.parseId(i1), row1));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testDeleteRowAfterDelete() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+ // add a deleted record to the temp provider
+ ContentValues row1 = newDeletedValues(null, null, null, ContentUris.parseId(i1));
+ mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testDeleteRowAfterInsert() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI, newModifyData("d1"));
+
+ // add a deleted record to the temp provider
+ ContentValues row1 = newDeletedValues(null, null, null, ContentUris.parseId(i1));
+ mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testDeleteRowAfterUpdate() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+ // add a deleted record to the temp provider
+ ContentValues row1 = newDeletedValues("si1", ACCOUNT, "sv1", ContentUris.parseId(i1));
+ mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ public void testDeleteRowFromServer() {
+ // add rows to the real provider
+ Uri i1 = mRealProvider.insert(TABLE_URI,
+ newValues("d1", "si1", ACCOUNT, "st1", "sv1", null));
+
+ // add a deleted record to the temp provider
+ ContentValues row1 = newDeletedValues("si1", ACCOUNT, "sv1", null);
+ mTempProvider.insert(DELETED_TABLE_URI, row1);
+
+ // add expected callbacks to merger
+ mExpectations.add(new Expectation(Expectation.Type.DELETE, ContentUris.parseId(i1), null));
+
+ // run merger
+ SyncResult syncResult = new SyncResult();
+ mMerger.mergeServerDiffs(mSyncContext, ACCOUNT, mTempProvider, syncResult);
+
+ // check that all expectations were met
+ assertEquals("not all expectations were met", 0, mExpectations.size());
+ }
+
+ class MockTableMerger extends AbstractTableMerger {
+ public MockTableMerger(SQLiteDatabase database, String table, Uri tableURL,
+ String deletedTable, Uri deletedTableURL) {
+ super(database, table, tableURL, deletedTable, deletedTableURL);
+ }
+
+ public void insertRow(ContentProvider diffs, Cursor diffsCursor) {
+ Expectation expectation = mExpectations.remove(0);
+ checkExpectation(expectation,
+ Expectation.Type.INSERT, null /* syncLocalId */, diffsCursor);
+ }
+
+ public void updateRow(long localPersonID, ContentProvider diffs, Cursor diffsCursor) {
+ Expectation expectation = mExpectations.remove(0);
+ checkExpectation(expectation, Expectation.Type.UPDATE, localPersonID, diffsCursor);
+ }
+
+ public void resolveRow(long localPersonID, String syncID, ContentProvider diffs,
+ Cursor diffsCursor) {
+ Expectation expectation = mExpectations.remove(0);
+ checkExpectation(expectation, Expectation.Type.RESOLVE, localPersonID, diffsCursor);
+ }
+
+ @Override
+ public void deleteRow(Cursor cursor) {
+ Expectation expectation = mExpectations.remove(0);
+ assertEquals(expectation.mType, Expectation.Type.DELETE);
+ assertNotNull(expectation.mLocalRowId);
+ final long localRowId = cursor.getLong(cursor.getColumnIndexOrThrow("_id"));
+ assertEquals((long)expectation.mLocalRowId, localRowId);
+ cursor.moveToNext();
+ mDb.delete(TABLE_NAME, "_id=" + localRowId, null);
+ }
+
+ protected void notifyChanges() {
+ throw new UnsupportedOperationException();
+ }
+
+ void checkExpectation(Expectation expectation,
+ Expectation.Type actualType, Long localRowId,
+ Cursor cursor) {
+ assertEquals(expectation.mType, actualType);
+ assertEquals(expectation.mLocalRowId, localRowId);
+
+ final SortedSet<String> actualKeys = Sets.newSortedSet(cursor.getColumnNames());
+ final SortedSet<String> expectedKeys = Sets.newSortedSet();
+ for (Map.Entry<String, Object> entry : expectation.mValues.valueSet()) {
+ expectedKeys.add(entry.getKey());
+ }
+ actualKeys.remove("_id");
+ actualKeys.remove("_sync_mark");
+ actualKeys.remove("_sync_local_id");
+ expectedKeys.remove("_sync_local_id");
+ expectedKeys.remove("_id");
+ assertEquals("column mismatch",
+ TextUtils.join(",", expectedKeys), TextUtils.join(",", actualKeys));
+
+// if (localRowId != null) {
+// assertEquals((long) localRowId,
+// cursor.getLong(cursor.getColumnIndexOrThrow("_sync_local_id")));
+// } else {
+// assertTrue("unexpected _sync_local_id, "
+// + cursor.getLong(cursor.getColumnIndexOrThrow("_sync_local_id")),
+// cursor.isNull(cursor.getColumnIndexOrThrow("_sync_local_id")));
+// }
+
+ for (String name : cursor.getColumnNames()) {
+ if ("_id".equals(name)) {
+ continue;
+ }
+ if (cursor.isNull(cursor.getColumnIndexOrThrow(name))) {
+ assertNull(expectation.mValues.getAsString(name));
+ } else {
+ String actualValue =
+ cursor.getString(cursor.getColumnIndexOrThrow(name));
+ assertEquals("mismatch on column " + name,
+ expectation.mValues.getAsString(name), actualValue);
+ }
+ }
+ }
+ }
+
+ class MockSyncableContentProvider extends SyncableContentProvider {
+ SQLiteDatabase mDb;
+ boolean mIsTemporary;
+ boolean mContainsDiffs;
+
+ private final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);
+
+ private static final int MATCHER_ITEMS = 0;
+ private static final int MATCHER_DELETED_ITEMS = 1;
+
+ public MockSyncableContentProvider() {
+ mIsTemporary = false;
+ setContainsDiffs(false);
+ sURIMatcher.addURI(CONTENT_URI.getAuthority(), "items", MATCHER_ITEMS);
+ sURIMatcher.addURI(CONTENT_URI.getAuthority(), "deleted_items", MATCHER_DELETED_ITEMS);
+
+ mDb = SQLiteDatabase.create(null);
+ mDb.execSQL("CREATE TABLE items ("
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + "data TEXT, "
+ + "_sync_time TEXT, "
+ + "_sync_version TEXT, "
+ + "_sync_id TEXT, "
+ + "_sync_local_id INTEGER, "
+ + "_sync_dirty INTEGER NOT NULL DEFAULT 0, "
+ + "_sync_account TEXT, "
+ + "_sync_mark INTEGER)");
+
+ mDb.execSQL("CREATE TABLE deleted_items ("
+ + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+ + "_sync_version TEXT, "
+ + "_sync_id TEXT, "
+ + "_sync_local_id INTEGER, "
+ + "_sync_account TEXT, "
+ + "_sync_mark INTEGER)");
+ }
+
+ public boolean onCreate() {
+ throw new UnsupportedOperationException();
+ }
+
+ public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,
+ String sortOrder) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MATCHER_ITEMS:
+ return mDb.query(TABLE_NAME, projection, selection, selectionArgs,
+ null, null, sortOrder);
+ case MATCHER_DELETED_ITEMS:
+ return mDb.query(DELETED_TABLE_NAME, projection, selection, selectionArgs,
+ null, null, sortOrder);
+ default:
+ throw new UnsupportedOperationException("Cannot query URL: " + uri);
+ }
+ }
+
+ public String getType(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ public Uri insert(Uri uri, ContentValues values) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MATCHER_ITEMS: {
+ long id = mDb.insert(TABLE_NAME, "_id", values);
+ return CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
+ }
+ case MATCHER_DELETED_ITEMS: {
+ long id = mDb.insert(DELETED_TABLE_NAME, "_id", values);
+ return CONTENT_URI.buildUpon().appendPath(String.valueOf(id)).build();
+ }
+ default:
+ throw new UnsupportedOperationException("Cannot query URL: " + uri);
+ }
+ }
+
+ public int delete(Uri uri, String selection, String[] selectionArgs) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MATCHER_ITEMS:
+ return mDb.delete(TABLE_NAME, selection, selectionArgs);
+ case MATCHER_DELETED_ITEMS:
+ return mDb.delete(DELETED_TABLE_NAME, selection, selectionArgs);
+ default:
+ throw new UnsupportedOperationException("Cannot query URL: " + uri);
+ }
+ }
+
+ public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
+ int match = sURIMatcher.match(uri);
+ switch (match) {
+ case MATCHER_ITEMS:
+ return mDb.update(TABLE_NAME, values, selection, selectionArgs);
+ case MATCHER_DELETED_ITEMS:
+ return mDb.update(DELETED_TABLE_NAME, values, selection, selectionArgs);
+ default:
+ throw new UnsupportedOperationException("Cannot query URL: " + uri);
+ }
+ }
+
+ protected boolean isTemporary() {
+ return mIsTemporary;
+ }
+
+ public void close() {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void bootstrapDatabase(SQLiteDatabase db) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected boolean upgradeDatabase(SQLiteDatabase db, int oldVersion, int newVersion) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void onDatabaseOpened(SQLiteDatabase db) {
+ throw new UnsupportedOperationException();
+ }
+
+ public MockSyncableContentProvider getTemporaryInstance() {
+ MockSyncableContentProvider temp = new MockSyncableContentProvider();
+ temp.mIsTemporary = true;
+ temp.setContainsDiffs(true);
+ return temp;
+ }
+
+ public SQLiteDatabase getDatabase() {
+ return mDb;
+ }
+
+ public boolean getContainsDiffs() {
+ return mContainsDiffs;
+ }
+
+ public void setContainsDiffs(boolean containsDiffs) {
+ mContainsDiffs = containsDiffs;
+ }
+
+ protected Iterable<? extends AbstractTableMerger> getMergers() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean changeRequiresLocalSync(Uri uri) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onSyncStart(SyncContext context, String account) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onSyncStop(SyncContext context, boolean success) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getSyncingAccount() {
+ throw new UnsupportedOperationException();
+ }
+
+ public void merge(SyncContext context, SyncableContentProvider diffs,
+ TempProviderSyncResult result, SyncResult syncResult) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void onSyncCanceled() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isMergeCancelled() {
+ return false;
+ }
+
+ protected int updateInternal(Uri url, ContentValues values, String selection,
+ String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected int deleteInternal(Uri url, String selection, String[] selectionArgs) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected Uri insertInternal(Uri url, ContentValues values) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected Cursor queryInternal(Uri url, String[] projection, String selection,
+ String[] selectionArgs, String sortOrder) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void onAccountsChanged(String[] accountsArray) {
+ throw new UnsupportedOperationException();
+ }
+
+ protected void deleteRowsForRemovedAccounts(Map<String, Boolean> accounts, String table,
+ String accountColumnName) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void wipeAccount(String account) {
+ throw new UnsupportedOperationException();
+ }
+
+ public byte[] readSyncDataBytes(String account) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void writeSyncDataBytes(String account, byte[] data) {
+ throw new UnsupportedOperationException();
+ }
+ }
+
+ class MockSyncContext extends SyncContext {
+ public MockSyncContext() {
+ super(null);
+ }
+
+ @Override
+ public void setStatusText(String message) {
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java b/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java
new file mode 100644
index 0000000..a4c33f5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/content/SearchRecentSuggestionsProviderTest.java
@@ -0,0 +1,402 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content;
+
+import android.app.SearchManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.provider.SearchRecentSuggestions;
+import android.test.ProviderTestCase2;
+import android.test.suitebuilder.annotation.Suppress;
+
+/**
+ * Very simple provider that I can instantiate right here.
+ */
+class TestProvider extends SearchRecentSuggestionsProvider {
+ final static String AUTHORITY = "android.content.TestProvider";
+ final static int MODE = DATABASE_MODE_QUERIES + DATABASE_MODE_2LINES;
+
+ public TestProvider() {
+ super();
+ setupSuggestions(AUTHORITY, MODE);
+ }
+}
+
+/**
+ * ProviderTestCase that performs unit tests of SearchRecentSuggestionsProvider.
+ *
+ * You can run this test in isolation via the commands:
+ *
+ * $ (cd tests/FrameworkTests/ && mm) && adb sync
+ * $ adb shell am instrument -w \
+ * -e class android.content.SearchRecentSuggestionsProviderTest
+ * com.android.frameworktest.tests/android.test.InstrumentationTestRunner
+ */
+// Suppress these until bug http://b/issue?id=1416586 is fixed.
+@Suppress
+public class SearchRecentSuggestionsProviderTest extends ProviderTestCase2<TestProvider> {
+
+ // Elements prepared by setUp()
+ SearchRecentSuggestions mSearchHelper;
+
+ public SearchRecentSuggestionsProviderTest() {
+ super(TestProvider.class, TestProvider.AUTHORITY);
+ }
+
+ /**
+ * During setup, grab a helper for DB access
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // Use the recent suggestions helper. As long as we pass in our isolated context,
+ // it should correctly access the provider under test.
+ mSearchHelper = new SearchRecentSuggestions(getMockContext(),
+ TestProvider.AUTHORITY, TestProvider.MODE);
+
+ // test for empty database at setup time
+ checkOpenCursorCount(0);
+ }
+
+ /**
+ * Simple test to see if we can instantiate the whole mess.
+ */
+ public void testSetup() {
+ assertTrue(true);
+ }
+
+ /**
+ * Simple test to see if we can write and read back a single query
+ */
+ public void testOneQuery() {
+ final String TEST_LINE1 = "test line 1";
+ final String TEST_LINE2 = "test line 2";
+ mSearchHelper.saveRecentQuery(TEST_LINE1, TEST_LINE2);
+
+ // make sure that there are is exactly one entry returned by a non-filtering cursor
+ checkOpenCursorCount(1);
+
+ // test non-filtering cursor for correct entry
+ checkResultCounts(null, 1, 1, TEST_LINE1, TEST_LINE2);
+
+ // test filtering cursor for correct entry
+ checkResultCounts(TEST_LINE1, 1, 1, TEST_LINE1, TEST_LINE2);
+ checkResultCounts(TEST_LINE2, 1, 1, TEST_LINE1, TEST_LINE2);
+
+ // test that a different filter returns zero results
+ checkResultCounts("bad filter", 0, 0, null, null);
+ }
+
+ /**
+ * Simple test to see if we can write and read back a diverse set of queries
+ */
+ public void testMixedQueries() {
+ // we'll make 10 queries named "query x" and 10 queries named "test x"
+ final String TEST_GROUP_1 = "query ";
+ final String TEST_GROUP_2 = "test ";
+ final String TEST_LINE2 = "line2 ";
+ final int GROUP_COUNT = 10;
+
+ writeEntries(GROUP_COUNT, TEST_GROUP_1, TEST_LINE2);
+ writeEntries(GROUP_COUNT, TEST_GROUP_2, TEST_LINE2);
+
+ // check counts
+ checkOpenCursorCount(2 * GROUP_COUNT);
+
+ // check that each query returns the right result counts
+ checkResultCounts(TEST_GROUP_1, GROUP_COUNT, GROUP_COUNT, null, null);
+ checkResultCounts(TEST_GROUP_2, GROUP_COUNT, GROUP_COUNT, null, null);
+ checkResultCounts(TEST_LINE2, 2 * GROUP_COUNT, 2 * GROUP_COUNT, null, null);
+ }
+
+ /**
+ * Test that the reordering code works properly. The most recently injected queries
+ * should replace existing queries and be sorted to the top of the list.
+ */
+ public void testReordering() {
+ // first we'll make 10 queries named "group1 x"
+ final int GROUP_1_COUNT = 10;
+ final String GROUP_1_QUERY = "group1 ";
+ final String GROUP_1_LINE2 = "line2 ";
+ writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+
+ // check totals
+ checkOpenCursorCount(GROUP_1_COUNT);
+
+ // guarantee that group 1 has older timestamps
+ writeDelay();
+
+ // next we'll add 10 entries named "group2 x"
+ final int GROUP_2_COUNT = 10;
+ final String GROUP_2_QUERY = "group2 ";
+ final String GROUP_2_LINE2 = "line2 ";
+ writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+
+ // check totals
+ checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+ // guarantee that group 2 has older timestamps
+ writeDelay();
+
+ // now refresh 5 of the 10 from group 1
+ // change line2 so they can be more easily tracked
+ final int GROUP_3_COUNT = 5;
+ final String GROUP_3_QUERY = GROUP_1_QUERY;
+ final String GROUP_3_LINE2 = "refreshed ";
+ writeEntries(GROUP_3_COUNT, GROUP_3_QUERY, GROUP_3_LINE2);
+
+ // confirm that the total didn't change (those were replacements, not adds)
+ checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+ // confirm that the are now 5 in group 1, 10 in group 2, and 5 in group 3
+ int newGroup1Count = GROUP_1_COUNT - GROUP_3_COUNT;
+ checkResultCounts(GROUP_1_QUERY, newGroup1Count, newGroup1Count, null, GROUP_1_LINE2);
+ checkResultCounts(GROUP_2_QUERY, GROUP_2_COUNT, GROUP_2_COUNT, null, null);
+ checkResultCounts(GROUP_3_QUERY, GROUP_3_COUNT, GROUP_3_COUNT, null, GROUP_3_LINE2);
+
+ // finally, spot check that the right groups are in the right places
+ // the ordering should be group 3 (newest), group 2, group 1 (oldest)
+ Cursor c = getQueryCursor(null);
+ int colQuery = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_QUERY);
+ int colDisplay1 = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1);
+ int colDisplay2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+
+ // Spot check the first and last expected entries of group 3
+ c.moveToPosition(0);
+ assertTrue("group 3 did not properly reorder to head of list",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_3_QUERY, GROUP_3_LINE2));
+ c.move(GROUP_3_COUNT - 1);
+ assertTrue("group 3 did not properly reorder to head of list",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_3_QUERY, GROUP_3_LINE2));
+
+ // Spot check the first and last expected entries of group 2
+ c.move(1);
+ assertTrue("group 2 not in expected position after reordering",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_2_QUERY, GROUP_2_LINE2));
+ c.move(GROUP_2_COUNT - 1);
+ assertTrue("group 2 not in expected position after reordering",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_2_QUERY, GROUP_2_LINE2));
+
+ // Spot check the first and last expected entries of group 1
+ c.move(1);
+ assertTrue("group 1 not in expected position after reordering",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_1_QUERY, GROUP_1_LINE2));
+ c.move(newGroup1Count - 1);
+ assertTrue("group 1 not in expected position after reordering",
+ checkRow(c, colQuery, colDisplay1, colDisplay2, GROUP_1_QUERY, GROUP_1_LINE2));
+
+ c.close();
+ }
+
+ /**
+ * Test that the pruning code works properly, The database should not go beyond 250 entries,
+ * and the oldest entries should always be discarded first.
+ *
+ * TODO: This is a slow test, do we have annotation for that?
+ */
+ public void testPruning() {
+ // first we'll make 50 queries named "group1 x"
+ final int GROUP_1_COUNT = 50;
+ final String GROUP_1_QUERY = "group1 ";
+ final String GROUP_1_LINE2 = "line2 ";
+ writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+
+ // check totals
+ checkOpenCursorCount(GROUP_1_COUNT);
+
+ // guarantee that group 1 has older timestamps (and will be pruned first)
+ writeDelay();
+
+ // next we'll add 200 entries named "group2 x"
+ final int GROUP_2_COUNT = 200;
+ final String GROUP_2_QUERY = "group2 ";
+ final String GROUP_2_LINE2 = "line2 ";
+ writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+
+ // check totals
+ checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+ // Finally we'll add 10 more entries named "group3 x"
+ // These should push out 10 entries from group 1
+ final int GROUP_3_COUNT = 10;
+ final String GROUP_3_QUERY = "group3 ";
+ final String GROUP_3_LINE2 = "line2 ";
+ writeEntries(GROUP_3_COUNT, GROUP_3_QUERY, GROUP_3_LINE2);
+
+ // total should still be 250
+ checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+ // there should be 40 group 1, 200 group 2, and 10 group 3
+ int group1NewCount = GROUP_1_COUNT-GROUP_3_COUNT;
+ checkResultCounts(GROUP_1_QUERY, group1NewCount, group1NewCount, null, null);
+ checkResultCounts(GROUP_2_QUERY, GROUP_2_COUNT, GROUP_2_COUNT, null, null);
+ checkResultCounts(GROUP_3_QUERY, GROUP_3_COUNT, GROUP_3_COUNT, null, null);
+ }
+
+ /**
+ * Test that the clear history code works properly.
+ */
+ public void testClear() {
+ // first we'll make 10 queries named "group1 x"
+ final int GROUP_1_COUNT = 10;
+ final String GROUP_1_QUERY = "group1 ";
+ final String GROUP_1_LINE2 = "line2 ";
+ writeEntries(GROUP_1_COUNT, GROUP_1_QUERY, GROUP_1_LINE2);
+
+ // next we'll add 10 entries named "group2 x"
+ final int GROUP_2_COUNT = 10;
+ final String GROUP_2_QUERY = "group2 ";
+ final String GROUP_2_LINE2 = "line2 ";
+ writeEntries(GROUP_2_COUNT, GROUP_2_QUERY, GROUP_2_LINE2);
+
+ // check totals
+ checkOpenCursorCount(GROUP_1_COUNT + GROUP_2_COUNT);
+
+ // delete all
+ mSearchHelper.clearHistory();
+
+ // check totals
+ checkOpenCursorCount(0);
+ }
+
+ /**
+ * Write a sequence of queries into the database, with incrementing counters in the strings.
+ */
+ private void writeEntries(int groupCount, String line1Base, String line2Base) {
+ for (int i = 0; i < groupCount; i++) {
+ final String line1 = line1Base + i;
+ final String line2 = line2Base + i;
+ mSearchHelper.saveRecentQuery(line1, line2);
+ }
+ }
+
+ /**
+ * A very slight delay to ensure that successive groups of queries in the DB cannot
+ * have the same timestamp.
+ */
+ private void writeDelay() {
+ try {
+ Thread.sleep(10);
+ } catch (InterruptedException e) {
+ fail("Interrupted sleep.");
+ }
+ }
+
+ /**
+ * Access an "open" (no selection) suggestions cursor and confirm that it has the specified
+ * number of entries.
+ *
+ * @param expectCount The expected number of entries returned by the cursor.
+ */
+ private void checkOpenCursorCount(int expectCount) {
+ Cursor c = getQueryCursor(null);
+ assertEquals(expectCount, c.getCount());
+ c.close();
+ }
+
+ /**
+ * Set up a filter cursor and then scan it for specific results.
+ *
+ * @param queryString The query string to apply.
+ * @param minRows The minimum number of matching rows that must be found.
+ * @param maxRows The maximum number of matching rows that must be found.
+ * @param matchDisplay1 If non-null, must match DISPLAY1 column if row counts as match
+ * @param matchDisplay2 If non-null, must match DISPLAY2 column if row counts as match
+ */
+ private void checkResultCounts(String queryString, int minRows, int maxRows,
+ String matchDisplay1, String matchDisplay2) {
+
+ // get the cursor and apply sanity checks to result
+ Cursor c = getQueryCursor(queryString);
+ assertNotNull(c);
+ assertTrue("Insufficient rows in filtered cursor", c.getCount() >= minRows);
+
+ // look for minimum set of columns (note, display2 is optional)
+ int colQuery = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_QUERY);
+ int colDisplay1 = c.getColumnIndexOrThrow(SearchManager.SUGGEST_COLUMN_TEXT_1);
+ int colDisplay2 = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
+
+ // now loop through rows and look for desired rows
+ int foundRows = 0;
+ c.moveToFirst();
+ while (!c.isAfterLast()) {
+ if (checkRow(c, colQuery, colDisplay1, colDisplay2, matchDisplay1, matchDisplay2)) {
+ foundRows++;
+ }
+ c.moveToNext();
+ }
+
+ // now check the results
+ assertTrue(minRows <= foundRows);
+ assertTrue(foundRows <= maxRows);
+
+ c.close();
+ }
+
+ /**
+ * Check a single row for equality with target strings.
+ *
+ * @param c The cursor, already moved to the row
+ * @param colQuery The column # containing the query. The query must match display1.
+ * @param colDisp1 The column # containing display line 1.
+ * @param colDisp2 The column # containing display line 2, or -1 if no column
+ * @param matchDisplay1 If non-null, this must be the prefix of display1
+ * @param matchDisplay2 If non-null, this must be the prefix of display2
+ * @return Returns true if the row is a "match"
+ */
+ private boolean checkRow(Cursor c, int colQuery, int colDisp1, int colDisp2,
+ String matchDisplay1, String matchDisplay2) {
+ // Get the data from the row
+ String query = c.getString(colQuery);
+ String display1 = c.getString(colDisp1);
+ String display2 = (colDisp2 >= 0) ? c.getString(colDisp2) : null;
+
+ assertEquals(query, display1);
+ boolean result = true;
+ if (matchDisplay1 != null) {
+ result = result && (display1 != null) && display1.startsWith(matchDisplay1);
+ }
+ if (matchDisplay2 != null) {
+ result = result && (display2 != null) && display2.startsWith(matchDisplay2);
+ }
+
+ return result;
+ }
+
+ /**
+ * Generate a query cursor in a manner like the search dialog would.
+ *
+ * @param queryString The search string, or, null for "all"
+ * @return Returns a cursor, or null if there was some problem. Be sure to close the cursor
+ * when done with it.
+ */
+ private Cursor getQueryCursor(String queryString) {
+ ContentResolver cr = getMockContext().getContentResolver();
+
+ String uriStr = "content://" + TestProvider.AUTHORITY +
+ '/' + SearchManager.SUGGEST_URI_PATH_QUERY;
+ Uri contentUri = Uri.parse(uriStr);
+
+ String[] selArgs = new String[] {queryString};
+
+ Cursor c = cr.query(contentUri, null, null, selArgs, null);
+
+ assertNotNull(c);
+ return c;
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java
new file mode 100644
index 0000000..93cb84a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewCallbacks.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class AutoCompleteTextViewCallbacks
+ extends ActivityInstrumentationTestCase2<AutoCompleteTextViewSimple> {
+
+ public AutoCompleteTextViewCallbacks() {
+ super("com.android.frameworktest", AutoCompleteTextViewSimple.class);
+ }
+
+ /** Test that the initial popup of the suggestions does not select anything */
+ @MediumTest
+ public void testPopupNoSelection() {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // now check for selection callbacks. Nothing should be clicked or selected.
+ assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+ assertFalse("onItemSelected should not be called", theActivity.mItemSelectedCalled);
+
+ // arguably, this should be "false", because we aren't deselecting - we shouldn't
+ // really be calling it. But it's not the end of the world, and we might wind up
+ // breaking something if we change this.
+ assertTrue("onNothingSelected should be called", theActivity.mNothingSelectedCalled);
+ }
+
+ /** Test that arrow-down into the popup calls the onSelected callback */
+ @MediumTest
+ public void testPopupEnterSelection() {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // prepare to move down into the popup
+ theActivity.resetItemListeners();
+ sendKeys("DPAD_DOWN");
+
+ // now check for selection callbacks.
+ assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+ assertTrue("onItemSelected should be called", theActivity.mItemSelectedCalled);
+ assertEquals("onItemSelected position", 0, theActivity.mItemSelectedPosition);
+ assertFalse("onNothingSelected should not be called", theActivity.mNothingSelectedCalled);
+
+ // try one more time - should move from 0 to 1
+ theActivity.resetItemListeners();
+ sendKeys("DPAD_DOWN");
+
+ // now check for selection callbacks.
+ assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+ assertTrue("onItemSelected should be called", theActivity.mItemSelectedCalled);
+ assertEquals("onItemSelected position", 1, theActivity.mItemSelectedPosition);
+ assertFalse("onNothingSelected should not be called", theActivity.mNothingSelectedCalled);
+ }
+
+ /** Test that arrow-up out of the popup calls the onNothingSelected callback */
+ @MediumTest
+ public void testPopupLeaveSelection() {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // move down into the popup
+ sendKeys("DPAD_DOWN");
+
+ // now move back up out of the popup
+ theActivity.resetItemListeners();
+ sendKeys("DPAD_UP");
+
+ // now check for selection callbacks.
+ assertFalse("onItemClick should not be called", theActivity.mItemClickCalled);
+ assertFalse("onItemSelected should not be called", theActivity.mItemSelectedCalled);
+ assertTrue("onNothingSelected should be called", theActivity.mNothingSelectedCalled);
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
new file mode 100644
index 0000000..663b7a4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/AutoCompleteTextViewPopup.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+
+/**
+ * A collection of tests on aspects of the AutoCompleteTextView's popup
+ */
+public class AutoCompleteTextViewPopup
+ extends ActivityInstrumentationTestCase2<AutoCompleteTextViewSimple> {
+
+ public AutoCompleteTextViewPopup() {
+ super("com.android.frameworktest", AutoCompleteTextViewSimple.class);
+ }
+
+ /** Test that we can move the selection and it responds as expected */
+ @MediumTest
+ public void testPopupSetListSelection() throws Throwable {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ final AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // No initial selection
+ assertEquals("getListSelection(-1)",
+ ListView.INVALID_POSITION, textView.getListSelection());
+
+ // set and check
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ textView.setListSelection(0);
+ }
+ });
+ instrumentation.waitForIdleSync();
+ assertEquals("set selection to (0)", 0, textView.getListSelection());
+
+ // Use movement to cross-check the movement
+ sendKeys("DPAD_DOWN");
+ assertEquals("move selection to (1)", 1, textView.getListSelection());
+ }
+
+ /** Test that we can look at the selection as we move around */
+ @MediumTest
+ public void testPopupGetListSelection() {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // No initial selection
+ assertEquals("getListSelection(-1)",
+ ListView.INVALID_POSITION, textView.getListSelection());
+
+ // check for selection position as expected
+ sendKeys("DPAD_DOWN");
+ assertEquals("move selection to (0)", 0, textView.getListSelection());
+
+ // Repeat for one more movement
+ sendKeys("DPAD_DOWN");
+ assertEquals("move selection to (1)", 1, textView.getListSelection());
+ }
+
+ /** Test that we can clear the selection */
+ @MediumTest
+ public void testPopupClearListSelection() throws Throwable {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ final AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // No initial selection
+ assertEquals("getListSelection(-1)",
+ ListView.INVALID_POSITION, textView.getListSelection());
+
+ // check for selection position as expected
+ sendKeys("DPAD_DOWN");
+ assertEquals("getListSelection(0)", 0, textView.getListSelection());
+
+ // clear it
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ textView.clearListSelection();
+ }
+ });
+ instrumentation.waitForIdleSync();
+ assertEquals("setListSelection(ListView.INVALID_POSITION)",
+ ListView.INVALID_POSITION, textView.getListSelection());
+ }
+
+ /** Make sure we handle an empty adapter properly */
+ @MediumTest
+ public void testPopupNavigateNoAdapter() throws Throwable {
+ AutoCompleteTextViewSimple theActivity = getActivity();
+ final AutoCompleteTextView textView = theActivity.getTextView();
+ final Instrumentation instrumentation = getInstrumentation();
+
+ // focus and type
+ textView.requestFocus();
+ instrumentation.waitForIdleSync();
+ sendKeys("A");
+
+ // No initial selection
+ assertEquals("getListSelection(-1)",
+ ListView.INVALID_POSITION, textView.getListSelection());
+
+ // check for selection position as expected
+ sendKeys("DPAD_DOWN");
+ assertEquals("getListSelection(0)", 0, textView.getListSelection());
+
+ // Now get rid of the adapter
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ textView.setAdapter((ArrayAdapter<?>) null);
+ }
+ });
+ instrumentation.waitForIdleSync();
+
+ // now try moving "down" - nothing should happen since there's no longer an adapter
+ sendKeys("DPAD_DOWN");
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java b/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java
new file mode 100644
index 0000000..58f4ccb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/android/widget/SimpleCursorAdapterTest.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import com.android.internal.database.ArrayListCursor;
+import com.google.android.collect.Lists;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import java.util.ArrayList;
+import java.util.Random;
+
+/**
+ * This is a series of tests of basic API contracts for SimpleCursorAdapter. It is
+ * incomplete and can use work.
+ *
+ * NOTE: This contract holds for underlying cursor types too and these should
+ * be extracted into a set of tests that can be run on any descendant of CursorAdapter.
+ */
+public class SimpleCursorAdapterTest extends AndroidTestCase {
+
+ String[] mFrom;
+ int[] mTo;
+ int mLayout;
+ Context mContext;
+
+ ArrayList<ArrayList> mData2x2;
+ Cursor mCursor2x2;
+
+ /**
+ * Set up basic columns and cursor for the tests
+ */
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ // all the pieces needed for the various tests
+ mFrom = new String[]{"Column1", "Column2"};
+ mTo = new int[]{com.android.internal.R.id.text1, com.android.internal.R.id.text2};
+ mLayout = com.android.internal.R.layout.simple_list_item_2;
+ mContext = getContext();
+
+ // raw data for building a basic test cursor
+ mData2x2 = createTestList(2, 2);
+ mCursor2x2 = new ArrayListCursor(mFrom, mData2x2);
+ }
+
+ /**
+ * Borrowed from CursorWindowTest.java
+ */
+ private ArrayList<ArrayList> createTestList(int rows, int cols) {
+ ArrayList<ArrayList> list = Lists.newArrayList();
+ Random generator = new Random();
+
+ for (int i = 0; i < rows; i++) {
+ ArrayList<Integer> col = Lists.newArrayList();
+ list.add(col);
+ for (int j = 0; j < cols; j++) {
+ // generate random number
+ Integer r = generator.nextInt();
+ col.add(r);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * Test creating with a live cursor
+ */
+ @SmallTest
+ public void testCreateLive() {
+ SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+
+ // Now see if we can pull 2 rows from the adapter
+ assertEquals(2, ca.getCount());
+ }
+
+ /**
+ * Test creating with a null cursor
+ */
+ @SmallTest
+ public void testCreateNull() {
+ SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, mFrom, mTo);
+
+ // The adapter should report zero rows
+ assertEquals(0, ca.getCount());
+ }
+
+ /**
+ * Test changeCursor() with live cursor
+ */
+ @SmallTest
+ public void testChangeCursorLive() {
+ SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+
+ // Now see if we can pull 2 rows from the adapter
+ assertEquals(2, ca.getCount());
+
+ // now put in a different cursor (5 rows)
+ ArrayList<ArrayList> data2 = createTestList(5, 2);
+ Cursor c2 = new ArrayListCursor(mFrom, data2);
+ ca.changeCursor(c2);
+
+ // Now see if we can pull 5 rows from the adapter
+ assertEquals(5, ca.getCount());
+ }
+
+ /**
+ * Test changeCursor() with null cursor
+ */
+ @SmallTest
+ public void testChangeCursorNull() {
+ SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, mCursor2x2, mFrom, mTo);
+
+ // Now see if we can pull 2 rows from the adapter
+ assertEquals(2, ca.getCount());
+
+ // now put in null
+ ca.changeCursor(null);
+
+ // The adapter should report zero rows
+ assertEquals(0, ca.getCount());
+ }
+
+ /**
+ * Test changeCursor() with differing column layout. This confirms that the Adapter can
+ * deal with cursors that have the same essential data (as defined by the original mFrom
+ * array) but it's OK if the physical structure of the cursor changes (columns rearranged).
+ */
+ @SmallTest
+ public void testChangeCursorColumns() {
+ TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2,
+ mFrom, mTo);
+
+ // check columns of original - mFrom and mTo should line up
+ int[] columns = ca.getConvertedFrom();
+ assertEquals(columns[0], 0);
+ assertEquals(columns[1], 1);
+
+ // Now make a new cursor with similar data but rearrange the columns
+ String[] swappedFrom = new String[]{"Column2", "Column1"};
+ Cursor c2 = new ArrayListCursor(swappedFrom, mData2x2);
+ ca.changeCursor(c2);
+ assertEquals(2, ca.getCount());
+
+ // check columns to see if rearrangement tracked (should be swapped now)
+ columns = ca.getConvertedFrom();
+ assertEquals(columns[0], 1);
+ assertEquals(columns[1], 0);
+ }
+
+ /**
+ * Test that you can safely construct with a null cursor *and* null to/from arrays.
+ * This is new functionality added in 12/2008.
+ */
+ @SmallTest
+ public void testNullConstructor() {
+ SimpleCursorAdapter ca = new SimpleCursorAdapter(mContext, mLayout, null, null, null);
+ assertEquals(0, ca.getCount());
+ }
+
+ /**
+ * Test going from a null cursor to a non-null cursor *and* setting the to/from arrays
+ * This is new functionality added in 12/2008.
+ */
+ @SmallTest
+ public void testChangeNullToMapped() {
+ TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, null, null, null);
+ assertEquals(0, ca.getCount());
+
+ ca.changeCursorAndColumns(mCursor2x2, mFrom, mTo);
+ assertEquals(2, ca.getCount());
+
+ // check columns of original - mFrom and mTo should line up
+ int[] columns = ca.getConvertedFrom();
+ assertEquals(2, columns.length);
+ assertEquals(0, columns[0]);
+ assertEquals(1, columns[1]);
+ int[] viewIds = ca.getTo();
+ assertEquals(2, viewIds.length);
+ assertEquals(com.android.internal.R.id.text1, viewIds[0]);
+ assertEquals(com.android.internal.R.id.text2, viewIds[1]);
+ }
+
+ /**
+ * Test going from one mapping to a different mapping
+ * This is new functionality added in 12/2008.
+ */
+ @SmallTest
+ public void testChangeMapping() {
+ TestSimpleCursorAdapter ca = new TestSimpleCursorAdapter(mContext, mLayout, mCursor2x2,
+ mFrom, mTo);
+ assertEquals(2, ca.getCount());
+
+ // Now create a new configuration with same cursor and just one column mapped
+ String[] singleFrom = new String[]{"Column1"};
+ int[] singleTo = new int[]{com.android.internal.R.id.text1};
+ ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
+
+ // And examine the results, make sure they're still consistent
+ int[] columns = ca.getConvertedFrom();
+ assertEquals(1, columns.length);
+ assertEquals(0, columns[0]);
+ int[] viewIds = ca.getTo();
+ assertEquals(1, viewIds.length);
+ assertEquals(com.android.internal.R.id.text1, viewIds[0]);
+
+ // And again, same cursor, different map
+ singleFrom = new String[]{"Column2"};
+ singleTo = new int[]{com.android.internal.R.id.text2};
+ ca.changeCursorAndColumns(mCursor2x2, singleFrom, singleTo);
+
+ // And examine the results, make sure they're still consistent
+ columns = ca.getConvertedFrom();
+ assertEquals(1, columns.length);
+ assertEquals(1, columns[0]);
+ viewIds = ca.getTo();
+ assertEquals(1, viewIds.length);
+ assertEquals(com.android.internal.R.id.text2, viewIds[0]);
+ }
+
+ /**
+ * This is simply a way to sneak a look at the protected mFrom() array. A more API-
+ * friendly way to do this would be to mock out a View and a ViewBinder and exercise
+ * it via those seams.
+ */
+ private static class TestSimpleCursorAdapter extends SimpleCursorAdapter {
+
+ public TestSimpleCursorAdapter(Context context, int layout, Cursor c,
+ String[] from, int[] to) {
+ super(context, layout, c, from, to);
+ }
+
+ int[] getConvertedFrom() {
+ return mFrom;
+ }
+
+ int[] getTo() {
+ return mTo;
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java
new file mode 100644
index 0000000..e43ebb8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/AllTests.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest;
+
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+import android.test.suitebuilder.TestSuiteBuilder;
+
+public class AllTests extends TestSuite {
+
+ public static Test suite() {
+ return new TestSuiteBuilder(AllTests.class)
+ .includeAllPackagesUnderHere()
+ .includePackages("android.content")
+ .includePackages("android.widget")
+ .build();
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java
new file mode 100644
index 0000000..ef6297d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/DrawableBgMinSizeTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.drawable;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.drawable.DrawableBgMinSize;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.graphics.drawable.Drawable;
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.widget.AbsoluteLayout;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+/**
+ * {@link DrawableBgMinSize} exercises Views to obey their background drawable's
+ * minimum sizes.
+ */
+public class DrawableBgMinSizeTest extends
+ ActivityInstrumentationTestCase<DrawableBgMinSize> {
+ private Button mChangeBackgroundsButton;
+
+ private Drawable mBackgroundDrawable;
+ private Drawable mBigBackgroundDrawable;
+
+ private TextView mTextView;
+ private LinearLayout mLinearLayout;
+ private RelativeLayout mRelativeLayout;
+ private FrameLayout mFrameLayout;
+ private AbsoluteLayout mAbsoluteLayout;
+
+ public DrawableBgMinSizeTest() {
+ super("com.android.frameworktest", DrawableBgMinSize.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final DrawableBgMinSize a = getActivity();
+
+ mChangeBackgroundsButton = (Button) a.findViewById(R.id.change_backgrounds);
+ mBackgroundDrawable = a.getResources().getDrawable(R.drawable.drawable_background);
+ mBigBackgroundDrawable = a.getResources().getDrawable(R.drawable.big_drawable_background);
+ mTextView = (TextView) a.findViewById(R.id.text_view);
+ mLinearLayout = (LinearLayout) a.findViewById(R.id.linear_layout);
+ mRelativeLayout = (RelativeLayout) a.findViewById(R.id.relative_layout);
+ mFrameLayout = (FrameLayout) a.findViewById(R.id.frame_layout);
+ mAbsoluteLayout = (AbsoluteLayout) a.findViewById(R.id.absolute_layout);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mChangeBackgroundsButton);
+ assertNotNull(mBackgroundDrawable);
+ assertNotNull(mBigBackgroundDrawable);
+ assertNotNull(mTextView);
+ assertNotNull(mLinearLayout);
+ assertNotNull(mRelativeLayout);
+ assertNotNull(mFrameLayout);
+ assertNotNull(mAbsoluteLayout);
+ }
+
+ public void doMinimumSizeTest(View view) throws Exception {
+ assertTrue(view.getClass().getSimpleName() + " should respect the background Drawable's minimum width",
+ view.getWidth() >= mBackgroundDrawable.getMinimumWidth());
+ assertTrue(view.getClass().getSimpleName() + " should respect the background Drawable's minimum height",
+ view.getHeight() >= mBackgroundDrawable.getMinimumHeight());
+ }
+
+ @MediumTest
+ public void testTextViewMinimumSize() throws Exception {
+ doMinimumSizeTest(mTextView);
+ }
+
+ @MediumTest
+ public void testLinearLayoutMinimumSize() throws Exception {
+ doMinimumSizeTest(mLinearLayout);
+ }
+
+ @MediumTest
+ public void testRelativeLayoutMinimumSize() throws Exception {
+ doMinimumSizeTest(mRelativeLayout);
+ }
+
+ @MediumTest
+ public void testAbsoluteLayoutMinimumSize() throws Exception {
+ doMinimumSizeTest(mAbsoluteLayout);
+ }
+
+ @MediumTest
+ public void testFrameLayoutMinimumSize() throws Exception {
+ doMinimumSizeTest(mFrameLayout);
+ }
+
+ public void doDiffBgMinimumSizeTest(final View view) throws Exception {
+ // Change to the bigger backgrounds
+ TouchUtils.tapView(this, mChangeBackgroundsButton);
+
+ assertTrue(view.getClass().getSimpleName()
+ + " should respect the different bigger background Drawable's minimum width", view
+ .getWidth() >= mBigBackgroundDrawable.getMinimumWidth());
+ assertTrue(view.getClass().getSimpleName()
+ + " should respect the different bigger background Drawable's minimum height", view
+ .getHeight() >= mBigBackgroundDrawable.getMinimumHeight());
+ }
+
+ @MediumTest
+ public void testTextViewDiffBgMinimumSize() throws Exception {
+ doDiffBgMinimumSizeTest(mTextView);
+ }
+
+ @MediumTest
+ public void testLinearLayoutDiffBgMinimumSize() throws Exception {
+ doDiffBgMinimumSizeTest(mLinearLayout);
+ }
+
+ @MediumTest
+ public void testRelativeLayoutDiffBgMinimumSize() throws Exception {
+ doDiffBgMinimumSizeTest(mRelativeLayout);
+ }
+
+ @MediumTest
+ public void testAbsoluteLayoutDiffBgMinimumSize() throws Exception {
+ doDiffBgMinimumSizeTest(mAbsoluteLayout);
+ }
+
+ @MediumTest
+ public void testFrameLayoutDiffBgMinimumSize() throws Exception {
+ doDiffBgMinimumSizeTest(mFrameLayout);
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
new file mode 100644
index 0000000..53085ca
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/drawable/MutateDrawableTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.drawable;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+public class MutateDrawableTest extends ActivityInstrumentationTestCase2<MutateDrawable> {
+ private View mFirstButton;
+ private View mSecondButton;
+
+ public MutateDrawableTest() {
+ super("com.android.frameworktest", MutateDrawable.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mFirstButton = getActivity().findViewById(com.android.frameworktest.R.id.a);
+ mSecondButton = getActivity().findViewById(com.android.frameworktest.R.id.b);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mFirstButton);
+ assertNotNull(mSecondButton);
+ assertNotSame(mFirstButton.getBackground(), mSecondButton.getBackground());
+ }
+
+ @MediumTest
+ public void testDrawableCanMutate() throws Exception {
+ assertNotSame(mFirstButton.getBackground().getConstantState(),
+ mSecondButton.getBackground().getConstantState());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java
new file mode 100644
index 0000000..163e084
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListBasicTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.expandablelistview;
+
+import com.android.frameworktest.expandablelistview.ExpandableListSimple;
+import com.android.frameworktest.util.ExpandableListScenario;
+import com.android.frameworktest.util.ListUtil;
+import com.android.frameworktest.util.ExpandableListScenario.MyGroup;
+
+import java.util.List;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.BaseExpandableListAdapter;
+import android.widget.ExpandableListAdapter;
+import android.widget.ExpandableListView;
+
+public class ExpandableListBasicTest extends ActivityInstrumentationTestCase<ExpandableListSimple> {
+ private ExpandableListScenario mActivity;
+ private ExpandableListView mListView;
+ private ExpandableListAdapter mAdapter;
+ private ListUtil mListUtil;
+
+ public ExpandableListBasicTest() {
+ super("com.android.frameworktest",
+ ExpandableListSimple.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = mActivity.getExpandableListView();
+ mAdapter = mListView.getExpandableListAdapter();
+ mListUtil = new ListUtil(mListView, getInstrumentation());
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ private int expandGroup(int numChildren, boolean atLeastOneChild) {
+ final int groupPos = mActivity.findGroupWithNumChildren(numChildren, atLeastOneChild);
+
+ assertTrue("Could not find group to expand", groupPos >= 0);
+ assertFalse("Group is already expanded", mListView.isGroupExpanded(groupPos));
+ mListUtil.arrowScrollToSelectedPosition(groupPos);
+ getInstrumentation().waitForIdleSync();
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+ assertTrue("Group did not expand", mListView.isGroupExpanded(groupPos));
+
+ return groupPos;
+ }
+
+ @MediumTest
+ public void testExpandGroup() {
+ expandGroup(-1, true);
+ }
+
+ @MediumTest
+ public void testCollapseGroup() {
+ final int groupPos = expandGroup(-1, true);
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+ assertFalse("Group did not collapse", mListView.isGroupExpanded(groupPos));
+ }
+
+ @MediumTest
+ public void testExpandedGroupMovement() {
+
+ // Expand the first group
+ mListUtil.arrowScrollToSelectedPosition(0);
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+
+ // Ensure it expanded
+ assertTrue("Group did not expand", mListView.isGroupExpanded(0));
+
+ // Wait until that's all good
+ getInstrumentation().waitForIdleSync();
+
+ // Make sure it expanded
+ assertTrue("Group did not expand", mListView.isGroupExpanded(0));
+
+ // Insert a collapsed group in front of the one just expanded
+ List<MyGroup> groups = mActivity.getGroups();
+ MyGroup insertedGroup = new MyGroup(1);
+ groups.add(0, insertedGroup);
+
+ // Notify data change
+ assertTrue("Adapter is not an instance of the base adapter",
+ mAdapter instanceof BaseExpandableListAdapter);
+ final BaseExpandableListAdapter adapter = (BaseExpandableListAdapter) mAdapter;
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ adapter.notifyDataSetChanged();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ // Make sure the right group is expanded
+ assertTrue("The expanded state didn't stay with the proper group",
+ mListView.isGroupExpanded(1));
+ assertFalse("The expanded state was given to the inserted group",
+ mListView.isGroupExpanded(0));
+ }
+
+}
\ No newline at end of file
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java
new file mode 100644
index 0000000..49b5106
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/expandablelistview/ExpandableListWithHeadersTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.expandablelistview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ExpandableListView;
+
+import com.android.frameworktest.expandablelistview.ExpandableListWithHeaders;
+import com.android.frameworktest.util.ListUtil;
+
+public class ExpandableListWithHeadersTest extends ActivityInstrumentationTestCase<ExpandableListWithHeaders> {
+ private ExpandableListView mExpandableListView;
+ private ListUtil mListUtil;
+
+ public ExpandableListWithHeadersTest() {
+ super("com.android.frameworktest",
+ ExpandableListWithHeaders.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mExpandableListView = getActivity().getExpandableListView();
+ mListUtil = new ListUtil(mExpandableListView, getInstrumentation());
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mExpandableListView);
+ }
+
+ @MediumTest
+ public void testExpandOnFirstPosition() {
+ // Should be a header, and hence the first group should NOT have expanded
+ mListUtil.arrowScrollToSelectedPosition(0);
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+ assertFalse(mExpandableListView.isGroupExpanded(0));
+ }
+
+ @LargeTest
+ public void testExpandOnFirstGroup() {
+ mListUtil.arrowScrollToSelectedPosition(getActivity().getNumOfHeadersAndFooters());
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+ assertTrue(mExpandableListView.isGroupExpanded(0));
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java
new file mode 100644
index 0000000..6bdd416
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/DescendantFocusabilityTest.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.DescendantFocusability;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.UiThreadTest;
+import android.test.TouchUtils;
+import android.view.ViewGroup;
+
+public class DescendantFocusabilityTest extends ActivityInstrumentationTestCase<DescendantFocusability> {
+
+ private DescendantFocusability a;
+
+ public DescendantFocusabilityTest() {
+ super("com.android.frameworktest", DescendantFocusability.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ a = getActivity();
+
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals(ViewGroup.FOCUS_BEFORE_DESCENDANTS,
+ a.beforeDescendants.getDescendantFocusability());
+ assertEquals(ViewGroup.FOCUS_AFTER_DESCENDANTS,
+ a.afterDescendants.getDescendantFocusability());
+ assertEquals(ViewGroup.FOCUS_BLOCK_DESCENDANTS,
+ a.blocksDescendants.getDescendantFocusability());
+
+ assertTrue(a.beforeDescendantsChild.isFocusable());
+ assertTrue(a.afterDescendantsChild.isFocusable());
+ assertTrue(a.blocksDescendantsChild.isFocusable());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testBeforeDescendants() {
+ a.beforeDescendants.setFocusable(true);
+
+ assertTrue(a.beforeDescendants.requestFocus());
+ assertTrue(a.beforeDescendants.isFocused());
+
+ a.beforeDescendants.setFocusable(false);
+ a.beforeDescendants.requestFocus();
+ assertTrue(a.beforeDescendantsChild.isFocused());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testAfterDescendants() {
+ a.afterDescendants.setFocusable(true);
+
+ assertTrue(a.afterDescendants.requestFocus());
+ assertTrue(a.afterDescendantsChild.isFocused());
+
+ a.afterDescendants.setFocusable(false);
+ assertTrue(a.afterDescendants.requestFocus());
+ assertTrue(a.afterDescendantsChild.isFocused());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testBlocksDescendants() {
+ a.blocksDescendants.setFocusable(true);
+ assertTrue(a.blocksDescendants.requestFocus());
+ assertTrue(a.blocksDescendants.isFocused());
+ assertFalse(a.blocksDescendantsChild.isFocused());
+
+ a.blocksDescendants.setFocusable(false);
+ assertFalse(a.blocksDescendants.requestFocus());
+ assertFalse(a.blocksDescendants.isFocused());
+ assertFalse(a.blocksDescendantsChild.isFocused());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testChildOfDescendantBlockerRequestFocusFails() {
+ assertFalse(a.blocksDescendantsChild.requestFocus());
+ }
+
+ @LargeTest
+ public void testBeforeDescendantsEnterTouchMode() {
+ a.runOnUiThread(new Runnable() {
+ public void run() {
+ a.beforeDescendants.setFocusableInTouchMode(true);
+ a.beforeDescendantsChild.requestFocus();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ assertTrue(a.beforeDescendantsChild.isFocused());
+ assertFalse(a.beforeDescendantsChild.isInTouchMode());
+
+ TouchUtils.clickView(this, a.beforeDescendantsChild);
+ assertTrue(a.beforeDescendantsChild.isInTouchMode());
+ assertFalse(a.beforeDescendants.isFocused());
+ }
+
+ @LargeTest
+ public void testAfterDescendantsEnterTouchMode() {
+ a.runOnUiThread(new Runnable() {
+ public void run() {
+ a.afterDescendants.setFocusableInTouchMode(true);
+ a.afterDescendantsChild.requestFocus();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ assertTrue(a.afterDescendantsChild.isFocused());
+ assertFalse(a.afterDescendantsChild.isInTouchMode());
+
+ TouchUtils.clickView(this, a.afterDescendantsChild);
+ assertTrue(a.afterDescendantsChild.isInTouchMode());
+ assertTrue(a.afterDescendants.isFocused());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java
new file mode 100644
index 0000000..8fb9b01
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusAfterRemovalTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.FocusAfterRemoval;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * {@link FocusAfterRemoval} is set up to exercise cases where the views that
+ * have focus become invisible or GONE.
+ */
+public class FocusAfterRemovalTest extends ActivityInstrumentationTestCase<FocusAfterRemoval> {
+
+ private LinearLayout mLeftLayout;
+ private Button mTopLeftButton;
+ private Button mBottomLeftButton;
+ private Button mTopRightButton;
+ private Button mBottomRightButton;
+
+ public FocusAfterRemovalTest() {
+ super("com.android.frameworktest", FocusAfterRemoval.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final FocusAfterRemoval a = getActivity();
+ mLeftLayout = (LinearLayout) a.findViewById(R.id.leftLayout);
+ mTopLeftButton = (Button) a.findViewById(R.id.topLeftButton);
+ mBottomLeftButton = (Button) a.findViewById(R.id.bottomLeftButton);
+ mTopRightButton = (Button) a.findViewById(R.id.topRightButton);
+ mBottomRightButton = (Button) a.findViewById(R.id.bottomRightButton);
+ }
+
+ // Test that setUp did what we expect it to do. These asserts
+ // can't go in SetUp, or the test will hang.
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mLeftLayout);
+ assertNotNull(mTopLeftButton);
+ assertNotNull(mTopRightButton);
+ assertNotNull(mBottomLeftButton);
+ assertNotNull(mBottomRightButton);
+
+ assertTrue(mTopLeftButton.hasFocus());
+ }
+
+ // if a parent layout becomes GONE when one of its children has focus,
+ // make sure the focus moves to something visible (bug 827087)
+ @MediumTest
+ public void testFocusLeavesWhenParentLayoutIsGone() throws Exception {
+
+ // clicking on this button makes its parent linear layout GONE
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ assertEquals(View.GONE, mLeftLayout.getVisibility());
+
+ assertTrue("focus should jump to visible button",
+ mTopRightButton.hasFocus());
+
+ }
+
+ @MediumTest
+ public void testFocusLeavesWhenParentLayoutInvisible() throws Exception {
+
+ // move down to bottom left button
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue(mBottomLeftButton.hasFocus());
+
+ // clicking on this button makes its parent linear layout INVISIBLE
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ assertEquals(View.INVISIBLE,
+ getActivity().findViewById(R.id.leftLayout).getVisibility());
+
+ assertTrue("focus should jump to visible button",
+ mTopRightButton.hasFocus());
+ }
+
+ @MediumTest
+ public void testFocusLeavesWhenFocusedViewBecomesGone() throws Exception {
+
+ // move to top right
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertTrue(mTopRightButton.hasFocus());
+
+ // click making it GONE
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ assertEquals(View.GONE, mTopRightButton.getVisibility());
+
+ assertTrue("focus should jump to visible button",
+ mTopLeftButton.hasFocus());
+ }
+
+ @MediumTest
+ public void testFocusLeavesWhenFocusedViewBecomesInvisible() throws Exception {
+
+ // move to bottom right
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue(mBottomRightButton.hasFocus());
+
+ // click making it INVISIBLE
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ assertEquals(View.INVISIBLE, mBottomRightButton.getVisibility());
+
+ assertTrue("focus should jump to visible button",
+ mTopLeftButton.hasFocus());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java
new file mode 100644
index 0000000..6bdb1ca
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/FocusChangeWithInterestingRectHintTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.AdjacentVerticalRectLists;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+/**
+ * {@link android.view.FocusFinder#findNextFocus(android.view.ViewGroup, android.view.View, int)}
+ * and
+ * {@link android.view.View#requestFocus(int, android.graphics.Rect)}
+ * work together to give a newly focused item a hint about the most interesting
+ * rectangle of the previously focused view. The view taking focus can use this
+ * to set an internal selection more appropriate using this rect.
+ *
+ * This tests that behavior using three adjacent {@link com.android.frameworktest.util.InternalSelectionView}
+ * that report interesting rects when giving up focus, and use interesting rects
+ * when taking focus to best select the internal row to show as selected.
+ *
+ */
+public class FocusChangeWithInterestingRectHintTest extends ActivityInstrumentationTestCase<AdjacentVerticalRectLists> {
+
+ private InternalSelectionView mLeftColumn;
+ private InternalSelectionView mMiddleColumn;
+ private InternalSelectionView mRightColumn;
+
+ public FocusChangeWithInterestingRectHintTest() {
+ super("com.android.frameworktest", AdjacentVerticalRectLists.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mLeftColumn = getActivity().getLeftColumn();
+ mMiddleColumn = getActivity().getMiddleColumn();
+ mRightColumn = getActivity().getRightColumn();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mLeftColumn);
+ assertNotNull(mMiddleColumn);
+ assertNotNull(mRightColumn);
+ assertTrue(mLeftColumn.hasFocus());
+ assertTrue("need at least 3 rows", mLeftColumn.getNumRows() > 2);
+ assertEquals(mLeftColumn.getNumRows(), mMiddleColumn.getNumRows());
+ assertEquals(mMiddleColumn.getNumRows(), mRightColumn.getNumRows());
+ }
+
+
+ @LargeTest
+ public void testSnakeBackAndForth() {
+ final int numRows = mLeftColumn.getNumRows();
+ for (int row = 0; row < numRows; row++) {
+
+ if ((row % 2) == 0) {
+ assertEquals("row " + row + ": should be at left column",
+ row, mLeftColumn.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertTrue("row " + row + ": should be at middle column",
+ mMiddleColumn.hasFocus());
+ assertEquals(row, mMiddleColumn.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertTrue("row " + row + ": should be at right column",
+ mRightColumn.hasFocus());
+ assertEquals(row, mRightColumn.getSelectedRow());
+
+ if (row < numRows - 1) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(row + 1, mRightColumn.getSelectedRow());
+ }
+ } else {
+ assertTrue("row " + row + ": should be at right column",
+ mRightColumn.hasFocus());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+ assertTrue("row " + row + ": should be at middle column",
+ mMiddleColumn.hasFocus());
+ assertEquals(row, mMiddleColumn.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+ assertEquals("row " + row + ": should be at left column",
+ row, mLeftColumn.getSelectedRow());
+
+ if (row < numRows - 1) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(row + 1, mLeftColumn.getSelectedRow());
+ }
+ }
+ }
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java
new file mode 100644
index 0000000..a490322
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/GoneParentFocusedChildTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import com.android.frameworktest.focus.GoneParentFocusedChild;
+
+/**
+ * When a parent is GONE, key events shouldn't go to its children, even if they
+ * have focus. (part of investigation into issue 945150).
+ */
+public class GoneParentFocusedChildTest
+ extends ActivityInstrumentationTestCase<GoneParentFocusedChild> {
+
+
+ public GoneParentFocusedChildTest() {
+ super("com.android.frameworktest", GoneParentFocusedChild.class);
+ }
+
+ @MediumTest
+ public void testPreconditinos() {
+ assertNotNull(getActivity().getLayout());
+ assertNotNull(getActivity().getGoneGroup());
+ assertNotNull(getActivity().getButton());
+ assertTrue("button should have focus",
+ getActivity().getButton().hasFocus());
+ assertEquals("gone group should be, well, gone!",
+ View.GONE,
+ getActivity().getGoneGroup().getVisibility());
+ assertFalse("the activity should have received no key events",
+ getActivity().isUnhandledKeyEvent());
+ }
+
+ @MediumTest
+ public void testKeyEventGoesToActivity() {
+ sendKeys(KeyEvent.KEYCODE_J);
+ assertTrue(getActivity().isUnhandledKeyEvent());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java
new file mode 100644
index 0000000..ca7cd7e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/HorizontalFocusSearchTest.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.HorizontalFocusSearch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.view.View;
+
+import static com.android.frameworktest.focus.VerticalFocusSearchTest.FocusSearchAlg;
+import static com.android.frameworktest.focus.VerticalFocusSearchTest.NewFocusSearchAlg;
+
+/**
+ * Tests that focus searching works on a horizontal linear layout of buttons of
+ * various widths and vertical placements.
+ */
+// Suppress until bug http://b/issue?id=1416545 is fixed.
+@Suppress
+public class HorizontalFocusSearchTest extends ActivityInstrumentationTestCase<HorizontalFocusSearch> {
+
+ private FocusSearchAlg mFocusFinder;
+
+ private LinearLayout mLayout;
+ private Button mLeftTall;
+ private Button mMidShort1Top;
+ private Button mMidShort2Bottom;
+ private Button mRightTall;
+
+
+ public HorizontalFocusSearchTest() {
+ super("com.android.frameworktest", HorizontalFocusSearch.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mFocusFinder = new NewFocusSearchAlg();
+
+ mLayout = getActivity().getLayout();
+ mLeftTall = getActivity().getLeftTall();
+ mMidShort1Top = getActivity().getMidShort1Top();
+ mMidShort2Bottom = getActivity().getMidShort2Bottom();
+ mRightTall = getActivity().getRightTall();
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mLayout);
+ assertNotNull(mLeftTall);
+ assertNotNull(mMidShort1Top);
+ assertNotNull(mMidShort2Bottom);
+ assertNotNull(mRightTall);
+ }
+
+ public void testSearchFromLeftButton() {
+ assertNull("going up from mLeftTall",
+ mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_UP));
+ assertNull("going down from mLeftTall",
+ mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_DOWN));
+ assertNull("going left from mLeftTall",
+ mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_LEFT));
+
+ assertEquals("going right from mLeftTall",
+ mMidShort1Top,
+ mFocusFinder.findNextFocus(mLayout, mLeftTall, View.FOCUS_RIGHT));
+ }
+
+ public void TODO_testSearchFromMiddleLeftButton() {
+ assertNull("going up from mMidShort1Top",
+ mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_UP));
+ assertEquals("going down from mMidShort1Top",
+ mMidShort2Bottom,
+ mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_DOWN));
+ assertEquals("going left from mMidShort1Top",
+ mLeftTall,
+ mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_LEFT));
+ assertEquals("going right from mMidShort1Top",
+ mMidShort2Bottom,
+ mFocusFinder.findNextFocus(mLayout, mMidShort1Top, View.FOCUS_RIGHT));
+ }
+
+ public void TODO_testSearchFromMiddleRightButton() {
+ assertEquals("going up from mMidShort2Bottom",
+ mMidShort1Top,
+ mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_UP));
+ assertNull("going down from mMidShort2Bottom",
+ mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_DOWN));
+ assertEquals("going left from mMidShort2Bottom",
+ mMidShort1Top,
+ mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_LEFT));
+ assertEquals("goind right from mMidShort2Bottom",
+ mRightTall,
+ mFocusFinder.findNextFocus(mLayout, mMidShort2Bottom, View.FOCUS_RIGHT));
+ }
+
+ public void testSearchFromRightButton() {
+ assertNull("going up from mRightTall",
+ mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_UP));
+ assertNull("going down from mRightTall",
+ mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_DOWN));
+ assertEquals("going left from mRightTall",
+ mMidShort2Bottom,
+ mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_LEFT));
+ assertNull("going right from mRightTall",
+ mFocusFinder.findNextFocus(mLayout, mRightTall, View.FOCUS_RIGHT));
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java
new file mode 100644
index 0000000..c26c331
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/LinearLayoutGridTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.test.SingleLaunchActivityTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.focus.LinearLayoutGrid;
+
+/**
+ * Tests focus searching between buttons within a grid that are touching, for example,
+ * two buttons next two each other would have the left button's right equal to the
+ * right button's left. Same goes for top and bottom edges.
+ *
+ * This exercises some edge cases of {@link android.view.FocusFinder}.
+ */
+public class LinearLayoutGridTest extends SingleLaunchActivityTestCase<LinearLayoutGrid> {
+ private ViewGroup mRootView;
+
+ public LinearLayoutGridTest() {
+ super("com.android.frameworktest", LinearLayoutGrid.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mRootView = getActivity().getRootView();
+ }
+
+ @MediumTest
+ public void testGoDownFromMiddle() {
+ assertEquals(getActivity().getButtonAt(2, 1),
+ FocusFinder.getInstance().findNextFocus(
+ mRootView,
+ getActivity().getButtonAt(1, 1),
+ View.FOCUS_DOWN));
+ }
+
+ @MediumTest
+ public void testGoUpFromMiddle() {
+ assertEquals(getActivity().getButtonAt(0, 1),
+ FocusFinder.getInstance().findNextFocus(
+ mRootView,
+ getActivity().getButtonAt(1, 1),
+ View.FOCUS_UP));
+ }
+
+ @MediumTest
+ public void testGoRightFromMiddle() {
+ assertEquals(getActivity().getButtonAt(1, 2),
+ FocusFinder.getInstance().findNextFocus(
+ mRootView,
+ getActivity().getButtonAt(1, 1),
+ View.FOCUS_RIGHT));
+ }
+
+ @MediumTest
+ public void testGoLeftFromMiddle() {
+ assertEquals(getActivity().getButtonAt(1, 0),
+ FocusFinder.getInstance().findNextFocus(
+ mRootView,
+ getActivity().getButtonAt(1, 1),
+ View.FOCUS_LEFT));
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java
new file mode 100644
index 0000000..902fc1c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListOfButtonsTest.java
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.ListOfButtons;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListAdapter;
+import android.widget.Button;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * Tests that focus works as expected when navigating into and out of
+ * a {@link ListView} that has buttons in it.
+ */
+public class ListOfButtonsTest extends ActivityInstrumentationTestCase<ListOfButtons> {
+
+ private ListAdapter mListAdapter;
+ private Button mButtonAtTop;
+
+ private ListView mListView;
+
+ public ListOfButtonsTest() {
+ super("com.android.frameworktest", ListOfButtons.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ ListOfButtons a = getActivity();
+ mListAdapter = a.getListAdapter();
+ mButtonAtTop = (Button) a.findViewById(R.id.button);
+ mListView = a.getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListAdapter);
+ assertNotNull(mButtonAtTop);
+ assertNotNull(mListView);
+
+ assertFalse(mButtonAtTop.hasFocus());
+ assertTrue(mListView.hasFocus());
+ assertEquals("expecting 0 index to be selected",
+ 0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testNavigateToButtonAbove() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ assertTrue(mButtonAtTop.hasFocus());
+ assertFalse(mListView.hasFocus());
+ }
+
+ @MediumTest
+ public void testNavigateToSecondItem() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue(mListView.hasFocus());
+
+ View childOne = mListView.getChildAt(1);
+ assertNotNull(childOne);
+ assertEquals(childOne, mListView.getFocusedChild());
+ assertTrue(childOne.hasFocus());
+ }
+
+ @MediumTest
+ public void testNavigateUpAboveAndBackOut() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertFalse("button at top should have focus back",
+ mButtonAtTop.hasFocus());
+ assertTrue(mListView.hasFocus());
+ }
+
+ // TODO: this reproduces bug 981791
+ public void TODO_testNavigateThroughAllButtonsAndBack() {
+
+ String[] labels = getActivity().getLabels();
+ for (int i = 0; i < labels.length; i++) {
+ String label = labels[i];
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+
+ String indexInfo = "index: " + i + ", label: " + label;
+
+ assertTrue(indexInfo, mListView.hasFocus());
+
+ Button button = (Button) mListView.getSelectedView();
+ assertNotNull(indexInfo, button);
+ assertEquals(indexInfo, label, button.getText().toString());
+ assertTrue(indexInfo, button.hasFocus());
+ }
+
+ // pressing down again shouldn't matter; make sure last item keeps focus
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+
+ for (int i = labels.length - 1; i >= 0; i--) {
+ String label = labels[i];
+
+ String indexInfo = "index: " + i + ", label: " + label;
+
+ assertTrue(indexInfo, mListView.hasFocus());
+
+ Button button = (Button) mListView.getSelectedView();
+ assertNotNull(indexInfo, button);
+ assertEquals(indexInfo, label, button.getText().toString());
+ assertTrue(indexInfo, button.hasFocus());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ assertTrue("button at top should have focus back",
+ mButtonAtTop.hasFocus());
+ assertFalse(mListView.hasFocus());
+ }
+
+ @MediumTest
+ public void testGoInAndOutOfListWithItemsFocusable() {
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ assertTrue(mButtonAtTop.hasFocus());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ final String firstButtonLabel = getActivity().getLabels()[0];
+ final Button firstButton = (Button) mListView.getSelectedView();
+
+ assertTrue(firstButton.isFocused());
+ assertEquals(firstButtonLabel, firstButton.getText());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertTrue(mButtonAtTop.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue(firstButton.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertTrue(mButtonAtTop.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue(firstButton.isFocused());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java
new file mode 100644
index 0000000..c094882
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ListWithFooterViewAndNewLabelsTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.ListWithFooterViewAndNewLabels;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.Button;
+import android.widget.ListAdapter;
+import android.widget.ListView;
+
+public class ListWithFooterViewAndNewLabelsTest
+ extends ActivityInstrumentationTestCase<ListWithFooterViewAndNewLabels> {
+
+ private Button mButton;
+
+ private ListAdapter mAdapter;
+
+ private ListView mListView;
+
+
+ public ListWithFooterViewAndNewLabelsTest() {
+ super("com.android.frameworktest",
+ ListWithFooterViewAndNewLabels.class);
+ }
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ ListWithFooterViewAndNewLabels a = getActivity();
+ mButton = (Button) a.findViewById(R.id.button);
+ mAdapter = a.getListAdapter();
+ mListView = a.getListView();
+ }
+
+ // bug 900885
+ public void FAILING_testPreconditions() {
+ assertNotNull(mButton);
+ assertNotNull(mAdapter);
+ assertNotNull(mListView);
+
+ assertTrue(mButton.hasFocus());
+ assertEquals("expected list adapter to have 1 item",
+ 1, mAdapter.getCount());
+ assertEquals("expected list view to have 2 items (1 in adapter, plus "
+ + "the footer view).",
+ 2, mListView.getCount());
+
+ // fails here!!!
+ assertEquals("Expecting the selected index to be 0, the first non footer "
+ + "view item.",
+ 0, mListView.getSelectedItemPosition());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java
new file mode 100644
index 0000000..5fb3a29
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/RequestFocusTest.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.RequestFocus;
+import com.android.frameworktest.R;
+
+import android.os.Handler;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.util.AndroidRuntimeException;
+
+/**
+ * {@link RequestFocusTest} is set up to exercise cases where the views that
+ * have focus become invisible or GONE.
+ */
+public class RequestFocusTest extends ActivityInstrumentationTestCase<RequestFocus> {
+
+ private Button mTopLeftButton;
+ private Button mBottomLeftButton;
+ private Button mTopRightButton;
+ private Button mBottomRightButton;
+ private Handler mHandler;
+
+ public RequestFocusTest() {
+ super("com.android.frameworktest", RequestFocus.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final RequestFocus a = getActivity();
+ mHandler = a.getHandler();
+ mTopLeftButton = (Button) a.findViewById(R.id.topLeftButton);
+ mBottomLeftButton = (Button) a.findViewById(R.id.bottomLeftButton);
+ mTopRightButton = (Button) a.findViewById(R.id.topRightButton);
+ mBottomRightButton = (Button) a.findViewById(R.id.bottomRightButton);
+ }
+
+ // Test that setUp did what we expect it to do. These asserts
+ // can't go in SetUp, or the test will hang.
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mHandler);
+ assertNotNull(mTopLeftButton);
+ assertNotNull(mTopRightButton);
+ assertNotNull(mBottomLeftButton);
+ assertNotNull(mBottomRightButton);
+ assertTrue("requestFocus() should work from onCreate.", mBottomRightButton.hasFocus());
+ }
+
+ // Test that a posted requestFocus works.
+ @LargeTest
+ public void testPostedRequestFocus() throws Exception {
+ mHandler.post(new Runnable() { public void run() {
+ mBottomLeftButton.requestFocus();
+ }});
+ synchronized(this) {
+ try {
+ wait(500);
+ } catch (InterruptedException e) {
+ // Don't care.
+ }
+ }
+ assertTrue("Focus should move to bottom left", mBottomLeftButton.hasFocus());
+ }
+
+ // Test that a requestFocus from the wrong thread fails.
+ @MediumTest
+ public void testWrongThreadRequestFocusFails() throws Exception {
+ try {
+ mTopRightButton.requestFocus();
+ fail("requestFocus from wrong thread should raise exception.");
+ } catch (AndroidRuntimeException e) {
+ // Expected. The actual exception is not public, so we can't catch it.
+ assertEquals("android.view.ViewRoot$CalledFromWrongThreadException",
+ e.getClass().getName());
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
new file mode 100644
index 0000000..07916ee
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/ScrollingThroughListOfFocusablesTest.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import android.graphics.Rect;
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.focus.ListOfInternalSelectionViews;
+import com.android.frameworktest.util.InternalSelectionView;
+
+
+/**
+ * TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
+ * bundle params.
+ */
+public class ScrollingThroughListOfFocusablesTest extends InstrumentationTestCase {
+
+ Rect mTempRect = new Rect();
+
+ private ListOfInternalSelectionViews mActivity;
+ private ListView mListView;
+
+ private int mNumItems = 4;
+ private int mNumRowsPerItem = 5;
+ private double mScreenHeightFactor = 5 /4;
+
+ @Override
+ protected void setUp() throws Exception {
+ mActivity = launchActivity(
+ "com.android.frameworktest",
+ ListOfInternalSelectionViews.class,
+ ListOfInternalSelectionViews.getBundleFor(
+ mNumItems, // 4 items
+ mNumRowsPerItem, // 5 internally selectable rows per item
+ mScreenHeightFactor)); // each item is 5 / 4 screen height tall
+ mListView = mActivity.getListView();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mActivity.finish();
+ super.tearDown();
+ }
+
+ @MediumTest
+ public void testPreconditions() throws Exception {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ assertEquals(mNumItems, mActivity.getNumItems());
+ assertEquals(mNumRowsPerItem, mActivity.getNumRowsPerItem());
+ }
+
+ @MediumTest
+ public void testScrollingDownInFirstItem() throws Exception {
+
+ for (int i = 0; i < mNumRowsPerItem; i++) {
+ assertEquals(0, mListView.getSelectedItemPosition());
+ InternalSelectionView view = mActivity.getSelectedView();
+
+ assertInternallySelectedRowOnScreen(view, i);
+
+ // move to next row
+ if (i < mNumRowsPerItem - 1) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+ }
+ }
+
+ {
+ assertEquals(0, mListView.getSelectedItemPosition());
+ InternalSelectionView view = (InternalSelectionView)
+ mListView.getSelectedView();
+
+ // 1 pixel tolerance in case height / 4 is not an even number
+ final int fadingEdge = mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
+ assertTrue("bottom of view should be just above fading edge",
+ view.getBottom() >= fadingEdge - 1 &&
+ view.getBottom() <= fadingEdge);
+ }
+
+
+ // make sure fading edge is the expected view
+ {
+ assertEquals("should be a second view visible due to the fading edge",
+ 2, mListView.getChildCount());
+ InternalSelectionView peekingChild = (InternalSelectionView)
+ mListView.getChildAt(1);
+ assertNotNull(peekingChild);
+ assertEquals("wrong value for peeking list item",
+ mActivity.getLabelForPosition(1), peekingChild.getLabel());
+ }
+ }
+
+
+ @MediumTest
+ public void testScrollingToSecondItem() throws Exception {
+
+ for (int i = 0; i < mNumRowsPerItem; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ assertEquals("should have moved to second item",
+ 1, mListView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testNoFadingEdgeAtBottomOfLastItem() {
+
+ // move down to last item
+ for (int i = 0; i < mNumItems; i++) {
+ for (int j = 0; j < mNumRowsPerItem; j++) {
+ if (i < mNumItems - 1 || j < mNumRowsPerItem - 1) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+ }
+ }
+ }
+
+ assertEquals(mNumItems - 1, mListView.getSelectedItemPosition());
+ InternalSelectionView view = mActivity.getSelectedView();
+ assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
+
+ view.getRectForRow(mTempRect, mNumRowsPerItem - 1);
+ mListView.offsetDescendantRectToMyCoords(view, mTempRect);
+
+ assertTrue("bottom of last row of last item should be at " +
+ "the bottom of the list view (no fading edge)",
+ mListView.getBottom() - mListView.getVerticalFadingEdgeLength() < mTempRect.bottom);
+ }
+
+ @LargeTest
+ public void testNavigatingUpThroughInternalSelection() throws Exception {
+
+ // get to bottom of second item
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < mNumRowsPerItem; j++) {
+ if (i < 1 || j < mNumRowsPerItem - 1) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+ }
+ }
+ }
+
+
+ // (make sure we are at last row of second item)
+ {
+ assertEquals(1, mListView.getSelectedItemPosition());
+ InternalSelectionView view = mActivity.getSelectedView();
+ assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
+ }
+
+ // go back up to the top of the second item
+ for (int i = mNumRowsPerItem - 1; i >= 0; i--) {
+ assertEquals(1, mListView.getSelectedItemPosition());
+ InternalSelectionView view = mActivity.getSelectedView();
+
+ assertInternallySelectedRowOnScreen(view, i);
+
+ // move up to next row
+ if (i > 0) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ getInstrumentation().waitForIdleSync();
+ }
+ }
+
+ // now we are at top row, should have caused scrolling, and fading edge...
+ {
+ assertEquals(1, mListView.getSelectedItemPosition());
+ InternalSelectionView view = mActivity.getSelectedView();
+ assertEquals(0, view.getSelectedRow());
+
+ view.getDrawingRect(mTempRect);
+ mListView.offsetDescendantRectToMyCoords(view, mTempRect);
+ assertEquals("top of selected row should be just below top vertical fading edge",
+ mListView.getVerticalFadingEdgeLength(),
+ view.getTop());
+ }
+
+ // make sure fading edge is the view we expect
+ {
+ final InternalSelectionView view =
+ (InternalSelectionView) mListView.getChildAt(0);
+ assertEquals(mActivity.getLabelForPosition(0), view.getLabel());
+ }
+
+
+ }
+
+ /**
+ * @param internalFocused The view to check
+ * @param row
+ */
+ private void assertInternallySelectedRowOnScreen(
+ InternalSelectionView internalFocused,
+ int row) {
+ assertEquals("expecting selected row",
+ row, internalFocused.getSelectedRow());
+
+ internalFocused.getRectForRow(mTempRect, row);
+ mListView.offsetDescendantRectToMyCoords(internalFocused, mTempRect);
+
+ assertTrue("top of row " + row + " should be on sreen",
+ mTempRect.top >= 0);
+ assertTrue("bottom of row " + row + " should be on sreen",
+ mTempRect.bottom < mActivity.getScreenHeight());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java
new file mode 100644
index 0000000..47a81fb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/focus/VerticalFocusSearchTest.java
@@ -0,0 +1,152 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.focus;
+
+import com.android.frameworktest.focus.VerticalFocusSearch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.FocusFinder;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.LinearLayout;
+
+/**
+ * Tests that focus searching works on a vertical linear layout of buttons of
+ * various widths and horizontal placements.
+ */
+// Suppress until bug http://b/issue?id=1416545 is fixed
+@Suppress
+public class VerticalFocusSearchTest extends ActivityInstrumentationTestCase<VerticalFocusSearch> {
+
+ private LinearLayout mLayout;
+
+ private Button mTopWide;
+ private Button mMidSkinny1Left;
+ private Button mMidSkinny2Right;
+ private Button mBottomWide;
+
+ private FocusSearchAlg mFocusFinder;
+
+ // helps test old and new impls when figuring out why something that used
+ // to work doesn't anymore (or verifying that new works as well as old).
+ interface FocusSearchAlg {
+ View findNextFocus(ViewGroup root, View focused, int direction);
+ }
+
+ // calls new impl
+ static class NewFocusSearchAlg implements FocusSearchAlg {
+
+ public View findNextFocus(ViewGroup root, View focused, int direction) {
+ return FocusFinder.getInstance()
+ .findNextFocus(root, focused, direction);
+ }
+ }
+
+ public VerticalFocusSearchTest() {
+ super("com.android.frameworktest", VerticalFocusSearch.class);
+ }
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mLayout = getActivity().getLayout();
+ mTopWide = getActivity().getTopWide();
+ mMidSkinny1Left = getActivity().getMidSkinny1Left();
+ mMidSkinny2Right = getActivity().getMidSkinny2Right();
+ mBottomWide = getActivity().getBottomWide();
+
+ mFocusFinder = new NewFocusSearchAlg();
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mLayout);
+ assertNotNull(mTopWide);
+ assertNotNull(mMidSkinny1Left);
+ assertNotNull(mMidSkinny2Right);
+ assertNotNull(mBottomWide);
+ }
+
+ public void testSearchFromTopButton() {
+ assertNull("going up from mTopWide.",
+ mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_UP));
+
+ assertNull("going left from mTopWide.",
+ mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_LEFT));
+
+ assertNull("going right from mTopWide.",
+ mFocusFinder.findNextFocus(mLayout, mTopWide, View.FOCUS_RIGHT));
+
+ assertEquals("going down from mTopWide.",
+ mMidSkinny1Left,
+ mFocusFinder
+ .findNextFocus(mLayout, mTopWide, View.FOCUS_DOWN));
+ }
+
+ public void testSearchFromMidLeft() {
+ assertNull("going left should have no next focus",
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_LEFT));
+
+ assertEquals("going right from mMidSkinny1Left should go to mMidSkinny2Right",
+ mMidSkinny2Right,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_RIGHT));
+
+ assertEquals("going up from mMidSkinny1Left should go to mTopWide",
+ mTopWide,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_UP));
+
+ assertEquals("going down from mMidSkinny1Left should go to mMidSkinny2Right",
+ mMidSkinny2Right,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny1Left, View.FOCUS_DOWN));
+ }
+
+ public void testSearchFromMidRight() {
+ assertEquals("going left from mMidSkinny2Right should go to mMidSkinny1Left",
+ mMidSkinny1Left,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_LEFT));
+
+ assertNull("going right should have no next focus",
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_RIGHT));
+
+ assertEquals("going up from mMidSkinny2Right should go to mMidSkinny1Left",
+ mMidSkinny1Left,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_UP));
+
+ assertEquals("going down from mMidSkinny2Right should go to mBottomWide",
+ mBottomWide,
+ mFocusFinder.findNextFocus(mLayout, mMidSkinny2Right, View.FOCUS_DOWN));
+
+ }
+
+ public void testSearchFromFromBottom() {
+ assertNull("going down from bottom button should have no next focus.",
+ mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_DOWN));
+
+ assertNull("going left from bottom button should have no next focus.",
+ mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_LEFT));
+
+ assertNull("going right from bottom button should have no next focus.",
+ mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_RIGHT));
+
+ assertEquals("going up from bottom button should go to mMidSkinny2Right.",
+ mMidSkinny2Right,
+ mFocusFinder.findNextFocus(mLayout, mBottomWide, View.FOCUS_UP));
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java
new file mode 100644
index 0000000..8af6214
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInHorizontalTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridInHorizontal;
+
+public class GridInHorizontalTest extends ActivityInstrumentationTestCase<GridInHorizontal> {
+
+ private GridInHorizontal mActivity;
+ private GridView mGridView;
+
+ public GridInHorizontalTest() {
+ super("com.android.frameworktest", GridInHorizontal.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+ assertTrue("Grid has 0 width", mGridView.getMeasuredWidth() > 0);
+ assertTrue("Grid has 0 height", mGridView.getMeasuredHeight() > 0);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java
new file mode 100644
index 0000000..61e1c8b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridInVerticalTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridInVertical;
+
+public class GridInVerticalTest extends ActivityInstrumentationTestCase<GridInVertical> {
+
+ private GridInVertical mActivity;
+ private GridView mGridView;
+
+ public GridInVerticalTest() {
+ super("com.android.frameworktest", GridInVertical.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+ assertTrue("Grid has 0 width", mGridView.getMeasuredWidth() > 0);
+ assertTrue("Grid has 0 height", mGridView.getMeasuredHeight() > 0);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java
new file mode 100644
index 0000000..43581c6
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridPaddingTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+public class GridPaddingTest extends ActivityInstrumentationTestCase2<GridPadding> {
+ private GridView mGridView;
+
+ public GridPaddingTest() {
+ super("com.android.frameworktest", GridPadding.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ setActivityInitialTouchMode(true);
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mGridView);
+ assertTrue("Not in touch mode", mGridView.isInTouchMode());
+ }
+
+ @MediumTest
+ public void testResurrectSelection() {
+ sendKeys("DPAD_DOWN");
+ assertEquals("The first item should be selected", mGridView.getSelectedItemPosition(), 0);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java
new file mode 100644
index 0000000..f939f16
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridScrollListenerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridScrollListener;
+
+public class GridScrollListenerTest extends ActivityInstrumentationTestCase<GridScrollListener> implements
+ AbsListView.OnScrollListener {
+ private GridScrollListener mActivity;
+ private GridView mGridView;
+ private int mFirstVisibleItem = -1;
+ private int mVisibleItemCount = -1;
+ private int mTotalItemCount = -1;
+
+ public GridScrollListenerTest() {
+ super("com.android.frameworktest", GridScrollListener.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ mGridView.setOnScrollListener(this);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ assertEquals(0, mFirstVisibleItem);
+ }
+
+ @LargeTest
+ public void testKeyScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisibleItem = mFirstVisibleItem;
+ for (int i = 0; i < mVisibleItemCount * 2; i++) {
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ inst.waitForIdleSync();
+
+ assertTrue("Arrow scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+
+ firstVisibleItem = mFirstVisibleItem;
+ inst.sendCharacterSync(KeyEvent.KEYCODE_SPACE);
+ inst.waitForIdleSync();
+
+ assertTrue("Page scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+
+ firstVisibleItem = mFirstVisibleItem;
+ KeyEvent down = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+ KeyEvent up = new KeyEvent(0, 0, KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+ inst.sendKeySync(down);
+ inst.sendKeySync(up);
+ inst.waitForIdleSync();
+
+ assertTrue("Full scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+ assertEquals("Full scroll did not happen", mTotalItemCount,
+ mFirstVisibleItem + mVisibleItemCount);
+ }
+
+ @LargeTest
+ public void testTouchScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisibleItem = mFirstVisibleItem;
+ TouchUtils.dragQuarterScreenUp(this);
+ TouchUtils.dragQuarterScreenUp(this);
+ assertTrue("Touch scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+ }
+
+
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+ mFirstVisibleItem = firstVisibleItem;
+ mVisibleItemCount = visibleItemCount;
+ mTotalItemCount = totalItemCount;
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java
new file mode 100644
index 0000000..3ca9b09
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionBaseTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.util.GridScenario;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.widget.GridView;
+
+public class GridSetSelectionBaseTest<T extends GridScenario> extends ActivityInstrumentationTestCase<T> {
+ private T mActivity;
+ private GridView mGridView;
+
+ protected GridSetSelectionBaseTest(Class<T> klass) {
+ super("com.android.frameworktest", klass);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // First item should be selected
+ if (mGridView.isStackFromBottom()) {
+ assertEquals(mGridView.getAdapter().getCount() - 1,
+ mGridView.getSelectedItemPosition());
+ } else {
+ assertEquals(0, mGridView.getSelectedItemPosition());
+ }
+ }
+
+ @MediumTest
+ public void testSetSelectionToTheEnd() {
+ final int target = mGridView.getAdapter().getCount() - 1;
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mGridView.setSelection(target);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals(mGridView.getSelectedItemPosition(), target);
+ assertNotNull(mGridView.getSelectedView());
+
+ ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+ }
+
+ @MediumTest
+ public void testSetSelectionToMiddle() {
+ final int target = mGridView.getAdapter().getCount() / 2;
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mGridView.setSelection(target);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals(mGridView.getSelectedItemPosition(), target);
+ assertNotNull(mGridView.getSelectedView());
+
+ ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+ }
+
+ @MediumTest
+ public void testSetSelectionToTheTop() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mGridView.setSelection(0);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals(mGridView.getSelectedItemPosition(), 0);
+ assertNotNull(mGridView.getSelectedView());
+
+ ViewAsserts.assertOnScreen(mGridView, mGridView.getSelectedView());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java
new file mode 100644
index 0000000..aadc185
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionManyTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionMany;
+
+public class GridSetSelectionManyTest extends GridSetSelectionBaseTest<GridSetSelectionMany> {
+ public GridSetSelectionManyTest() {
+ super(GridSetSelectionMany.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java
new file mode 100644
index 0000000..831ba85
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomManyTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionStackFromBottomMany;
+
+public class GridSetSelectionStackFromBottomManyTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottomMany> {
+ public GridSetSelectionStackFromBottomManyTest() {
+ super(GridSetSelectionStackFromBottomMany.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java
new file mode 100644
index 0000000..c4d0513
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionStackFromBottomTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelectionStackFromBottom;
+
+public class GridSetSelectionStackFromBottomTest extends GridSetSelectionBaseTest<GridSetSelectionStackFromBottom> {
+ public GridSetSelectionStackFromBottomTest() {
+ super(GridSetSelectionStackFromBottom.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java
new file mode 100644
index 0000000..5a584a5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSetSelectionTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridSetSelection;
+
+public class GridSetSelectionTest extends GridSetSelectionBaseTest<GridSetSelection> {
+ public GridSetSelectionTest() {
+ super(GridSetSelection.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java
new file mode 100644
index 0000000..b72a2e0
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridSingleColumnTest.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridSingleColumn;
+
+public class GridSingleColumnTest extends ActivityInstrumentationTestCase<GridSingleColumn> {
+ private GridSingleColumn mActivity;
+ private GridView mGridView;
+
+ public GridSingleColumnTest() {
+ super("com.android.frameworktest", GridSingleColumn.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+ assertEquals(0, mGridView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java
new file mode 100644
index 0000000..a0b819e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomManyTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridStackFromBottomMany;
+
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+import android.test.ActivityInstrumentationTestCase;
+
+public class GridStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
+ private GridStackFromBottomMany mActivity;
+ private GridView mGridView;
+
+ public GridStackFromBottomManyTest() {
+ super("com.android.frameworktest", GridStackFromBottomMany.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // Last item should be selected
+ assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java
new file mode 100644
index 0000000..821c7a5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/GridStackFromBottomTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview;
+
+import com.android.frameworktest.gridview.GridStackFromBottom;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.GridView;
+
+public class GridStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
+ private GridStackFromBottom mActivity;
+ private GridView mGridView;
+
+ public GridStackFromBottomTest() {
+ super("com.android.frameworktest", GridStackFromBottom.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // Last item should be selected
+ assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java
new file mode 100644
index 0000000..926d662
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchSetSelectionTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridSimple;
+
+/**
+ * Tests setting the selection in touch mode
+ */
+public class GridTouchSetSelectionTest extends ActivityInstrumentationTestCase<GridSimple> {
+ private GridSimple mActivity;
+ private GridView mGridView;
+
+ public GridTouchSetSelectionTest() {
+ super("com.android.frameworktest", GridSimple.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+ }
+
+ @LargeTest
+ public void testSetSelection() {
+ TouchUtils.dragQuarterScreenDown(this);
+ TouchUtils.dragQuarterScreenUp(this);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ final int targetPosition = mGridView.getAdapter().getCount() / 2;
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mGridView.setSelection(targetPosition);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ boolean found = false;
+ int childCount = mGridView.getChildCount();
+ for (int i=0; i<childCount; i++) {
+ View child = mGridView.getChildAt(i);
+ if (child.getId() == targetPosition) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Selected item not visible in list", found);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java
new file mode 100644
index 0000000..710617e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomManyTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview.touch;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import com.android.frameworktest.gridview.GridStackFromBottomMany;
+
+import android.widget.GridView;
+import android.view.View;
+import android.test.ActivityInstrumentationTestCase;
+
+public class GridTouchStackFromBottomManyTest extends ActivityInstrumentationTestCase<GridStackFromBottomMany> {
+ private GridStackFromBottomMany mActivity;
+ private GridView mGridView;
+
+ public GridTouchStackFromBottomManyTest() {
+ super("com.android.frameworktest", GridStackFromBottomMany.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // Last item should be selected
+ assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testScrollToTop() {
+ View firstChild;
+ TouchUtils.scrollToTop(this, mGridView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ firstChild = mGridView.getChildAt(0);
+
+ assertEquals("Item zero not the first child in the grid", 0, firstChild.getId());
+
+ assertEquals("Item zero not at the top of the grid",
+ mGridView.getListPaddingTop(), firstChild.getTop());
+ }
+
+ @MediumTest
+ public void testScrollToBottom() {
+ TouchUtils.scrollToBottom(this, mGridView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ assertEquals("Last item is not touching the bottom edge",
+ mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java
new file mode 100644
index 0000000..e085105
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchStackFromBottomTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview.touch;
+
+import com.android.frameworktest.gridview.GridStackFromBottom;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.GridView;
+import android.view.View;
+
+public class GridTouchStackFromBottomTest extends ActivityInstrumentationTestCase<GridStackFromBottom> {
+ private GridStackFromBottom mActivity;
+ private GridView mGridView;
+
+ public GridTouchStackFromBottomTest() {
+ super("com.android.frameworktest", GridStackFromBottom.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // First item should be selected
+ assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testPushUp() {
+ TouchUtils.scrollToBottom(this, mGridView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("Last item not the last child in the grid",
+ mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+ assertEquals("Last item not at the bottom of the grid",
+ mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+ @MediumTest
+ public void testPullDown() {
+ TouchUtils.scrollToTop(this, mGridView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("Last item not the last child in the grid",
+ mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+ assertEquals("Last item not at the bottom of the grid",
+ mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+ @MediumTest
+ public void testPushUpFast() {
+ TouchUtils.dragViewToTop(this, mGridView.getChildAt(mGridView.getChildCount() - 1), 2);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("Last item not the last child in the grid",
+ mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+ assertEquals("Last item not at the bottom of the grid",
+ mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+ @MediumTest
+ public void testPullDownFast() {
+ TouchUtils.dragViewToBottom(this, mGridView.getChildAt(0), 2);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mGridView.getSelectedItemPosition());
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("Last item not the last child in the grid",
+ mGridView.getAdapter().getCount() - 1, lastChild.getId());
+
+ assertEquals("Last item not at the bottom of the grid",
+ mGridView.getHeight() - mGridView.getListPaddingBottom(), lastChild.getBottom());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
new file mode 100644
index 0000000..3937c43
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridVerticalSpacingStackFromBottom;
+
+public class GridTouchVerticalSpacingStackFromBottomTest extends ActivityInstrumentationTestCase<GridVerticalSpacingStackFromBottom> {
+ private GridVerticalSpacingStackFromBottom mActivity;
+ private GridView mGridView;
+
+ public GridTouchVerticalSpacingStackFromBottomTest() {
+ super("com.android.frameworktest", GridVerticalSpacingStackFromBottom.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ // Last item should be selected
+ assertEquals(mGridView.getAdapter().getCount() - 1, mGridView.getSelectedItemPosition());
+
+ }
+
+ @MediumTest
+ public void testNoScroll() {
+ View firstChild = mGridView.getChildAt(0);
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+ ViewConfiguration.getTouchSlop());
+
+ View newLastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("View scrolled too early", lastTop, newLastChild.getTop());
+ assertEquals("Wrong view in last position", mGridView.getAdapter().getCount() - 1,
+ newLastChild.getId());
+ }
+
+ @LargeTest
+ public void testShortScroll() {
+ View firstChild = mGridView.getChildAt(0);
+ if (firstChild.getTop() < this.mGridView.getListPaddingTop()) {
+ firstChild = mGridView.getChildAt(1);
+ }
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+ ViewConfiguration.getTouchSlop() + 1 + 10);
+
+ View newLastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ assertEquals("View scrolled to wrong position", lastTop, newLastChild.getTop() - 10);
+ assertEquals("Wrong view in last position", mGridView.getAdapter().getCount() - 1,
+ newLastChild.getId());
+ }
+
+ @LargeTest
+ public void testLongScroll() {
+ View firstChild = mGridView.getChildAt(0);
+ if (firstChild.getTop() < mGridView.getListPaddingTop()) {
+ firstChild = mGridView.getChildAt(1);
+ }
+
+ int firstTop = firstChild.getTop();
+
+ int distance = TouchUtils.dragViewBy(this, firstChild,
+ Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+ (int) (mActivity.getWindowManager().getDefaultDisplay().getHeight() * 0.75f));
+
+ assertEquals("View scrolled to wrong position", firstTop
+ + (distance - ViewConfiguration.getTouchSlop() - 1), firstChild.getTop());
+ }
+
+ @LargeTest
+ public void testManyScrolls() {
+ int originalCount = mGridView.getChildCount();
+
+ View firstChild;
+ int firstId = Integer.MIN_VALUE;
+ int firstTop = Integer.MIN_VALUE;
+ int prevId;
+ int prevTop;
+ do {
+ prevId = firstId;
+ prevTop = firstTop;
+ TouchUtils.dragQuarterScreenDown(this);
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mGridView.getChildCount(), originalCount + 4),
+ mGridView.getChildCount() <= originalCount + 4);
+ firstChild = mGridView.getChildAt(0);
+ firstId = firstChild.getId();
+ firstTop = firstChild.getTop();
+ } while ((prevId != firstId) || (prevTop != firstTop));
+
+
+ firstChild = mGridView.getChildAt(0);
+ assertEquals("View scrolled to wrong position", 0, firstChild.getId());
+
+ firstId = Integer.MIN_VALUE;
+ firstTop = Integer.MIN_VALUE;
+ do {
+ prevId = firstId;
+ prevTop = firstTop;
+ TouchUtils.dragQuarterScreenUp(this);
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mGridView.getChildCount(), originalCount + 4),
+ mGridView.getChildCount() <= originalCount + 4);
+ firstChild = mGridView.getChildAt(0);
+ firstId = firstChild.getId();
+ firstTop = firstChild.getTop();
+ } while ((prevId != firstId) || (prevTop != firstTop));
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+ assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+ lastChild.getId());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java
new file mode 100644
index 0000000..0b39909
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/gridview/touch/GridTouchVerticalSpacingTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.gridview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.GridView;
+
+import com.android.frameworktest.gridview.GridVerticalSpacing;
+
+public class GridTouchVerticalSpacingTest extends ActivityInstrumentationTestCase<GridVerticalSpacing> {
+ private GridVerticalSpacing mActivity;
+ private GridView mGridView;
+
+ public GridTouchVerticalSpacingTest() {
+ super("com.android.frameworktest", GridVerticalSpacing.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mGridView = getActivity().getGridView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mGridView);
+
+ assertEquals(0, mGridView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testNoScroll() {
+ View firstChild = mGridView.getChildAt(0);
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ int firstTop = firstChild.getTop();
+
+ TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ 0, -(ViewConfiguration.getTouchSlop()));
+
+ View newFirstChild = mGridView.getChildAt(0);
+
+ assertEquals("View scrolled too early", firstTop, newFirstChild.getTop());
+ assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+ }
+
+ @LargeTest
+ public void testShortScroll() {
+ View firstChild = mGridView.getChildAt(0);
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ int firstTop = firstChild.getTop();
+
+ TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ 0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+
+ View newFirstChild = mGridView.getChildAt(0);
+
+ assertEquals("View scrolled to wrong position", firstTop, newFirstChild.getTop() + 10);
+ assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+ }
+
+ @LargeTest
+ public void testLongScroll() {
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ int distance = TouchUtils.dragViewToY(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ mGridView.getTop());
+
+ assertEquals("View scrolled to wrong position",
+ lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+ }
+
+ @LargeTest
+ public void testManyScrolls() {
+ int originalCount = mGridView.getChildCount();
+
+ View firstChild;
+ int firstId = Integer.MIN_VALUE;
+ int firstTop = Integer.MIN_VALUE;
+ int prevId;
+ int prevTop;
+ do {
+ prevId = firstId;
+ prevTop = firstTop;
+ TouchUtils.dragQuarterScreenUp(this);
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mGridView.getChildCount(), originalCount + 4),
+ mGridView.getChildCount() <= originalCount + 4);
+ firstChild = mGridView.getChildAt(0);
+ firstId = firstChild.getId();
+ firstTop = firstChild.getTop();
+ } while ((prevId != firstId) || (prevTop != firstTop));
+
+
+ View lastChild = mGridView.getChildAt(mGridView.getChildCount() - 1);
+ assertEquals("Grid is not scrolled to the bottom", mGridView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ firstId = Integer.MIN_VALUE;
+ firstTop = Integer.MIN_VALUE;
+ do {
+ prevId = firstId;
+ prevTop = firstTop;
+ TouchUtils.dragQuarterScreenDown(this);
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mGridView.getChildCount(), originalCount + 4),
+ mGridView.getChildCount() <= originalCount + 4);
+ firstChild = mGridView.getChildAt(0);
+ firstId = firstChild.getId();
+ firstTop = firstChild.getTop();
+ } while ((prevId != firstId) || (prevTop != firstTop));
+
+ firstChild = mGridView.getChildAt(0);
+ assertEquals("Grid is not scrolled to the top", 0, firstChild.getId());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java
new file mode 100644
index 0000000..239bd7d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutGravityTest.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.frame;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.app.Activity;
+import android.view.View;
+import com.android.frameworktest.layout.frame.FrameLayoutGravity;
+import com.android.frameworktest.R;
+
+public class FrameLayoutGravityTest extends ActivityInstrumentationTestCase<FrameLayoutGravity> {
+ private View mLeftView;
+ private View mRightView;
+ private View mCenterHorizontalView;
+ private View mLeftCenterVerticalView;
+ private View mRighCenterVerticalView;
+ private View mCenterView;
+ private View mLeftBottomView;
+ private View mRightBottomView;
+ private View mCenterHorizontalBottomView;
+ private View mParent;
+
+ public FrameLayoutGravityTest() {
+ super("com.android.frameworktest", FrameLayoutGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+
+ mParent = activity.findViewById(R.id.parent);
+
+ mLeftView = activity.findViewById(R.id.left);
+ mRightView = activity.findViewById(R.id.right);
+ mCenterHorizontalView = activity.findViewById(R.id.center_horizontal);
+
+ mLeftCenterVerticalView = activity.findViewById(R.id.left_center_vertical);
+ mRighCenterVerticalView = activity.findViewById(R.id.right_center_vertical);
+ mCenterView = activity.findViewById(R.id.center);
+
+ mLeftBottomView = activity.findViewById(R.id.left_bottom);
+ mRightBottomView = activity.findViewById(R.id.right_bottom);
+ mCenterHorizontalBottomView = activity.findViewById(R.id.center_horizontal_bottom);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mParent);
+ assertNotNull(mLeftView);
+ assertNotNull(mRightView);
+ assertNotNull(mCenterHorizontalView);
+ assertNotNull(mLeftCenterVerticalView);
+ assertNotNull(mRighCenterVerticalView);
+ assertNotNull(mCenterView);
+ assertNotNull(mLeftBottomView);
+ assertNotNull(mRightBottomView);
+ assertNotNull(mCenterHorizontalBottomView);
+ }
+
+ @MediumTest
+ public void testLeftTopAligned() throws Exception {
+ ViewAsserts.assertLeftAligned(mParent, mLeftView);
+ ViewAsserts.assertTopAligned(mParent, mLeftView);
+ }
+
+ @MediumTest
+ public void testRightTopAligned() throws Exception {
+ ViewAsserts.assertRightAligned(mParent, mRightView);
+ ViewAsserts.assertTopAligned(mParent, mRightView);
+ }
+
+ @MediumTest
+ public void testCenterHorizontalTopAligned() throws Exception {
+ ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterHorizontalView);
+ ViewAsserts.assertTopAligned(mParent, mCenterHorizontalView);
+ }
+
+ @MediumTest
+ public void testLeftCenterVerticalAligned() throws Exception {
+ ViewAsserts.assertLeftAligned(mParent, mLeftCenterVerticalView);
+ ViewAsserts.assertVerticalCenterAligned(mParent, mLeftCenterVerticalView);
+ }
+
+ @MediumTest
+ public void testRightCenterVerticalAligned() throws Exception {
+ ViewAsserts.assertRightAligned(mParent, mRighCenterVerticalView);
+ ViewAsserts.assertVerticalCenterAligned(mParent, mRighCenterVerticalView);
+ }
+
+ @MediumTest
+ public void testCenterAligned() throws Exception {
+ ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterView);
+ ViewAsserts.assertVerticalCenterAligned(mParent, mCenterView);
+ }
+
+ @MediumTest
+ public void testLeftBottomAligned() throws Exception {
+ ViewAsserts.assertLeftAligned(mParent, mLeftBottomView);
+ ViewAsserts.assertBottomAligned(mParent, mLeftBottomView);
+ }
+
+ @MediumTest
+ public void testRightBottomAligned() throws Exception {
+ ViewAsserts.assertRightAligned(mParent, mRightBottomView);
+ ViewAsserts.assertBottomAligned(mParent, mRightBottomView);
+ }
+
+ @MediumTest
+ public void testCenterHorizontalBottomAligned() throws Exception {
+ ViewAsserts.assertHorizontalCenterAligned(mParent, mCenterHorizontalBottomView);
+ ViewAsserts.assertBottomAligned(mParent, mCenterHorizontalBottomView);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java
new file mode 100644
index 0000000..4df4805
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/frame/FrameLayoutMarginTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.frame;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.app.Activity;
+import android.view.View;
+import android.view.ViewGroup;
+import com.android.frameworktest.layout.frame.FrameLayoutMargin;
+import com.android.frameworktest.R;
+
+public class FrameLayoutMarginTest extends ActivityInstrumentationTestCase<FrameLayoutMargin> {
+ private View mLeftView;
+ private View mRightView;
+ private View mTopView;
+ private View mBottomView;
+ private View mParent;
+
+ public FrameLayoutMarginTest() {
+ super("com.android.frameworktest", FrameLayoutMargin.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+
+ mParent = activity.findViewById(R.id.parent);
+
+ mLeftView = activity.findViewById(R.id.left);
+ mRightView = activity.findViewById(R.id.right);
+ mTopView = activity.findViewById(R.id.top);
+ mBottomView = activity.findViewById(R.id.bottom);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mParent);
+ assertNotNull(mLeftView);
+ assertNotNull(mRightView);
+ assertNotNull(mTopView);
+ assertNotNull(mBottomView);
+ }
+
+ @MediumTest
+ public void testLeftMarginAligned() throws Exception {
+ ViewAsserts.assertLeftAligned(mParent, mLeftView,
+ ((ViewGroup.MarginLayoutParams) mLeftView.getLayoutParams()).leftMargin);
+ }
+
+ @MediumTest
+ public void testRightMarginAligned() throws Exception {
+ ViewAsserts.assertRightAligned(mParent, mRightView,
+ ((ViewGroup.MarginLayoutParams) mRightView.getLayoutParams()).rightMargin);
+ }
+
+ @MediumTest
+ public void testTopMarginAligned() throws Exception {
+ ViewAsserts.assertTopAligned(mParent, mTopView,
+ ((ViewGroup.MarginLayoutParams) mTopView.getLayoutParams()).topMargin);
+ }
+
+ @MediumTest
+ public void testBottomMarginAligned() throws Exception {
+ ViewAsserts.assertBottomAligned(mParent, mBottomView,
+ ((ViewGroup.MarginLayoutParams) mBottomView.getLayoutParams()).bottomMargin);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java
new file mode 100644
index 0000000..0b6360e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentCenterGravityTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+import android.widget.Button;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineAlignmentCenterGravity;
+
+public class BaselineAlignmentCenterGravityTest extends ActivityInstrumentationTestCase<BaselineAlignmentCenterGravity> {
+ private Button mButton1;
+ private Button mButton2;
+ private Button mButton3;
+
+ public BaselineAlignmentCenterGravityTest() {
+ super("com.android.frameworktest", BaselineAlignmentCenterGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mButton1 = (Button) activity.findViewById(R.id.button1);
+ mButton2 = (Button) activity.findViewById(R.id.button2);
+ mButton3 = (Button) activity.findViewById(R.id.button3);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mButton1);
+ assertNotNull(mButton2);
+ assertNotNull(mButton3);
+ }
+
+ @MediumTest
+ public void testChildrenAligned() throws Exception {
+ final View parent = (View) mButton1.getParent();
+ ViewAsserts.assertTopAligned(mButton1, parent);
+ ViewAsserts.assertTopAligned(mButton2, parent);
+ ViewAsserts.assertTopAligned(mButton3, parent);
+ ViewAsserts.assertBottomAligned(mButton1, parent);
+ ViewAsserts.assertBottomAligned(mButton2, parent);
+ ViewAsserts.assertBottomAligned(mButton3, parent);
+ ViewAsserts.assertTopAligned(mButton1, mButton2);
+ ViewAsserts.assertTopAligned(mButton2, mButton3);
+ ViewAsserts.assertBottomAligned(mButton1, mButton2);
+ ViewAsserts.assertBottomAligned(mButton2, mButton3);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java
new file mode 100644
index 0000000..050e053
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentSpinnerButton.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.HorizontalOrientationVerticalAlignment;
+
+public class BaselineAlignmentSpinnerButton extends ActivityInstrumentationTestCase<HorizontalOrientationVerticalAlignment> {
+ private View mSpinner;
+ private View mButton;
+
+ public BaselineAlignmentSpinnerButton() {
+ super("com.android.frameworktest", HorizontalOrientationVerticalAlignment.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mSpinner = activity.findViewById(R.id.reminder_value);
+ mButton = activity.findViewById(R.id.reminder_remove);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mSpinner);
+ assertNotNull(mButton);
+ }
+
+ @MediumTest
+ public void testChildrenAligned() throws Exception {
+ ViewAsserts.assertBaselineAligned(mSpinner, mButton);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
new file mode 100644
index 0000000..a315d81
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineAlignmentZeroWidthAndWeightTest.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineAlignmentZeroWidthAndWeight;
+import com.android.frameworktest.layout.linear.ExceptionTextView;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+public class BaselineAlignmentZeroWidthAndWeightTest extends ActivityInstrumentationTestCase<BaselineAlignmentZeroWidthAndWeight> {
+ private Button mShowButton;
+
+ public BaselineAlignmentZeroWidthAndWeightTest() {
+ super("com.android.frameworktest", BaselineAlignmentZeroWidthAndWeight.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mShowButton = (Button) activity.findViewById(R.id.show);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mShowButton);
+ }
+
+ @MediumTest
+ public void testComputeTexViewWithoutIllegalArgumentException() throws Exception {
+ assertTrue(mShowButton.hasFocus());
+
+ // Pressing the button will show an ExceptionTextView that might set a failed bit if
+ // the test fails.
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+
+ final ExceptionTextView etv = (ExceptionTextView) getActivity()
+ .findViewById(R.id.routeToField);
+ assertFalse("exception test view should not fail", etv.isFailed());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java
new file mode 100644
index 0000000..9f2e138
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/BaselineButtonsTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.BaselineButtons;
+
+public class BaselineButtonsTest extends ActivityInstrumentationTestCase<BaselineButtons> {
+ private View mCurrentTime;
+ private View mTotalTime;
+ private ImageButton mPrev;
+ private ImageButton mNext;
+ private ImageButton mPause;
+ private View mLayout;
+
+ public BaselineButtonsTest() {
+ super("com.android.frameworktest", BaselineButtons.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mCurrentTime = activity.findViewById(R.id.currenttime);
+ mTotalTime = activity.findViewById(R.id.totaltime);
+ mPrev = (ImageButton) activity.findViewById(R.id.prev);
+ mNext = (ImageButton) activity.findViewById(R.id.next);
+ mPause = (ImageButton) activity.findViewById(R.id.pause);
+ mLayout = activity.findViewById(R.id.layout);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mCurrentTime);
+ assertNotNull(mTotalTime);
+ assertNotNull(mPrev);
+ assertNotNull(mNext);
+ assertNotNull(mPause);
+ assertNotNull(mLayout);
+ }
+
+ @MediumTest
+ public void testLayout() {
+ int pauseHeight = Math.max(mPause.getDrawable().getIntrinsicHeight()
+ + mPause.getPaddingTop() + mPause.getPaddingBottom(),
+ mPause.getBackground().getMinimumHeight());
+ int prevHeight = Math.max(mPrev.getDrawable().getIntrinsicHeight() + mPrev.getPaddingTop()
+ + mPrev.getPaddingBottom(),
+ mPrev.getBackground().getMinimumHeight());
+ int nextHeight = Math.max(mNext.getDrawable().getIntrinsicHeight() + mNext.getPaddingTop()
+ + mNext.getPaddingBottom(),
+ mNext.getBackground().getMinimumHeight());
+ assertEquals("Layout incorrect height", pauseHeight, mLayout.getHeight());
+ assertEquals("Pause incorrect height", pauseHeight, mPause.getHeight());
+ assertEquals("Prev incorrect height", prevHeight, mPrev.getHeight());
+ assertEquals("Next incorrect height", nextHeight, mNext.getHeight());
+ assertEquals("Pause wrong top", 0, mPause.getTop());
+ assertEquals("Prev wrong top", (pauseHeight - prevHeight) / 2, mPrev.getTop());
+ assertEquals("Next wrong top", (pauseHeight - nextHeight) / 2, mNext.getTop());
+ assertEquals("CurrentTime wrong bottom", pauseHeight, mCurrentTime.getBottom());
+ assertEquals("TotalTime wrong bottom", pauseHeight, mTotalTime.getBottom());
+ assertTrue("CurrentTime too tall", mCurrentTime.getTop() > 0);
+ assertTrue("TotalTime too tall", mTotalTime.getTop() > 0);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java
new file mode 100644
index 0000000..0e7a4a0
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/FillInWrapTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+import com.android.frameworktest.R;
+
+public class FillInWrapTest extends ActivityInstrumentationTestCase<FillInWrap> {
+ private View mChild;
+ private View mContainer;
+
+ public FillInWrapTest() {
+ super("com.android.frameworktest", FillInWrap.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mChild = activity.findViewById(R.id.data);
+ mContainer = activity.findViewById(R.id.layout);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mChild);
+ assertNotNull(mContainer);
+ }
+
+ @MediumTest
+ public void testLayout() {
+ assertTrue("the child's height should be less than the parent's",
+ mChild.getMeasuredHeight() < mContainer.getMeasuredHeight());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java
new file mode 100644
index 0000000..9dde62c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/LinearLayoutEditTextsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import com.android.frameworktest.layout.linear.LinearLayoutEditTexts;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.app.Activity;
+
+public class LinearLayoutEditTextsTest extends ActivityInstrumentationTestCase<LinearLayoutEditTexts> {
+ private View mChild;
+ private View mContainer;
+
+ public LinearLayoutEditTextsTest() {
+ super("com.android.frameworktest", LinearLayoutEditTexts.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mChild = activity.findViewById(R.id.editText1);
+ mContainer = activity.findViewById(R.id.layout);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mChild);
+ assertNotNull(mContainer);
+ }
+
+ @MediumTest
+ public void testLayout() {
+ final int childHeight = mChild.getHeight();
+ final int containerHeight = mContainer.getHeight();
+
+ assertEquals(containerHeight, childHeight);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java
new file mode 100644
index 0000000..a51743b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightSumTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.WeightSum;
+
+public class WeightSumTest extends ActivityInstrumentationTestCase<WeightSum> {
+ private View mChild;
+ private View mContainer;
+
+ public WeightSumTest() {
+ super("com.android.frameworktest", WeightSum.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mChild = activity.findViewById(R.id.child);
+ mContainer = activity.findViewById(R.id.container);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mChild);
+ assertNotNull(mContainer);
+ }
+
+ @MediumTest
+ public void testLayout() {
+ final int childWidth = mChild.getWidth();
+ final int containerWidth = mContainer.getWidth();
+
+ assertEquals(containerWidth / 2, childWidth);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java
new file mode 100644
index 0000000..f7fec78
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/linear/WeightTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.linear;
+
+import android.app.Activity;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.layout.linear.Weight;
+
+public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
+ private View mChild;
+ private View mContainer;
+
+ public WeightTest() {
+ super("com.android.frameworktest", Weight.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Activity activity = getActivity();
+ mChild = activity.findViewById(R.id.child4);
+ mContainer = activity.findViewById(R.id.layout);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mChild);
+ assertNotNull(mContainer);
+ }
+
+ @MediumTest
+ public void testLayout() {
+ ViewAsserts.assertRightAligned(mChild, mContainer);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java
new file mode 100644
index 0000000..9d713c8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/AddColumnTest.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.AddColumn;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.TableLayout;
+import android.widget.TableRow;
+
+/**
+ * {@link com.android.frameworktest.layout.table.AddColumn} is
+ * setup to exercise the case of adding row programmatically in a table.
+ */
+public class AddColumnTest extends ActivityInstrumentationTestCase<AddColumn> {
+ private Button mAddRow;
+ private TableLayout mTable;
+
+ public AddColumnTest() {
+ super("com.android.frameworktest", AddColumn.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final AddColumn activity = getActivity();
+ mAddRow = (Button) activity.findViewById(R.id.add_row_button);
+ mTable = (TableLayout) activity.findViewById(R.id.table);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mAddRow);
+ assertNotNull(mTable);
+ assertTrue(mAddRow.hasFocus());
+ }
+
+ @MediumTest
+ public void testWidths() throws Exception {
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+
+ TableRow row1 = (TableRow) mTable.getChildAt(0);
+ TableRow row2 = (TableRow) mTable.getChildAt(1);
+
+ assertTrue(row1.getChildCount() < row2.getChildCount());
+
+ for (int i = 0; i < row1.getChildCount(); i++) {
+ assertEquals(row2.getChildAt(i).getWidth(), row1.getChildAt(i).getWidth());
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java
new file mode 100644
index 0000000..85f9c2c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/CellSpanTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.CellSpan;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.CellSpan} is
+ * setup to exercise tables in which cells use spanning.
+ */
+public class CellSpanTest extends ActivityInstrumentationTestCase<CellSpan> {
+ private View mA;
+ private View mB;
+ private View mC;
+ private View mSpanThenCell;
+ private View mCellThenSpan;
+ private View mSpan;
+
+ public CellSpanTest() {
+ super("com.android.frameworktest", CellSpan.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final CellSpan activity = getActivity();
+ mA = activity.findViewById(R.id.a);
+ mB = activity.findViewById(R.id.b);
+ mC = activity.findViewById(R.id.c);
+ mSpanThenCell = activity.findViewById(R.id.spanThenCell);
+ mCellThenSpan = activity.findViewById(R.id.cellThenSpan);
+ mSpan = activity.findViewById(R.id.span);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mA);
+ assertNotNull(mB);
+ assertNotNull(mC);
+ assertNotNull(mSpanThenCell);
+ assertNotNull(mCellThenSpan);
+ assertNotNull(mSpan);
+ }
+
+ @MediumTest
+ public void testSpanThenCell() throws Exception {
+ int spanWidth = mA.getMeasuredWidth() + mB.getMeasuredWidth();
+ assertEquals("span followed by cell is broken", spanWidth,
+ mSpanThenCell.getMeasuredWidth());
+ }
+
+ @MediumTest
+ public void testCellThenSpan() throws Exception {
+ int spanWidth = mB.getMeasuredWidth() + mC.getMeasuredWidth();
+ assertEquals("cell followed by span is broken", spanWidth,
+ mCellThenSpan.getMeasuredWidth());
+ }
+
+ @MediumTest
+ public void testSpan() throws Exception {
+ int spanWidth = mA.getMeasuredWidth() + mB.getMeasuredWidth() +
+ mC.getMeasuredWidth();
+ assertEquals("span is broken", spanWidth, mSpan.getMeasuredWidth());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java
new file mode 100644
index 0000000..a54d503
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/FixedWidthTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.FixedWidth;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.FixedWidth} is
+ * setup to exercise tables in which cells use fixed width and height.
+ */
+public class FixedWidthTest extends ActivityInstrumentationTestCase<FixedWidth> {
+ private View mFixedWidth;
+ private View mFixedHeight;
+ private View mNonFixedWidth;
+
+ public FixedWidthTest() {
+ super("com.android.frameworktest", FixedWidth.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final FixedWidth activity = getActivity();
+ mFixedWidth = activity.findViewById(R.id.fixed_width);
+ mNonFixedWidth = activity.findViewById(R.id.non_fixed_width);
+ mFixedHeight = activity.findViewById(R.id.fixed_height);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mFixedWidth);
+ assertNotNull(mFixedHeight);
+ assertNotNull(mNonFixedWidth);
+ }
+
+ @MediumTest
+ public void testFixedWidth() throws Exception {
+ assertEquals(150, mFixedWidth.getWidth());
+ assertEquals(mFixedWidth.getWidth(), mNonFixedWidth.getWidth());
+ }
+
+ @MediumTest
+ public void testFixedHeight() throws Exception {
+ assertEquals(48, mFixedHeight.getHeight());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java
new file mode 100644
index 0000000..1355cb3
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/HorizontalGravityTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.HorizontalGravity;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.HorizontalGravity} is
+ * setup to exercise tables in which cells use horizontal gravity.
+ */
+public class HorizontalGravityTest extends ActivityInstrumentationTestCase<HorizontalGravity> {
+ private View mReference;
+ private View mCenter;
+ private View mBottomRight;
+ private View mLeft;
+
+ public HorizontalGravityTest() {
+ super("com.android.frameworktest", HorizontalGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final HorizontalGravity activity = getActivity();
+ mReference = activity.findViewById(R.id.reference);
+ mCenter = activity.findViewById(R.id.center);
+ mBottomRight = activity.findViewById(R.id.bottomRight);
+ mLeft = activity.findViewById(R.id.left);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mReference);
+ assertNotNull(mCenter);
+ assertNotNull(mBottomRight);
+ assertNotNull(mLeft);
+ }
+
+ @MediumTest
+ public void testCenterGravity() throws Exception {
+ ViewAsserts.assertHorizontalCenterAligned(mReference, mCenter);
+ }
+
+ @MediumTest
+ public void testLeftGravity() throws Exception {
+ ViewAsserts.assertLeftAligned(mReference, mLeft);
+ }
+
+ @MediumTest
+ public void testRightGravity() throws Exception {
+ ViewAsserts.assertRightAligned(mReference, mBottomRight);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
new file mode 100644
index 0000000..de3e68b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/VerticalGravityTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.VerticalGravity;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.VerticalGravity} is
+ * setup to exercise tables in which cells use vertical gravity.
+ */
+public class VerticalGravityTest extends ActivityInstrumentationTestCase<VerticalGravity> {
+ private View mReference1;
+ private View mReference2;
+ private View mReference3;
+ private View mTop;
+ private View mCenter;
+ private View mBottom;
+
+ public VerticalGravityTest() {
+ super("com.android.frameworktest", VerticalGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final VerticalGravity activity = getActivity();
+ mReference1 = activity.findViewById(R.id.reference1);
+ mReference2 = activity.findViewById(R.id.reference2);
+ mReference3 = activity.findViewById(R.id.reference3);
+ mTop = activity.findViewById(R.id.cell_top);
+ mCenter = activity.findViewById(R.id.cell_center);
+ mBottom = activity.findViewById(R.id.cell_bottom);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mReference1);
+ assertNotNull(mReference2);
+ assertNotNull(mReference3);
+ assertNotNull(mTop);
+ assertNotNull(mCenter);
+ assertNotNull(mBottom);
+ }
+
+ @MediumTest
+ public void testTopGravity() throws Exception {
+ ViewAsserts.assertTopAligned(mReference1, mTop);
+ }
+
+ @MediumTest
+ public void testCenterGravity() throws Exception {
+ ViewAsserts.assertVerticalCenterAligned(mReference2, mCenter);
+ }
+
+ @MediumTest
+ public void testBottomGravity() throws Exception {
+ ViewAsserts.assertBottomAligned(mReference3, mBottom);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java
new file mode 100644
index 0000000..9e20686
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/layout/table/WeightTest.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.layout.table;
+
+import com.android.frameworktest.layout.table.Weight;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+
+/**
+ * {@link com.android.frameworktest.layout.table.Weight} is
+ * setup to exercise tables in which cells use a weight.
+ */
+public class WeightTest extends ActivityInstrumentationTestCase<Weight> {
+ private View mCell1;
+ private View mCell2;
+ private View mCell3;
+ private View mRow;
+
+ public WeightTest() {
+ super("com.android.frameworktest", Weight.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ final Weight activity = getActivity();
+ mCell1 = activity.findViewById(R.id.cell1);
+ mCell3 = activity.findViewById(R.id.cell2);
+ mCell2 = activity.findViewById(R.id.cell3);
+ mRow = activity.findViewById(R.id.row);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mCell1);
+ assertNotNull(mCell2);
+ assertNotNull(mCell3);
+ assertNotNull(mRow);
+ }
+
+ @MediumTest
+ public void testAllCellsFillParent() throws Exception {
+ assertEquals(mCell1.getWidth() + mCell2.getWidth() + mCell3.getWidth(), mRow.getWidth());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java
new file mode 100644
index 0000000..d36e343
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityManyTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravityMany;
+
+public class ListBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
+ private ListBottomGravityMany mActivity;
+ private ListView mListView;
+
+ public ListBottomGravityManyTest() {
+ super("com.android.frameworktest", ListBottomGravityMany.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // Last item should be selected
+ assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java
new file mode 100644
index 0000000..79556cf
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListBottomGravityTest.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravity;
+
+public class ListBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
+ private ListBottomGravity mActivity;
+ private ListView mListView;
+
+ public ListBottomGravityTest() {
+ super("com.android.frameworktest", ListBottomGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // Last item should be selected
+ assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java
new file mode 100644
index 0000000..ca12154
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListEmptyViewTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.content.Intent;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+
+public class ListEmptyViewTest extends ActivityInstrumentationTestCase<ListWithEmptyView> {
+ private ListWithEmptyView mActivity;
+ private ListView mListView;
+
+
+ public ListEmptyViewTest() {
+ super("com.android.frameworktest", ListWithEmptyView.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ assertTrue("Empty view not shown", mListView.getVisibility() == View.GONE);
+ }
+
+ @MediumTest
+ public void testZeroToOne() {
+ Instrumentation inst = getInstrumentation();
+
+ inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+ inst.waitForIdleSync();
+ assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+ assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+ }
+
+ @MediumTest
+ public void testZeroToOneForwardBack() {
+ Instrumentation inst = getInstrumentation();
+
+ inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+ inst.waitForIdleSync();
+ assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+ assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+
+ // Navigate forward
+ Intent intent = new Intent();
+ intent.setClass(mActivity, ListWithEmptyView.class);
+ mActivity.startActivity(intent);
+
+ // Navigate backward
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+ assertTrue("Empty view still shown", mActivity.getEmptyView().getVisibility() == View.GONE);
+ assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+
+ }
+
+ @LargeTest
+ public void testZeroToManyToZero() {
+ Instrumentation inst = getInstrumentation();
+
+ int i;
+
+ for (i = 0; i < 10; i++) {
+ inst.invokeMenuActionSync(mActivity, mActivity.MENU_ADD, 0);
+ inst.waitForIdleSync();
+ assertTrue("Empty view still shown",
+ mActivity.getEmptyView().getVisibility() == View.GONE);
+ assertTrue("List not shown", mActivity.getListView().getVisibility() == View.VISIBLE);
+ }
+
+ for (i = 0; i < 10; i++) {
+ inst.invokeMenuActionSync(mActivity, mActivity.MENU_REMOVE, 0);
+ inst.waitForIdleSync();
+ if (i < 9) {
+ assertTrue("Empty view still shown",
+ mActivity.getEmptyView().getVisibility() == View.GONE);
+ assertTrue("List not shown",
+ mActivity.getListView().getVisibility() == View.VISIBLE);
+ } else {
+ assertTrue("Empty view not shown",
+ mActivity.getEmptyView().getVisibility() == View.VISIBLE);
+ assertTrue("List still shown",
+ mActivity.getListView().getVisibility() == View.GONE);
+ }
+ }
+
+ // Navigate forward
+ Intent intent = new Intent();
+ intent.setClass(mActivity, ListWithEmptyView.class);
+ mActivity.startActivity(intent);
+
+ // Navigate backward
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+ assertTrue("Empty view not shown", mActivity.getEmptyView().getVisibility() == View.VISIBLE);
+ assertTrue("List still shown", mActivity.getListView().getVisibility() == View.GONE);
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java
new file mode 100644
index 0000000..1bb1f1c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListFocusableTest.java
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.widget.ListAdapter;
+import android.widget.ArrayAdapter;
+
+public class ListFocusableTest extends ActivityInstrumentationTestCase<ListTopGravity> {
+ private ListTopGravity mActivity;
+ private ListView mListView;
+
+ public ListFocusableTest() {
+ super("com.android.frameworktest", ListTopGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // First item should be selected
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testAdapterFull() {
+ setFullAdapter();
+ assertTrue(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterEmpty() {
+ setEmptyAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterNull() {
+ setNullAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterFullSetFocusable() {
+ assertTrue(mListView.isFocusable());
+
+ setFocusable();
+ assertTrue(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterFullSetNonFocusable() {
+ assertTrue(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterEmptySetFocusable() {
+ setEmptyAdapter();
+ assertFalse(mListView.isFocusable());
+
+ setFocusable();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterEmptySetNonFocusable() {
+ setEmptyAdapter();
+ assertFalse(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterNullSetFocusable() {
+ setNullAdapter();
+ assertFalse(mListView.isFocusable());
+
+ setFocusable();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testAdapterNullSetNonFocusable() {
+ setNullAdapter();
+ assertFalse(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testFocusableSetAdapterFull() {
+ assertTrue(mListView.isFocusable());
+
+ setFullAdapter();
+ assertTrue(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testNonFocusableSetAdapterFull() {
+ assertTrue(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+
+ setFullAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testFocusableSetAdapterEmpty() {
+ assertTrue(mListView.isFocusable());
+
+ setEmptyAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testNonFocusableSetAdapterEmpty() {
+ assertTrue(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+
+ setEmptyAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testFocusableSetAdapterNull() {
+ assertTrue(mListView.isFocusable());
+
+ setNullAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ @MediumTest
+ public void testNonFocusableSetAdapterNull() {
+ assertTrue(mListView.isFocusable());
+
+ setNonFocusable();
+ assertFalse(mListView.isFocusable());
+
+ setNullAdapter();
+ assertFalse(mListView.isFocusable());
+ }
+
+ private ListAdapter createFullAdapter() {
+ return new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
+ new String[] { "Android", "Robot" });
+ }
+
+ private ListAdapter createEmptyAdapter() {
+ return new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1,
+ new String[] { });
+ }
+
+
+ private void setFullAdapter() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setAdapter(createFullAdapter());
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void setEmptyAdapter() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setAdapter(createEmptyAdapter());
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void setNullAdapter() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setAdapter(null);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void setFocusable() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setFocusable(true);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+
+ private void setNonFocusable() {
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setFocusable(false);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java
new file mode 100644
index 0000000..0e48993
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListHeterogeneousTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListHeterogeneous;
+
+public class ListHeterogeneousTest extends ActivityInstrumentationTestCase<ListHeterogeneous> {
+ private ListHeterogeneous mActivity;
+ private ListView mListView;
+
+
+ public ListHeterogeneousTest() {
+ super("com.android.frameworktest", ListHeterogeneous.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ @LargeTest
+ public void testKeyScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int count = mListView.getAdapter().getCount();
+
+
+ for (int i = 0; i < count - 1; i++) {
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ inst.waitForIdleSync();
+ int convertMissesBefore = mActivity.getConvertMisses();
+
+ assertEquals("Unexpected convert misses", 0, convertMissesBefore);
+
+ for (int i = 0; i < count - 1; i++) {
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ inst.waitForIdleSync();
+ int convertMissesAfter = mActivity.getConvertMisses();
+
+ assertEquals("Unexpected convert misses", 0, convertMissesAfter);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java
new file mode 100644
index 0000000..1432576
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInHorizontalTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListInHorizontal;
+
+public class ListInHorizontalTest extends ListUnspecifiedMeasure<ListInHorizontal> {
+ public ListInHorizontalTest() {
+ super(ListInHorizontal.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java
new file mode 100644
index 0000000..73078b9
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListInVerticalTest.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListInVertical;
+
+public class ListInVerticalTest extends ListUnspecifiedMeasure<ListInVertical> {
+ public ListInVerticalTest() {
+ super(ListInVertical.class);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java
new file mode 100644
index 0000000..16c4d39
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListItemRequestRectAboveThinFirstItemTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfThinItems;
+
+public class ListItemRequestRectAboveThinFirstItemTest
+ extends ActivityInstrumentationTestCase<ListOfThinItems> {
+ private ListView mListView;
+
+ public ListItemRequestRectAboveThinFirstItemTest() {
+ super("com.android.frameworktest", ListOfThinItems.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+
+ assertTrue("first child needs to be within fading edge height",
+ mListView.getChildAt(0).getBottom() < mListView.getVerticalFadingEdgeLength());
+ assertTrue("should be at least two visible children",
+ mListView.getChildCount() >= 2);
+ }
+
+ // reproduce bug 998501: when first item fits within fading edge,
+ // having the second item call requestRectangleOnScreen with a rect above
+ // the bounds of the list, it was scrolling too far
+ @MediumTest
+ public void testSecondItemRequestRectAboveTop() throws Exception {
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+
+ final View second = mListView.getChildAt(1);
+ final Rect rect = new Rect();
+ second.getDrawingRect(rect);
+ rect.offset(0, -2 * second.getBottom());
+
+ getActivity().requestRectangleOnScreen(1, rect);
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals("top of first item",
+ mListView.getListPaddingTop(), mListView.getChildAt(0).getTop());
+
+ }
+
+ // same thing, but at bottom
+ @LargeTest
+ public void testSecondToLastItemRequestRectBelowBottom() throws Exception {
+
+ final int secondToLastPos = mListView.getCount() - 2;
+
+ while (mListView.getSelectedItemPosition() < secondToLastPos) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("selected position", secondToLastPos,
+ mListView.getSelectedItemPosition());
+
+ final View secondToLast = mListView.getSelectedView();
+ final Rect rect = new Rect();
+ secondToLast.getDrawingRect(rect);
+ rect.offset(0,
+ 2 * (mListView.getBottom() - secondToLast.getTop()));
+
+ final int secondToLastIndex = mListView.getChildCount() - 2;
+ getActivity().requestRectangleOnScreen(secondToLastIndex, rect);
+ getInstrumentation().waitForIdleSync();
+
+ int listBottom = mListView.getHeight() - mListView.getPaddingBottom();
+ assertEquals("bottom of last item should be at bottom of list",
+ listBottom,
+ mListView.getChildAt(mListView.getChildCount() - 1).getBottom());
+ }
+
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java
new file mode 100644
index 0000000..0251dfb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListManagedCursorTest.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import android.test.TouchUtils;
+
+/**
+ * Tests restoring the scroll position in a list with a managed cursor.
+ */
+public class ListManagedCursorTest extends ActivityInstrumentationTestCase<ListManagedCursor> {
+ private ListManagedCursor mActivity;
+ private ListView mListView;
+
+ public ListManagedCursorTest() {
+ super("com.android.frameworktest", ListManagedCursor.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ assertEquals(0, mListView.getFirstVisiblePosition());
+ }
+
+ /**
+ * Scroll the list using arrows, launch new activity, hit back, make sure we're still scrolled.
+ */
+ @LargeTest
+ public void testKeyScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisiblePosition = arrowScroll(inst);
+
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+
+ assertTrue("List changed to touch mode", !mListView.isInTouchMode());
+ assertTrue("List did not preserve scroll position",
+ firstVisiblePosition == mListView.getFirstVisiblePosition());
+ }
+
+ /**
+ * Scroll the list using touch, launch new activity, hit back, make sure we're still scrolled.
+ */
+ @LargeTest
+ public void testTouchScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisiblePosition = touchScroll(inst);
+
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+
+ assertTrue("List not in touch mode", mListView.isInTouchMode());
+ assertTrue("List did not preserve scroll position",
+ firstVisiblePosition == mListView.getFirstVisiblePosition());
+ }
+
+ /**
+ * Scroll the list using arrows, launch new activity, change to touch mode, hit back, make sure
+ * we're still scrolled.
+ */
+ @LargeTest
+ public void testKeyScrollingToTouchMode() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisiblePosition = arrowScroll(inst);
+
+ TouchUtils.dragQuarterScreenUp(this);
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+
+ assertTrue("List did not change to touch mode", mListView.isInTouchMode());
+ assertTrue("List did not preserve scroll position",
+ firstVisiblePosition == mListView.getFirstVisiblePosition());
+ }
+
+
+ /**
+ * Scroll the list using touch, launch new activity, change to trackball mode, hit back, make
+ * sure we're still scrolled.
+ */
+ @FlakyTest(tolerance=3)
+ @LargeTest
+ public void testTouchScrollingToTrackballMode() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisiblePosition = touchScroll(inst);
+
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ inst.waitForIdleSync();
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ inst.waitForIdleSync();
+ inst.sendCharacterSync(KeyEvent.KEYCODE_BACK);
+ inst.waitForIdleSync();
+ assertTrue("List not in trackball mode", !mListView.isInTouchMode());
+ assertTrue("List did not preserve scroll position", firstVisiblePosition == mListView
+ .getFirstVisiblePosition());
+ }
+
+ public int arrowScroll(Instrumentation inst) {
+ int count = mListView.getChildCount();
+
+ for (int i = 0; i < count * 2; i++) {
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ inst.waitForIdleSync();
+
+ int firstVisiblePosition = mListView.getFirstVisiblePosition();
+ assertTrue("Arrow scroll did not happen", firstVisiblePosition > 0);
+ assertTrue("List still in touch mode", !mListView.isInTouchMode());
+
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_CENTER);
+ inst.waitForIdleSync();
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return firstVisiblePosition;
+ }
+
+ public int touchScroll(Instrumentation inst) {
+ TouchUtils.dragQuarterScreenUp(this);
+ inst.waitForIdleSync();
+ TouchUtils.dragQuarterScreenUp(this);
+ inst.waitForIdleSync();
+ TouchUtils.dragQuarterScreenUp(this);
+ inst.waitForIdleSync();
+ TouchUtils.dragQuarterScreenUp(this);
+ inst.waitForIdleSync();
+
+ int firstVisiblePosition = mListView.getFirstVisiblePosition();
+ assertTrue("Touch scroll did not happen", firstVisiblePosition > 0);
+ assertTrue("List not in touch mode", mListView.isInTouchMode());
+
+ TouchUtils.clickView(this, mListView.getChildAt(mListView.getChildCount() - 1));
+ inst.waitForIdleSync();
+
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ return firstVisiblePosition;
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java
new file mode 100644
index 0000000..02a8beb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListRetainsFocusAcrossLayoutsTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.listview.ListItemFocusablesClose;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+public class ListRetainsFocusAcrossLayoutsTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
+
+ public ListRetainsFocusAcrossLayoutsTest() {
+ super("com.android.frameworktest", ListItemFocusablesClose.class);
+ }
+
+ private void requestLayoutOnList() {
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ getActivity().getListView().requestLayout();
+ }
+ });
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("top button at position 0 should be focused",
+ getActivity().getChildOfItem(0, 0).isFocused());
+ }
+
+ @MediumTest
+ public void testBottomButtonRetainsFocusAfterLayout() throws Exception {
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue("bottom botton at position 0 should be focused",
+ getActivity().getChildOfItem(0, 2).isFocused());
+
+ requestLayoutOnList();
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("bottom botton at position 0 should be focused after layout",
+ getActivity().getChildOfItem(0, 2).isFocused());
+ }
+
+ @MediumTest
+ public void testTopButtonOfSecondPositionRetainsFocusAfterLayout() {
+ sendRepeatedKeys(2, KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue("top botton at position 1 should be focused",
+ getActivity().getChildOfItem(1, 0).isFocused());
+
+ requestLayoutOnList();
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("top botton at position 1 should be focused after layout",
+ getActivity().getChildOfItem(1, 0).isFocused());
+
+ }
+
+ @MediumTest
+ public void testBottomButtonOfSecondPositionRetainsFocusAfterLayout() {
+ sendRepeatedKeys(3, KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue("bottom botton at position 1 should be focused",
+ getActivity().getChildOfItem(1, 2).isFocused());
+
+ requestLayoutOnList();
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("bottom botton at position 1 should be focused after layout",
+ getActivity().getChildOfItem(1, 2).isFocused());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
new file mode 100644
index 0000000..44958d9
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListScrollListenerTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.ListView;
+
+import android.test.TouchUtils;
+
+public class ListScrollListenerTest extends ActivityInstrumentationTestCase<ListScrollListener> implements
+ AbsListView.OnScrollListener {
+ private ListScrollListener mActivity;
+ private ListView mListView;
+ private int mFirstVisibleItem = -1;
+ private int mVisibleItemCount = -1;
+ private int mTotalItemCount = -1;
+
+ public ListScrollListenerTest() {
+ super("com.android.frameworktest", ListScrollListener.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ mListView.setOnScrollListener(this);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ assertEquals(0, mFirstVisibleItem);
+ }
+
+ @LargeTest
+ public void testKeyScrolling() {
+ Instrumentation inst = getInstrumentation();
+
+ int firstVisibleItem = mFirstVisibleItem;
+ for (int i = 0; i < mVisibleItemCount * 2; i++) {
+ inst.sendCharacterSync(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ inst.waitForIdleSync();
+ assertTrue("Arrow scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+
+ firstVisibleItem = mFirstVisibleItem;
+ inst.sendCharacterSync(KeyEvent.KEYCODE_SPACE);
+ inst.waitForIdleSync();
+ assertTrue("Page scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+
+ firstVisibleItem = mFirstVisibleItem;
+ KeyEvent down = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+ KeyEvent up = new KeyEvent(0, 0, KeyEvent.ACTION_UP,
+ KeyEvent.KEYCODE_DPAD_DOWN, 0, KeyEvent.META_ALT_ON);
+ inst.sendKeySync(down);
+ inst.sendKeySync(up);
+ inst.waitForIdleSync();
+
+ assertTrue("Full scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+ assertEquals("Full scroll did not happen", mTotalItemCount,
+ mFirstVisibleItem + mVisibleItemCount);
+ }
+
+ @LargeTest
+ public void testTouchScrolling() {
+ int firstVisibleItem = mFirstVisibleItem;
+ TouchUtils.dragQuarterScreenUp(this);
+ TouchUtils.dragQuarterScreenUp(this);
+ assertTrue("Touch scroll did not happen", mFirstVisibleItem > firstVisibleItem);
+ }
+
+
+ public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
+ mFirstVisibleItem = firstVisibleItem;
+ mVisibleItemCount = visibleItemCount;
+ mTotalItemCount = totalItemCount;
+ }
+
+ public void onScrollStateChanged(AbsListView view, int scrollState) {
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
new file mode 100644
index 0000000..e35d894
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListSetSelectionTest.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.UiThreadTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+/**
+ * Basic tests of setting & clearing the selection
+ */
+public class ListSetSelectionTest extends ActivityInstrumentationTestCase2<ListSimple> {
+ private ListSimple mActivity;
+ private ListView mListView;
+
+ public ListSetSelectionTest() {
+ super("com.android.frameworktest", ListSimple.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ /** Confirm that we can set the selection to each specific position */
+ @MediumTest
+ @UiThreadTest
+ public void testSetSelection() {
+ // Set the selection to each position
+ int childCount = mListView.getChildCount();
+ for (int i=0; i<childCount; i++) {
+ mListView.setSelection(i);
+ assertEquals("Set selection", i, mListView.getSelectedItemPosition());
+ }
+ }
+
+ /** Confirm that you cannot unset the selection using the same API */
+ @MediumTest
+ @UiThreadTest
+ public void testClearSelection() {
+ // Set the selection to first position
+ mListView.setSelection(0);
+ assertEquals("Set selection", 0, mListView.getSelectedItemPosition());
+
+ // Clear the selection
+ mListView.setSelection(ListView.INVALID_POSITION);
+ assertEquals("Set selection", 0, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java
new file mode 100644
index 0000000..55a57ef
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListUnspecifiedMeasure.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.app.Activity;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+
+public class ListUnspecifiedMeasure<T extends Activity> extends ActivityInstrumentationTestCase<T> {
+ private T mActivity;
+ private ListView mListView;
+
+ protected ListUnspecifiedMeasure(Class<T> klass) {
+ super("com.android.frameworktest", klass);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = (ListView) mActivity.findViewById(R.id.list);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ @MediumTest
+ public void testWasMeasured() {
+ assertTrue(mListView.getMeasuredWidth() > 0);
+ assertTrue(mListView.getWidth() > 0);
+ assertTrue(mListView.getMeasuredHeight() > 0);
+ assertTrue(mListView.getHeight() > 0);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java
new file mode 100644
index 0000000..d5bdf8b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/ListViewHeightTest.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview;
+
+import android.app.Instrumentation;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.listview.ListViewHeight;
+
+public class ListViewHeightTest extends ActivityInstrumentationTestCase<ListViewHeight> {
+ private ListViewHeight mActivity;
+
+
+ public ListViewHeightTest() {
+ super("com.android.frameworktest", ListViewHeight.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ }
+
+ @MediumTest
+ public void testButtons() {
+ Instrumentation inst = getInstrumentation();
+ final Button button1 = (Button) mActivity.findViewById(R.id.button1);
+ final Button button2 = (Button) mActivity.findViewById(R.id.button2);
+ final Button button3 = (Button) mActivity.findViewById(R.id.button3);
+
+
+ ListView list = (ListView) mActivity.findViewById(R.id.inner_list);
+ assertEquals("Unexpected items in adapter", 0, list.getCount());
+ assertEquals("Unexpected children in list view", 0, list.getChildCount());
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ button1.performClick();
+ }
+ });
+ inst.waitForIdleSync();
+ assertTrue("List not be visible after clicking button1", list.isShown());
+ assertTrue("List incorrect height", list.getHeight() == 200);
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ button2.performClick();
+ }
+ });
+ inst.waitForIdleSync();
+ assertTrue("List not be visible after clicking button2", list.isShown());
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ button3.performClick();
+ }
+ });
+ inst.waitForIdleSync();
+ assertFalse("List should not be visible clicking button3", list.isShown());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java
new file mode 100644
index 0000000..1fe75c4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListInterleaveFocusablesTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworktest.listview.ListInterleaveFocusables;
+import com.android.frameworktest.util.ListUtil;
+
+public class ListInterleaveFocusablesTest extends ActivityInstrumentationTestCase<ListInterleaveFocusables> {
+ private ListView mListView;
+ private ListUtil mListUtil;
+
+ public ListInterleaveFocusablesTest() {
+ super("com.android.frameworktest", ListInterleaveFocusables.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ mListUtil = new ListUtil(mListView, getInstrumentation());
+ }
+
+ @LargeTest
+ public void testPreconditions() {
+ assertEquals(7, mListView.getChildCount());
+ assertTrue(mListView.getChildAt(1).isFocusable());
+ assertTrue(mListView.getChildAt(3).isFocusable());
+ assertTrue(mListView.getChildAt(6).isFocusable());
+ }
+
+ @MediumTest
+ public void testGoingFromUnFocusableSelectedToFocusable() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals("selected item position", 1, mListView.getSelectedItemPosition());
+ assertSelectedViewFocus(true);
+ }
+
+ // go down from an item that isn't focusable, make sure it finds the focusable
+ // below (instead of above). this exposes a (now fixed) bug where the focus search
+ // was not starting from the right spot
+ @MediumTest
+ public void testGoingDownFromUnFocusableSelectedToFocusableWithOtherFocusableAbove() {
+ mListUtil.setSelectedPosition(2);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("selected item position", 3, mListView.getSelectedItemPosition());
+ assertSelectedViewFocus(true);
+ }
+
+ // same, but going up
+ @MediumTest
+ public void testGoingUpFromUnFocusableSelectedToFocusableWithOtherFocusableAbove() {
+ mListUtil.setSelectedPosition(2);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("selected item position", 1, mListView.getSelectedItemPosition());
+ assertSelectedViewFocus(true);
+ }
+
+ /**
+ * Go down from a focusable when there is a focusable below, but it is more than
+ * one item away; make sure it won't give that item focus because it is too far away.
+ */
+ @MediumTest
+ public void testGoingDownFromFocusableToUnfocusableWhenFocusableIsBelow() {
+ mListUtil.setSelectedPosition(3);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("selected item position", 4, mListView.getSelectedItemPosition());
+ assertSelectedViewFocus(false);
+ }
+
+ // same but going up
+ @MediumTest
+ public void testGoingUpFromFocusableToUnfocusableWhenFocusableIsBelow() {
+ mListUtil.setSelectedPosition(6);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("selected item position", 5, mListView.getSelectedItemPosition());
+ assertSelectedViewFocus(false);
+ }
+
+ public void assertSelectedViewFocus(boolean isFocused) {
+ final View view = mListView.getSelectedView();
+ assertEquals("selected view focused", isFocused, view.isFocused());
+ assertEquals("selected position's isSelected should be the inverse "
+ + "of it having focus", !isFocused, view.isSelected());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
new file mode 100644
index 0000000..6ff9181
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusableAboveUnfocusableTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListItemFocusableAboveUnfocusable;
+
+public class ListItemFocusableAboveUnfocusableTest extends ActivityInstrumentationTestCase<ListItemFocusableAboveUnfocusable> {
+ private ListView mListView;
+
+ public ListItemFocusableAboveUnfocusableTest() {
+ super("com.android.frameworktest", ListItemFocusableAboveUnfocusable.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ }
+
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+ assertTrue(mListView.getChildAt(0).isFocused());
+ assertFalse(mListView.getChildAt(1).isFocusable());
+ }
+
+ @MediumTest
+ public void testMovingToUnFocusableTakesFocusAway() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertFalse("focused item should have lost focus",
+ mListView.getChildAt(0).isFocused());
+ assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java
new file mode 100644
index 0000000..07356ba
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesCloseTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.LinearLayout;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListItemFocusablesClose;
+
+public class ListItemFocusablesCloseTest extends ActivityInstrumentationTestCase<ListItemFocusablesClose> {
+ private ListView mListView;
+ private int mListTop;
+ private int mListBottom;
+
+ public ListItemFocusablesCloseTest() {
+ super("com.android.frameworktest", ListItemFocusablesClose.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception{
+ super.setUp();
+ mListView = getActivity().getListView();
+ mListTop = mListView.getListPaddingTop();
+ mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertTrue(mListView.getAdapter().areAllItemsEnabled());
+ assertTrue(mListView.getItemsCanFocus());
+ assertEquals(0, mListView.getSelectedItemPosition());
+ final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+ getInstrumentation().waitForIdleSync();
+ assertEquals("first item should be at top of screen",
+ mListView.getListPaddingTop(),
+ first.getTop());
+ assertTrue("first button of first list item should have focus",
+ first.getChildAt(0).isFocused());
+ assertTrue("item should be shorter than list for this test to make sense",
+ first.getHeight() < mListView.getHeight());
+ assertEquals("two items should be on screen",
+ 2, mListView.getChildCount());
+ assertTrue("first button of second item should be on screen",
+ getActivity().getChildOfItem(1, 0).getBottom() < mListBottom);
+ }
+
+
+ @MediumTest
+ public void testChangeFocusWithinItem() {
+ final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+ final int topOfFirstItemBefore = first.getTop();
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue("focus should have moved to second button of first item",
+ first.getChildAt(2).isFocused());
+ assertEquals("selection should not have changed",
+ 0, mListView.getSelectedItemPosition());
+ assertEquals("list item should not have been shifted",
+ topOfFirstItemBefore, first.getTop());
+
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertTrue("focus should have moved back to first button of first item",
+ first.getChildAt(0).isFocused());
+ assertEquals("list item should not have been shifted",
+ topOfFirstItemBefore, first.getTop());
+ }
+
+ @MediumTest
+ public void testMoveDownToButtonInDifferentSelection() {
+ final LinearLayout first = (LinearLayout) mListView.getSelectedView();
+ final int topOfFirstItemBefore = first.getTop();
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals("selection should have moved to second item",
+ 1, mListView.getSelectedItemPosition());
+ final LinearLayout selectedItem = (LinearLayout) mListView.getSelectedView();
+ assertTrue("first button of second item should have focus",
+ selectedItem.getChildAt(0).isFocused());
+ assertEquals("list item should not have been shifted",
+ topOfFirstItemBefore, first.getTop());
+ }
+
+ @MediumTest
+ public void testMoveUpToButtonInDifferentSelection() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(1, mListView.getSelectedItemPosition());
+ assertTrue("first button of second item should have focus",
+ getActivity().getChildOfItem(1, 0).hasFocus());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("first list item should have selection", 0,
+ mListView.getSelectedItemPosition());
+ assertTrue("second button of first item should have focus",
+ getActivity().getChildOfItem(0, 2).hasFocus());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java
new file mode 100644
index 0000000..951e021
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemFocusablesFarApartTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListItemFocusablesFarApart;
+
+public class ListItemFocusablesFarApartTest extends ActivityInstrumentationTestCase<ListItemFocusablesFarApart> {
+ private ListView mListView;
+ private int mListTop;
+ private int mListBottom;
+
+ public ListItemFocusablesFarApartTest() {
+ super("com.android.frameworktest", ListItemFocusablesFarApart.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ mListTop = mListView.getListPaddingTop();
+ mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ }
+
+ /**
+ * Get the child of a list item.
+ * @param listIndex The index of the currently visible items
+ * @param index The index of the child.
+ */
+ public View getChildOfItem(int listIndex, int index) {
+ return ((ViewGroup) mListView.getChildAt(listIndex)).getChildAt(index);
+
+ }
+
+ public int getTopOfChildOfItem(int listIndex, int index) {
+ ViewGroup listItem = (ViewGroup) mListView.getChildAt(listIndex);
+ View child = listItem.getChildAt(index);
+ return child.getTop() + listItem.getTop();
+ }
+
+ public int getBottomOfChildOfItem(int listIndex, int index) {
+ ViewGroup listItem = (ViewGroup) mListView.getChildAt(listIndex);
+ View child = listItem.getChildAt(index);
+ return child.getBottom() + listItem.getTop();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertEquals("should only be one visible list item",
+ 1, mListView.getChildCount());
+ int topOfFirstButton = getTopOfChildOfItem(0, 0);
+ int topOfSecondButton = getTopOfChildOfItem(0, 2);
+ assertTrue("second button should be more than max scroll away from first",
+ topOfSecondButton - topOfFirstButton > mListView.getMaxScrollAmount());
+ }
+
+
+ @MediumTest
+ public void testPanWhenNextFocusableTooFarDown() {
+
+ int expectedTop = mListView.getChildAt(0).getTop();
+
+ final Button topButton = (Button) getChildOfItem(0, 0);
+
+ int counter = 0;
+ while(getTopOfChildOfItem(0, 2) > mListBottom) {
+ // just to make sure we never end up with an infinite loop
+ if (counter > 5) fail("couldn't reach next button within " + counter + " downs");
+
+ if (getBottomOfChildOfItem(0, 0) < mListTop) {
+ assertFalse("after " + counter + " downs, top button not visible, should not have focus",
+ topButton.isFocused());
+ assertFalse("after " + counter + " downs, neither top button nor botom button visible, nothng within first list " +
+ "item should have focus", mListView.getChildAt(0).hasFocus());
+ } else {
+ assertTrue("after " + counter + " downs, top button still visible, should have focus",
+ topButton.isFocused());
+ }
+
+ assertEquals("after " + counter + " downs, " +
+ "should have panned by max scroll amount",
+ expectedTop, mListView.getChildAt(0).getTop());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ expectedTop -= mListView.getMaxScrollAmount();
+ counter++;
+ }
+
+ // at this point, the second button is visible on screen.
+ // it should have focus
+ assertTrue("second button should have focus",
+ getChildOfItem(0, 2).isFocused());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
new file mode 100644
index 0000000..f61ce7b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListItemsExpandOnSelectionTest.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListItemsExpandOnSelection;
+
+public class ListItemsExpandOnSelectionTest extends ActivityInstrumentationTestCase<ListItemsExpandOnSelection> {
+ private ListView mListView;
+ private int mListTop;
+ private int mListBottom;
+ private int mExpandedHeight;
+ private int mNormalHeight;
+
+ public ListItemsExpandOnSelectionTest() {
+ super("com.android.frameworktest",
+ ListItemsExpandOnSelection.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ mListTop = mListView.getListPaddingTop();
+ mListBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ mExpandedHeight = mListView.getChildAt(0).getHeight();
+ mNormalHeight = mListView.getChildAt(1).getHeight();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals(0, mListView.getSelectedItemPosition());
+ assertEquals("selected item should be 1.5 times taller than the others",
+ mExpandedHeight, (int) (mNormalHeight * 1.5));
+ }
+
+ @MediumTest
+ public void testMoveSelectionDownNotRequiringScroll() {
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals(1, mListView.getSelectedItemPosition());
+ assertEquals("first item's top should not have shifted",
+ mListTop, mListView.getChildAt(0).getTop());
+
+ }
+
+ @MediumTest
+ public void testMoveSelectionUpNotRequiringScroll() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals(1, mListView.getSelectedItemPosition());
+ final int oldBottom = mListView.getSelectedView().getBottom();
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ assertEquals("bottom of 2nd itme should have stayed the same when " +
+ "moving back up",
+ oldBottom,
+ mListView.getChildAt(1).getBottom());
+ }
+
+ @MediumTest
+ public void testMoveSelectionDownRequiringScroll() {
+ int lastItemIndex = mListView.getChildCount() - 1;
+
+ for(int i = 0; i < lastItemIndex; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals("list position", lastItemIndex, mListView.getSelectedItemPosition());
+ assertEquals("expanded height", mExpandedHeight, mListView.getSelectedView().getHeight());
+ assertEquals("should be above bottom fading edge",
+ mListBottom - mListView.getVerticalFadingEdgeLength(),
+ mListView.getSelectedView().getBottom());
+ }
+
+ @LargeTest
+ public void testMoveSelectionUpRequiringScroll() {
+ int childrenPerScreen = mListView.getChildCount();
+
+ // go down past last child on screen
+ for(int i = 0; i < childrenPerScreen; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ // go back up to second to last
+ for(int i = 0; i < childrenPerScreen - 1; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals("list position", 1, mListView.getSelectedItemPosition());
+ assertEquals("expanded height", mExpandedHeight, mListView.getSelectedView().getHeight());
+ assertEquals("should be below top fading edge",
+ mListTop + mListView.getVerticalFadingEdgeLength(),
+ mListView.getSelectedView().getTop());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
new file mode 100644
index 0000000..38f4b0e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListLastItemPartiallyVisibleTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListLastItemPartiallyVisible;
+
+public class ListLastItemPartiallyVisibleTest extends ActivityInstrumentationTestCase<ListLastItemPartiallyVisible> {
+ private ListView mListView;
+ private int mListBottom;
+
+
+ public ListLastItemPartiallyVisibleTest() {
+ super("com.android.frameworktest", ListLastItemPartiallyVisible.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ mListBottom = mListView.getHeight() - mListView.getPaddingBottom();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals("number of elements visible should be the same as number of items " +
+ "in adapter", mListView.getCount(), mListView.getChildCount());
+
+ final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+ assertTrue("last item should be partially off screen",
+ lastChild.getBottom() > mListBottom);
+ assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+ }
+
+ // reproduce bug 998094
+ @MediumTest
+ public void testMovingDownToFullyVisibleNoScroll() {
+ final View firstChild = mListView.getChildAt(0);
+ final int firstBottom = firstChild.getBottom();
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("shouldn't have scrolled: bottom of first child changed.",
+ firstBottom, firstChild.getBottom());
+ }
+
+ // reproduce bug 998094
+ @MediumTest
+ public void testMovingUpToFullyVisibleNoScroll() {
+ int numMovesToLast = mListView.getCount() - 1;
+ for (int i = 0; i < numMovesToLast; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("should have moved to last position",
+ mListView.getChildCount() - 1, mListView.getSelectedItemPosition());
+
+ final View lastChild = mListView.getSelectedView();
+ final int lastTop = lastChild.getTop();
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("shouldn't have scrolled: top of last child changed.",
+ lastTop, lastChild.getTop());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
new file mode 100644
index 0000000..126eea2
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsShorterThanScreenTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.frameworktest.listview.ListOfItemsShorterThanScreen;
+
+public class ListOfItemsShorterThanScreenTest
+ extends ActivityInstrumentationTestCase<ListOfItemsShorterThanScreen> {
+ private ListView mListView;
+ private ListOfItemsShorterThanScreen mActivity;
+
+
+ public ListOfItemsShorterThanScreenTest() {
+ super("com.android.frameworktest", ListOfItemsShorterThanScreen.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals(0, mListView.getSelectedItemPosition());
+ assertTrue(mListView.getChildAt(0).isSelected());
+ assertEquals(mListView.getListPaddingTop(), mListView.getSelectedView().getTop());
+ }
+
+ @MediumTest
+ public void testMoveDownToOnScreenNextItem() {
+ final View next = mListView.getChildAt(1);
+ assertFalse(next.isSelected());
+ final int secondPosition = mListView.getSelectedView().getBottom();
+ assertEquals("second item should be positioned item height pixels from top.",
+ secondPosition,
+ next.getTop());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(1, mListView.getSelectedItemPosition());
+ assertTrue(next.isSelected());
+ assertEquals("next selected item shouldn't have moved",
+ secondPosition,
+ next.getTop());
+ }
+
+ @MediumTest
+ public void testMoveUpToOnScreenItem() {
+ // move down one, then back up
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testMoveDownToItemRequiringScrolling() {
+ final int lastOnScreenItemIndex = mListView.getChildCount() - 1;
+ final View lastItem = mListView.getChildAt(lastOnScreenItemIndex);
+ assertTrue("last item should be partially off screen",
+ lastItem.getBottom() > mListView.getBottom());
+ assertEquals(mListView.getListPaddingTop(), mListView.getSelectedView().getTop());
+
+ for (int i = 0; i < lastOnScreenItemIndex; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ assertEquals(lastOnScreenItemIndex, mListView.getSelectedItemPosition());
+ assertEquals(
+ getTopOfBottomFadingEdge(),
+ mListView.getSelectedView().getBottom());
+
+ // there should be a peeking view
+
+ // the current view isn't the last anymore...
+ assertEquals(mListView.getSelectedView(), mListView.getChildAt(mListView.getChildCount() - 2));
+
+ // peeking view is now last
+ final TextView view = (TextView) mListView.getChildAt(mListView.getChildCount() - 1);
+ assertEquals(mActivity.getValueAtPosition(lastOnScreenItemIndex + 1), view.getText());
+ assertFalse(view.isSelected());
+ }
+
+ @MediumTest
+ public void testMoveUpToItemRequiringScrolling() {
+ // go down to one past last item, then back up to the second item. this will
+ // require scrolling to get it back on screen, and will need a peeking edge
+
+ int numItemsOnScreen = mListView.getChildCount();
+ for (int i = 0; i < numItemsOnScreen; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ for (int i = 0; i < numItemsOnScreen - 1; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+
+ assertEquals(1, mListView.getSelectedItemPosition());
+ assertEquals("top should be just below vertical fading edge",
+ mListView.getVerticalFadingEdgeLength() + mListView.getListPaddingTop(),
+ mListView.getSelectedView().getTop());
+ }
+
+ @MediumTest
+ public void testPressUpWhenAlreadyAtTop() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testPressDownWhenAlreadyAtBottom() {
+ final int lastItemPosition = mListView.getAdapter().getCount() - 1;
+ for (int i = 0; i < lastItemPosition; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testNoVerticalFadingEdgeWhenMovingToBottom() {
+ final int lastItemPosition = mListView.getAdapter().getCount() - 1;
+ for (int i = 0; i < lastItemPosition; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals(lastItemPosition, mListView.getSelectedItemPosition());
+
+ assertEquals("bottom of last item should be just above padding; no fading edge.",
+ mListView.getHeight() - mListView.getListPaddingBottom(),
+ mListView.getSelectedView().getBottom());
+
+ }
+
+ // the top of the bottom fading edge takes into account the list padding at the bottom,
+ // and the fading edge size
+ private int getTopOfBottomFadingEdge() {
+ return mListView.getHeight() - (mListView.getVerticalFadingEdgeLength() + mListView.getListPaddingBottom());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
new file mode 100644
index 0000000..ec3a15c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfItemsTallerThanScreenTest.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListOfItemsTallerThanScreen;
+
+public class ListOfItemsTallerThanScreenTest
+ extends ActivityInstrumentationTestCase<ListOfItemsTallerThanScreen> {
+
+ private ListView mListView;
+ private ListOfItemsTallerThanScreen mActivity;
+
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ public ListOfItemsTallerThanScreenTest() {
+ super("com.android.frameworktest", ListOfItemsTallerThanScreen.class);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertEquals("should only be one visible child", 1, mListView.getChildCount());
+ final int amountOffScreen = mListView.getChildAt(0).getBottom() - (mListView.getBottom() - mListView.getListPaddingBottom());
+ assertTrue("must be more than max scroll off screen for this test to work",
+ amountOffScreen > mListView.getMaxScrollAmount());
+ }
+
+ @MediumTest
+ public void testScrollDownAcrossItem() {
+ final View view = mListView.getSelectedView();
+ assertTrue(view.isSelected());
+
+ assertEquals(mListView.getListPaddingTop(),
+ view.getTop());
+
+ assertTrue("view must be taller than screen for this test to be worth anything",
+ view.getBottom() > mListView.getBottom());
+
+ // scroll down until next view is peeking ahead
+ int numScrollsUntilNextViewVisible = getNumDownPressesToScrollDownAcrossSelected();
+
+ for (int i = 0; i < numScrollsUntilNextViewVisible; i++) {
+ assertEquals("after " + i + " down scrolls across tall item",
+ mListView.getListPaddingTop() - mListView.getMaxScrollAmount() * i,
+ view.getTop());
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ // at this point, next view should be on screen peeking ahead, but we haven't given
+ // it selection yet
+ assertEquals("child count", 2, mListView.getChildCount());
+ assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+ assertTrue("same view should be selected", view.isSelected());
+ final View peekingView = mListView.getChildAt(1);
+ assertEquals(view.getBottom(), peekingView.getTop());
+ }
+
+ @MediumTest
+ public void testScrollDownToNextItem() {
+ final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
+ assertEquals(1, mListView.getChildCount());
+
+ for (int i = 0; i < numPresses; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ // remember top of peeking child
+ final int topOfPeekingNext = mListView.getChildAt(1).getTop();
+
+ // next view is peeking, now press one more time
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ // old view should not have selection
+ assertFalse(mListView.getChildAt(0).isSelected());
+
+ // next view should now have selection, and be scrolled another a third of the list
+ // height
+ assertEquals(2, mListView.getChildCount());
+ final View next = mListView.getChildAt(1);
+ assertTrue("has selection", next.isSelected());
+ assertEquals(topOfPeekingNext - (mListView.getMaxScrollAmount()), next.getTop());
+ }
+
+ @MediumTest
+ public void testScrollFirstItemOffScreen() {
+ int numDownsToGetFirstItemOffScreen =
+ (mListView.getSelectedView().getHeight() / mListView.getMaxScrollAmount()) + 1;
+
+ for (int i = 0; i < numDownsToGetFirstItemOffScreen; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals("should be at next item",
+ 1, mListView.getSelectedItemPosition());
+
+ final int listTop = mListView.getTop() + mListView.getListPaddingTop();
+ assertTrue("top of selected view should be above top of list",
+ mListView.getSelectedView().getTop() < listTop);
+
+ assertEquals("off screen item shouldn't be a child of list view",
+ 1, mListView.getChildCount());
+ }
+
+ @LargeTest
+ public void testScrollDownToLastItem() {
+ final int numItems = mListView.getAdapter().getCount();
+
+ int maxDowns = 20;
+ while (mListView.getSelectedItemPosition() < (numItems - 1)) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ if (--maxDowns <= 0) {
+ fail("couldn't get to last item within 20 down arrows");
+ }
+ }
+ getInstrumentation().waitForIdleSync();
+
+ // press down enough times to get to bottom of last item
+ final int numDownsLeft = getNumDownPressesToScrollDownAcrossSelected();
+ assertTrue(numDownsLeft > 0);
+ for (int i = 0; i < numDownsLeft; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ // one more time to get across last item
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+
+ assertEquals(numItems - 1, mListView.getSelectedItemPosition());
+ final int realBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ assertEquals(realBottom, mListView.getSelectedView().getBottom());
+
+ assertEquals("views scrolled off screen should be removed from view group",
+ 1, mListView.getChildCount());
+ }
+
+ @MediumTest
+ public void testScrollUpAcrossFirstItem() {
+ final int listTop = mListView.getListPaddingTop();
+ assertEquals(listTop, mListView.getSelectedView().getTop());
+ final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
+ for (int i = 0; i < numPresses; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals(2, mListView.getChildCount());
+ for (int i = 0; i < numPresses; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals(1, mListView.getChildCount());
+ }
+ assertEquals(listTop, mListView.getSelectedView().getTop());
+ }
+
+ /**
+ * Assuming the selected view is overlapping the bottom edge, how many times
+ * do I have to press down to get beyond it so that either:
+ * a) the next view is peeking in
+ * b) the selected view is the last item in the list, and we are scrolled to the bottom
+ * @return
+ */
+ private int getNumDownPressesToScrollDownAcrossSelected() {
+ View selected = mListView.getSelectedView();
+ int realBottom = mListView.getBottom() - mListView.getListPaddingBottom();
+ assertTrue("view should be overlapping bottom",
+ selected.getBottom() > realBottom);
+ assertTrue("view should be overlapping bottom",
+ selected.getTop() < realBottom);
+
+ int pixelsOffScreen = selected.getBottom() - realBottom;
+ return (pixelsOffScreen / mListView.getMaxScrollAmount()) + 1;
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
new file mode 100644
index 0000000..e218099
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortShortTallShortShortTest.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfShortShortTallShortShort;
+import com.android.frameworktest.util.ListUtil;
+
+public class ListOfShortShortTallShortShortTest extends ActivityInstrumentationTestCase<ListOfShortShortTallShortShort> {
+ private ListView mListView;
+ private ListUtil mListUtil;
+
+ public ListOfShortShortTallShortShortTest() {
+ super("com.android.frameworktest", ListOfShortShortTallShortShort.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ mListUtil = new ListUtil(mListView, getInstrumentation());
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals("list item count", 5, mListView.getCount());
+ assertEquals("list visible child count", 3, mListView.getChildCount());
+ int firstTwoHeight = mListView.getChildAt(0).getHeight() + mListView.getChildAt(1).getHeight();
+ assertTrue("first two items should fit within fading edge",
+ firstTwoHeight <= mListView.getVerticalFadingEdgeLength());
+ assertTrue("first two items should fit within list max scroll",
+ firstTwoHeight <= mListView.getMaxScrollAmount());
+ }
+
+ @MediumTest
+ public void testFadeTopTwoItemsOut() {
+ // put 2nd item selected
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ // one more to get two items scrolled off
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals("selected item position", 2, mListView.getSelectedItemPosition());
+ assertTrue("selected item top should be above list top",
+ mListView.getSelectedView().getTop() < mListUtil.getListTop());
+ assertTrue("selected item bottom should be below list bottom",
+ mListView.getSelectedView().getBottom() > mListUtil.getListBottom());
+ assertEquals("should only be 1 child of list (2 should have been scrolled off and removed",
+ 1, mListView.getChildCount());
+ }
+
+ @LargeTest
+ public void testFadeInTwoBottomItems() {
+ // put 2nd item selected
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ // one more to get two items scrolled off
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("number of list children", 1, mListView.getChildCount());
+
+ // last down brings bottom two items into view
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("should have scrolled two extra views onto screen",
+ 3, mListView.getChildCount());
+ assertEquals("new view position", 3, mListView.getChildAt(1).getId());
+ assertEquals("new view position", 4, mListView.getChildAt(2).getId());
+
+ assertTrue("bottom most view shouldn't be above list bottom",
+ mListView.getChildAt(2).getBottom() >= mListUtil.getListBottom());
+ }
+
+ @LargeTest
+ public void testFadeOutBottomTwoItems() throws Exception {
+ mListUtil.arrowScrollToSelectedPosition(4);
+
+ // go up to tall item
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ // one more time to scroll off bottom two items
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+
+ assertEquals("selected item position", 2, mListView.getSelectedItemPosition());
+ assertTrue("selected item top should be at or above list top",
+ mListView.getSelectedView().getTop() <= mListUtil.getListTop());
+ assertTrue("selected item bottom should be below list bottom",
+ mListView.getSelectedView().getBottom() > mListUtil.getListBottom());
+ assertEquals("should only be 1 child of list (2 should have been scrolled off and removed",
+ 1, mListView.getChildCount());
+ }
+
+ @LargeTest
+ public void testFadeInTopTwoItems() throws Exception {
+ mListUtil.arrowScrollToSelectedPosition(4);
+
+ // put 2nd item selected
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ // one more to get two items scrolled off
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("number of list children", 1, mListView.getChildCount());
+
+ // last down brings top two items into view
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("should have scrolled two extra views onto screen",
+ 3, mListView.getChildCount());
+ assertEquals("new view position", 0, mListView.getChildAt(0).getId());
+ assertEquals("new view position", 1, mListView.getChildAt(1).getId());
+
+ assertTrue("top most view shouldn't be above list top",
+ mListView.getChildAt(0).getTop() <= mListUtil.getListTop());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java
new file mode 100644
index 0000000..6a83ada
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfShortTallShortTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListOfShortTallShort;
+
+public class ListOfShortTallShortTest extends ActivityInstrumentationTestCase<ListOfShortTallShort> {
+ private ListView mListView;
+
+ public ListOfShortTallShortTest() {
+ super("com.android.frameworktest", ListOfShortTallShort.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("second item should be taller than screen",
+ mListView.getChildAt(1).getHeight() > mListView.getHeight());
+ }
+
+ @MediumTest
+ public void testGoDownFromShortToTall() {
+ int topBeforeMove = mListView.getChildAt(1).getTop();
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals("selection should have moved to tall item below",
+ 1, mListView.getSelectedItemPosition());
+ assertEquals("should not have scrolled; top should be the same.",
+ topBeforeMove,
+ mListView.getSelectedView().getTop());
+ }
+
+ @MediumTest
+ public void testGoUpFromShortToTall() {
+ int maxMoves = 8;
+ while (mListView.getSelectedItemPosition() != 2 && maxMoves > 0) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("couldn't get to 3rd item",
+ 2,
+ mListView.getSelectedItemPosition());
+
+ assertEquals("should only be two items on screen",
+ 2, mListView.getChildCount());
+ assertEquals("selected item should be last item on screen",
+ mListView.getChildAt(1), mListView.getSelectedView());
+
+ final int bottomBeforeMove = mListView.getChildAt(0).getBottom();
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("should have moved selection to tall item above",
+ 1, mListView.getSelectedItemPosition());
+ assertEquals("should not have scrolled, top should be the same",
+ bottomBeforeMove,
+ mListView.getChildAt(0).getBottom());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java
new file mode 100644
index 0000000..e8dbbec
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListOfThinItemsTest.java
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListOfThinItems;
+
+public class ListOfThinItemsTest extends ActivityInstrumentationTestCase<ListOfThinItems> {
+ private ListView mListView;
+
+ public ListOfThinItemsTest() {
+ super("com.android.frameworktest", ListOfThinItems.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception{
+ super.setUp();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertTrue("need item height less than fading edge length",
+ mListView.getSelectedView().getHeight() < mListView.getVerticalFadingEdgeLength());
+ assertTrue("need items off screen",
+ mListView.getChildCount() < mListView.getAdapter().getCount());
+ }
+
+ @LargeTest
+ public void testScrollToBottom() {
+ final int numItems = mListView.getAdapter().getCount();
+ final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ for (int i = 0; i < numItems; i++) {
+ assertEquals("wrong selection at position " + i,
+ i, mListView.getSelectedItemPosition());
+ final int bottomFadingEdge = listBottom - mListView.getVerticalFadingEdgeLength();
+ final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+ final int lastVisiblePosition = lastChild.getId();
+
+
+ int bottomThreshold = (lastVisiblePosition < mListView.getAdapter().getCount() - 1) ?
+ bottomFadingEdge : listBottom;
+
+ String prefix = "after " + i + " down presses, ";
+
+ assertTrue(prefix + "selected item is below bottom threshold (fading edge or bottom as " +
+ "appropriate)",
+ mListView.getSelectedView().getBottom() <= bottomThreshold);
+ assertTrue(prefix + "first item in list must be at very top or just above",
+ mListView.getChildAt(0).getTop() <= 0);
+ assertTrue(prefix + "last item in list should be at very bottom or just below",
+ lastChild.getBottom() >= listBottom);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ }
+
+ @LargeTest
+ public void testScrollToTop() {
+ final int numItems = mListView.getAdapter().getCount();
+
+ for (int i = 0; i < numItems - 1; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("should have moved to last position",
+ numItems - 1, mListView.getSelectedItemPosition());
+
+ int listTop = mListView.getListPaddingTop();
+ final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+
+ for (int i = 0; i < numItems; i++) {
+ int expectedPostion = numItems - (i + 1);
+ assertEquals("wrong selection at position " + expectedPostion,
+ expectedPostion, mListView.getSelectedItemPosition());
+ final int topFadingEdge = listTop + mListView.getVerticalFadingEdgeLength();
+ final View firstChild = mListView.getChildAt(0);
+ final View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+ final int firstVisiblePosition = firstChild.getId();
+
+
+ int topThreshold = (firstVisiblePosition > 0) ?
+ topFadingEdge : listTop;
+
+ String prefix = "after " + i + " up presses, ";
+
+ assertTrue(prefix + "selected item is above top threshold (fading edge or top as " +
+ "appropriate)",
+ mListView.getSelectedView().getTop() >= topThreshold);
+ assertTrue(prefix + "first item in list must be at very top or just above",
+ firstChild.getTop() <= 0);
+ assertTrue(prefix + "last item in list should be at very bottom or just below",
+ lastChild.getBottom() >= listBottom);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
new file mode 100644
index 0000000..307c39d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithFirstScreenUnSelectableTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2008 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithFirstScreenUnSelectable;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.widget.ListView;
+import android.widget.AdapterView;
+
+public class ListWithFirstScreenUnSelectableTest
+ extends ActivityInstrumentationTestCase2<ListWithFirstScreenUnSelectable> {
+ private ListView mListView;
+
+ public ListWithFirstScreenUnSelectableTest() {
+ super("com.android.frameworktest", ListWithFirstScreenUnSelectable.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ setActivityInitialTouchMode(true);
+
+ mListView = getActivity().getListView();
+ }
+
+ public void testPreconditions() {
+ assertTrue(mListView.isInTouchMode());
+ assertEquals(1, mListView.getChildCount());
+ assertFalse(mListView.getAdapter().isEnabled(0));
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+
+ public void testRessurectSelection() {
+ sendKeys(KeyEvent.KEYCODE_SPACE);
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+
+ public void testScrollUpDoesNothing() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals(AdapterView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ assertEquals(1, mListView.getChildCount());
+ assertEquals(0, mListView.getFirstVisiblePosition());
+ }
+
+ public void testScrollDownPansNextItemOn() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(2, mListView.getChildCount());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java
new file mode 100644
index 0000000..449e048
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithNoFadingEdgeTest.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithNoFadingEdge;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+
+public class ListWithNoFadingEdgeTest extends ActivityInstrumentationTestCase<ListWithNoFadingEdge> {
+
+ private ListView mListView;
+
+ public ListWithNoFadingEdgeTest() {
+ super("com.android.frameworktest", ListWithNoFadingEdge.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertEquals("listview vertical fading edge", 0, mListView.getVerticalFadingEdgeLength());
+ assertTrue("expecting that not all views fit on screen",
+ mListView.getChildCount() < mListView.getCount());
+ }
+
+ @MediumTest
+ public void testScrollDownToBottom() {
+ final int numItems = mListView.getCount();
+
+ for (int i = 0; i < numItems; i++) {
+ assertEquals("selected position", i, mListView.getSelectedItemPosition());
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("selected position", numItems - 1, mListView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testScrollFromBottomToTop() {
+ final int numItems = mListView.getCount();
+
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setSelection(numItems - 1);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ for (int i = numItems - 1; i >=0; i--) {
+ assertEquals(i, mListView.getSelectedItemPosition());
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+
+ assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
new file mode 100644
index 0000000..6e62ccb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOffScreenNextSelectableTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+import android.widget.TextView;
+import com.android.frameworktest.listview.ListWithOffScreenNextSelectable;
+
+public class ListWithOffScreenNextSelectableTest
+ extends ActivityInstrumentationTestCase<ListWithOffScreenNextSelectable> {
+ private ListView mListView;
+
+ public ListWithOffScreenNextSelectableTest() {
+ super("com.android.frameworktest", ListWithOffScreenNextSelectable.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mListView);
+ assertEquals(5, mListView.getAdapter().getCount());
+ assertFalse(mListView.getAdapter().areAllItemsEnabled());
+ assertFalse(mListView.getAdapter().isEnabled(1));
+ assertFalse(mListView.getAdapter().isEnabled(2));
+ assertFalse(mListView.getAdapter().isEnabled(3));
+ assertEquals("only 4 children should be on screen (so that next selectable is off " +
+ "screen) for this test to be meaningful.",
+ 4, mListView.getChildCount());
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ // when the next items on screen are not selectable, we pan until the next selectable item
+ // is (partially visible), then we jump to it
+ @MediumTest
+ public void testGoDownToOffScreenSelectable() {
+
+ final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+
+ final View lastVisibleView = mListView.getChildAt(mListView.getChildCount() - 1);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("expecting view to be panned to just above fading edge",
+ listBottom - mListView.getVerticalFadingEdgeLength(), lastVisibleView.getBottom());
+ assertEquals("selection should not have moved yet",
+ 0, mListView.getSelectedItemPosition());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("selection should have moved",
+ 4, mListView.getSelectedItemPosition());
+ assertEquals("wrong view created when scrolling",
+ getActivity().getValueAtPosition(4), ((TextView) mListView.getSelectedView()).getText());
+ assertEquals(listBottom, mListView.getSelectedView().getBottom());
+ }
+
+ @MediumTest
+ public void testGoUpToOffScreenSelectable() {
+ final int listBottom = mListView.getHeight() - mListView.getListPaddingBottom();
+ final int listTop = mListView.getListPaddingTop();
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals(4, mListView.getSelectedItemPosition());
+ assertEquals(listBottom, mListView.getSelectedView().getBottom());
+
+ // now we have the reverse situation: the next selectable position upward is off screen
+ final View firstVisibleView = mListView.getChildAt(0);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("should have panned top view just below vertical fading edge",
+ listTop + mListView.getVerticalFadingEdgeLength(), firstVisibleView.getTop());
+ assertEquals("selection should not have moved yet",
+ 4, mListView.getSelectedItemPosition());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("selection should have moved",
+ 0, mListView.getSelectedItemPosition());
+ assertEquals(getActivity().getValueAtPosition(0),((TextView) mListView.getSelectedView()).getText());
+ assertEquals(listTop, mListView.getSelectedView().getTop());
+
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
new file mode 100644
index 0000000..0a8af45
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithOnItemSelectedActionTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListWithOnItemSelectedAction;
+
+public class ListWithOnItemSelectedActionTest extends ActivityInstrumentationTestCase<ListWithOnItemSelectedAction> {
+ private ListView mListView;
+
+ public ListWithOnItemSelectedActionTest() {
+ super("com.android.frameworktest", ListWithOnItemSelectedAction.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ }
+
+ private String getValueOfSelectedTextView() {
+ return ((TextView) mListView.getSelectedView()).getText().toString();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals(0, mListView.getSelectedItemPosition());
+ assertEquals("header text field should be echoing contents of selected item",
+ getValueOfSelectedTextView(),
+ getActivity().getHeaderValue());
+ }
+
+ @MediumTest
+ public void testHeaderEchoesSelectionAfterMove() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals(1, mListView.getSelectedItemPosition());
+ assertEquals("header text field should be echoing contents of selected item",
+ getValueOfSelectedTextView(),
+ getActivity().getHeaderValue());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
new file mode 100644
index 0000000..0c0084e
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithScreenOfNoSelectablesTest.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import com.android.frameworktest.listview.ListWithScreenOfNoSelectables;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.ListView;
+
+public class ListWithScreenOfNoSelectablesTest extends ActivityInstrumentationTestCase<ListWithScreenOfNoSelectables> {
+
+ private ListView mListView;
+
+ public ListWithScreenOfNoSelectablesTest() {
+ super("com.android.frameworktest", ListWithScreenOfNoSelectables.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("expecting first position to be selectable",
+ mListView.getAdapter().isEnabled(0));
+ final int numItems = mListView.getCount();
+ for (int i = 1; i < numItems; i++) {
+ assertFalse("expecting item to be unselectable (index " + i +")",
+ mListView.getAdapter().isEnabled(i));
+ }
+ assertTrue("expecting that not all views fit on screen",
+ mListView.getChildCount() < mListView.getCount());
+ }
+
+
+ @MediumTest
+ public void testGoFromSelectedViewExistsToNoSelectedViewExists() {
+
+ // go down untile first (and only selectable) item is off screen
+ View first = mListView.getChildAt(0);
+ while (first.getParent() != null) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ // nothing should be selected
+ assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ assertNull("selected view", mListView.getSelectedView());
+ }
+
+ @LargeTest
+ public void testPanDownAcrossUnselectableChildrenToBottom() {
+ final int lastPosition = mListView.getCount() - 1;
+ final int maxDowns = 20;
+ for(int count = 0; count < maxDowns && mListView.getLastVisiblePosition() <= lastPosition; count++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ assertEquals("last visible position not the last position in the list even "
+ + "after " + maxDowns + " downs", lastPosition, mListView.getLastVisiblePosition());
+ }
+
+ @MediumTest
+ public void testGoFromNoSelectionToSelectionExists() {
+ // go down untile first (and only selectable) item is off screen
+ View first = mListView.getChildAt(0);
+ while (first.getParent() != null) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ // nothing should be selected
+ assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ assertNull("selected view", mListView.getSelectedView());
+
+ // go up once to bring the selectable back on screen
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("first visible position", 0, mListView.getFirstVisiblePosition());
+ assertEquals("selected position", ListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+
+
+ // up once more should give it selection
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("selected position", 0, mListView.getSelectedItemPosition());
+
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java
new file mode 100644
index 0000000..fdeaa4a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/arrowscroll/ListWithSeparatorsTest.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.arrowscroll;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.ListView;
+import android.view.KeyEvent;
+import com.android.frameworktest.listview.ListWithSeparators;
+
+public class ListWithSeparatorsTest extends ActivityInstrumentationTestCase<ListWithSeparators> {
+ private ListWithSeparators mActivity;
+ private ListView mListView;
+
+ public ListWithSeparatorsTest() {
+ super("com.android.frameworktest", ListWithSeparators.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ assertFalse(mListView.getAdapter().areAllItemsEnabled());
+ assertFalse(mListView.getAdapter().isEnabled(0));
+ assertFalse(mListView.getAdapter().isEnabled(2));
+ assertEquals(1, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testGoingUpDoesnNotHitUnselectableItem() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals("selected position should remain the same",
+ 1, mListView.getSelectedItemPosition());
+
+ assertEquals("seperator should be scrolled flush with top",
+ mListView.getListPaddingTop(), mListView.getChildAt(0).getTop());
+ }
+
+ @MediumTest
+ public void testGoingDownSkipsOverUnselectable() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("should have skipped to next selectable ",
+ 3,
+ mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testGoingUpSkippingOverUnselectable() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertEquals(1, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
new file mode 100644
index 0000000..2c0c2d8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/AdjacentListsWithAdjacentISVsInsideTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.AdjacentListsWithAdjacentISVsInside;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ListView;
+
+public class AdjacentListsWithAdjacentISVsInsideTest extends ActivityInstrumentationTestCase<AdjacentListsWithAdjacentISVsInside> {
+
+ private ListView mLeftListView;
+ private InternalSelectionView mLeftIsv;
+ private InternalSelectionView mLeftMiddleIsv;
+ private ListView mRightListView;
+ private InternalSelectionView mRightMiddleIsv;
+ private InternalSelectionView mRightIsv;
+
+ public AdjacentListsWithAdjacentISVsInsideTest() {
+ super("com.android.frameworktest", AdjacentListsWithAdjacentISVsInside.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ final AdjacentListsWithAdjacentISVsInside a = getActivity();
+ mLeftListView = a.getLeftListView();
+ mLeftIsv = a.getLeftIsv();
+ mLeftMiddleIsv = a.getLeftMiddleIsv();
+ mRightListView = a.getRightListView();
+ mRightMiddleIsv = a.getRightMiddleIsv();
+ mRightIsv = a.getRightIsv();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue(mLeftListView.hasFocus());
+ assertTrue(mLeftIsv.isFocused());
+ assertEquals(0, mLeftIsv.getSelectedRow());
+ }
+
+ /**
+ * rockinist test name to date!
+ */
+ @MediumTest
+ public void testFocusedRectAndFocusHintWorkWithinListItemHorizontal() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals(1, mLeftIsv.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertTrue(mLeftListView.hasFocus());
+ assertTrue(mLeftMiddleIsv.isFocused());
+ assertEquals("mLeftMiddleIsv.getSelectedRow()", 1, mLeftMiddleIsv.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+ assertTrue(mLeftIsv.isFocused());
+ assertEquals("mLeftIsv.getSelectedRow()", 1, mLeftIsv.getSelectedRow());
+ }
+
+ @MediumTest
+ public void testFocusTransfersOutsideOfListWhenNoCandidateInsideHorizontal() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_RIGHT);
+
+ assertTrue(mLeftListView.hasFocus());
+ assertTrue(mLeftMiddleIsv.isFocused());
+ assertEquals(2, mLeftMiddleIsv.getSelectedRow());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertTrue("mRightListView.hasFocus()", mRightListView.hasFocus());
+ assertTrue("mRightMiddleIsv.isFocused()", mRightMiddleIsv.isFocused());
+ assertEquals("mRightMiddleIsv.getSelectedRow()", 2, mRightMiddleIsv.getSelectedRow());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
new file mode 100644
index 0000000..c54add3
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListButtonsDiagonalAcrossItemsTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.ListButtonsDiagonalAcrossItems;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+/**
+ * Test that ListView will override default behavior of focus searching to
+ * make sure going right and left doesn't change selection
+ */
+public class ListButtonsDiagonalAcrossItemsTest extends ActivityInstrumentationTestCase<ListButtonsDiagonalAcrossItems> {
+
+ private Button mLeftButton;
+ private Button mCenterButton;
+ private Button mRightButton;
+ private ListView mListView;
+
+ public ListButtonsDiagonalAcrossItemsTest() {
+ super("com.android.frameworktest", ListButtonsDiagonalAcrossItems.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mLeftButton = getActivity().getLeftButton();
+ mCenterButton = getActivity().getCenterButton();
+ mRightButton = getActivity().getRightButton();
+
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ final ListView lv = mListView;
+ assertEquals("num children", 3, lv.getChildCount());
+
+ assertEquals("selected position", 0, lv.getSelectedItemPosition());
+ assertTrue("left button focused", mLeftButton.isFocused());
+
+ assertTrue("left left of center",
+ mLeftButton.getRight()
+ < mCenterButton.getLeft());
+
+ assertTrue("center left of right",
+ mCenterButton.getRight()
+ < mRightButton.getLeft());
+
+ assertEquals("focus search right from left button should be center button",
+ mCenterButton,
+ FocusFinder.getInstance().findNextFocus(mListView, mLeftButton, View.FOCUS_RIGHT));
+ assertEquals("focus search right from center button should be right button",
+ mRightButton,
+ FocusFinder.getInstance().findNextFocus(mListView, mCenterButton, View.FOCUS_RIGHT));
+ assertEquals("focus search left from centr button should be left button",
+ mLeftButton,
+ FocusFinder.getInstance().findNextFocus(mListView, mCenterButton, View.FOCUS_LEFT));
+ }
+
+ @MediumTest
+ public void testGoingRightDoesNotChangeSelection() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+ assertEquals("selected position shouldn't have changed",
+ 0,
+ mListView.getSelectedItemPosition());
+ assertTrue("left should still be focused", mLeftButton.isFocused());
+ }
+
+ @MediumTest
+ public void testGoingLeftDoesNotChangeSelection() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("list view postion", 1, mListView.getSelectedItemPosition());
+ assertTrue("mCenterButton.isFocused()", mCenterButton.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+ assertEquals("selected position shouldn't have changed",
+ 1,
+ mListView.getSelectedItemPosition());
+ assertTrue("center should still be focused", mCenterButton.isFocused());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
new file mode 100644
index 0000000..35f9b06
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListHorizontalFocusWithinItemWinsTest.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.focus;
+
+import com.android.frameworktest.listview.ListHorizontalFocusWithinItemWins;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.FocusFinder;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+public class ListHorizontalFocusWithinItemWinsTest extends ActivityInstrumentationTestCase<ListHorizontalFocusWithinItemWins> {
+
+ private ListView mListView;
+ private Button mTopLeftButton;
+ private Button mTopRightButton;
+ private Button mBottomMiddleButton;
+
+ public ListHorizontalFocusWithinItemWinsTest() {
+ super("com.android.frameworktest", ListHorizontalFocusWithinItemWins.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mListView = getActivity().getListView();
+ mTopLeftButton = getActivity().getTopLeftButton();
+ mTopRightButton = getActivity().getTopRightButton();
+ mBottomMiddleButton = getActivity().getBottomMiddleButton();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertEquals("list position", 0, mListView.getSelectedItemPosition());
+ assertTrue("mTopLeftButton.isFocused()", mTopLeftButton.isFocused());
+ assertEquals("global focus search to right from top left is bottom middle",
+ mBottomMiddleButton,
+ FocusFinder.getInstance().findNextFocus(mListView, mTopLeftButton, View.FOCUS_RIGHT));
+ assertEquals("global focus search to left from top right is bottom middle",
+ mBottomMiddleButton,
+ FocusFinder.getInstance().findNextFocus(mListView, mTopRightButton, View.FOCUS_LEFT));
+ }
+
+ @MediumTest
+ public void testOptionWithinItemTrumpsGlobal() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+ assertEquals("list position", 0, mListView.getSelectedItemPosition());
+ assertTrue("mTopRightButton.isFocused()", mTopRightButton.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT);
+ assertEquals("list position", 0, mListView.getSelectedItemPosition());
+ assertTrue("mTopLeftButton.isFocused()", mTopLeftButton.isFocused());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java
new file mode 100644
index 0000000..dea689f
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/focus/ListWithEditTextHeaderTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.focus;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.KeyEvent;
+import android.widget.AbsListView;
+import android.widget.ListView;
+import com.android.frameworktest.listview.ListWithEditTextHeader;
+
+public class ListWithEditTextHeaderTest extends ActivityInstrumentationTestCase<ListWithEditTextHeader> {
+ private ListView mListView;
+
+ public ListWithEditTextHeaderTest() {
+ super("com.android.frameworktest", ListWithEditTextHeader.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("listview.getItemsCanFocus()", mListView.getItemsCanFocus());
+ assertFalse("out of touch-mode", mListView.isInTouchMode());
+ assertEquals("header view count", 1, mListView.getHeaderViewsCount());
+ assertTrue("header has focus", mListView.getChildAt(0).isFocused());
+ }
+
+ @FlakyTest(tolerance=2)
+ @LargeTest
+ public void testClickingHeaderKeepsFocus() {
+ TouchUtils.clickView(this, mListView.getChildAt(0));
+ assertTrue("header has focus", mListView.getChildAt(0).isFocused());
+ assertEquals("nothing selected", AbsListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testClickingHeaderWhenOtherItemHasFocusGivesHeaderFocus() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertEquals("selected position", 1, mListView.getSelectedItemPosition());
+ TouchUtils.clickView(this, mListView.getChildAt(0));
+ assertTrue("header has focus", mListView.getChildAt(0).isFocused());
+ assertEquals("nothing selected", AbsListView.INVALID_POSITION, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java
new file mode 100644
index 0000000..3a75f93
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListGetSelectedViewTest.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.widget.ListView;
+import android.view.View;
+
+import com.android.frameworktest.listview.ListGetSelectedView;
+
+/**
+ * This test is made to check that getSelectedView() will return
+ * null in touch mode.
+ */
+public class ListGetSelectedViewTest extends ActivityInstrumentationTestCase<ListGetSelectedView> {
+ private ListGetSelectedView mActivity;
+ private ListView mListView;
+
+ public ListGetSelectedViewTest() {
+ super("com.android.frameworktest", ListGetSelectedView.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testGetSelectedView() {
+ View last = mListView.getChildAt(1);
+ TouchUtils.clickView(this, last);
+
+ assertNull(mListView.getSelectedItem());
+ assertNull(mListView.getSelectedView());
+ assertEquals(-1, mListView.getSelectedItemPosition());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java
new file mode 100644
index 0000000..f8b384d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListOfTouchablesTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListOfTouchables;
+import android.test.TouchUtils;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen.
+ */
+public class ListOfTouchablesTest extends ActivityInstrumentationTestCase<ListOfTouchables> {
+ private ListOfTouchables mActivity;
+ private ListView mListView;
+
+ public ListOfTouchablesTest() {
+ super("com.android.frameworktest", ListOfTouchables.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ @LargeTest
+ public void testShortScroll() {
+ View firstChild = mListView.getChildAt(0);
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int firstTop = firstChild.getTop();
+
+ TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ 0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+
+ View newFirstChild = mListView.getChildAt(0);
+
+ assertEquals("View scrolled too early", firstTop, newFirstChild.getTop() + 10);
+ assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+ }
+
+ @LargeTest
+ public void testLongScroll() {
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ int distance = TouchUtils.dragViewToY(this, lastChild,
+ Gravity.TOP | Gravity.LEFT, mListView.getTop());
+
+ assertEquals("View scrolled to wrong position",
+ lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java
new file mode 100644
index 0000000..c3d7264
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListSetSelectionTest.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListSimple;
+
+/**
+ * Tests setting the selection in touch mode
+ */
+public class ListSetSelectionTest extends ActivityInstrumentationTestCase<ListSimple> {
+ private ListSimple mActivity;
+ private ListView mListView;
+
+ public ListSetSelectionTest() {
+ super("com.android.frameworktest", ListSimple.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+ }
+
+ @LargeTest
+ public void testSetSelection() {
+ TouchUtils.dragQuarterScreenDown(this);
+ TouchUtils.dragQuarterScreenUp(this);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ final int targetPosition = mListView.getAdapter().getCount() / 2;
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setSelection(targetPosition);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ boolean found = false;
+ int childCount = mListView.getChildCount();
+ for (int i=0; i<childCount; i++) {
+ View child = mListView.getChildAt(i);
+ if (child.getId() == targetPosition) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Selected item not visible in list", found);
+ }
+
+ @LargeTest
+ public void testSetSelectionFromTop() {
+ TouchUtils.dragQuarterScreenDown(this);
+ TouchUtils.dragQuarterScreenUp(this);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ final int targetPosition = mListView.getAdapter().getCount() / 2;
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setSelectionFromTop(targetPosition, 100);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ View target = null;
+ boolean found = false;
+ int childCount = mListView.getChildCount();
+ for (int i=0; i<childCount; i++) {
+ View child = mListView.getChildAt(i);
+ if (child.getId() == targetPosition) {
+ target = child;
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Selected item not visible in list", found);
+
+ if (target != null) {
+ assertEquals("Selection not at correct location", 100 + mListView.getPaddingTop(),
+ target.getTop());
+ }
+ }
+
+ @LargeTest
+ public void testSetSelection0() {
+ TouchUtils.dragQuarterScreenDown(this);
+ TouchUtils.dragQuarterScreenDown(this);
+ TouchUtils.dragQuarterScreenDown(this);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ mListView.setSelection(0);
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+
+ boolean found = false;
+ int childCount = mListView.getChildCount();
+ for (int i=0; i<childCount; i++) {
+ View child = mListView.getChildAt(i);
+ if (child.getId() == 0 && i == 0) {
+ found = true;
+ break;
+ }
+ }
+ assertTrue("Selected item not visible in list", found);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java
new file mode 100644
index 0000000..d271564
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityManyTest.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravityMany;
+
+/**
+ * Touch tests for a list where all of the items do not fit on the screen, and the list
+ * stacks from the bottom.
+ */
+public class ListTouchBottomGravityManyTest extends ActivityInstrumentationTestCase<ListBottomGravityMany> {
+ private ListBottomGravityMany mActivity;
+ private ListView mListView;
+
+ public ListTouchBottomGravityManyTest() {
+ super("com.android.frameworktest", ListBottomGravityMany.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // Last item should be selected
+ assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+ }
+
+ @LargeTest
+ public void testPullDown() {
+ int originalCount = mListView.getChildCount();
+
+ TouchUtils.scrollToTop(this, mListView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ View firstChild = mListView.getChildAt(0);
+
+ assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+
+ assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+ firstChild.getTop());
+
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mListView.getChildCount(), originalCount + 1),
+ mListView.getChildCount() <= originalCount + 1);
+ }
+
+ @MediumTest
+ public void testPushUp() {
+ TouchUtils.scrollToBottom(this, mListView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ assertEquals("Last item is not touching the bottom edge",
+ mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+ @MediumTest
+ public void testNoScroll() {
+ View firstChild = mListView.getChildAt(0);
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
+ 0, ViewConfiguration.getTouchSlop());
+
+ View newLastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ assertEquals("View scrolled too early", lastTop, newLastChild.getTop());
+ assertEquals("Wrong view in last position", mListView.getAdapter().getCount() - 1,
+ newLastChild.getId());
+ }
+
+ @LargeTest
+ public void testShortScroll() {
+ View firstChild = mListView.getChildAt(0);
+ if (firstChild.getTop() < this.mListView.getListPaddingTop()) {
+ firstChild = mListView.getChildAt(1);
+ }
+
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ TouchUtils.dragViewBy(this, firstChild, Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL,
+ 0, ViewConfiguration.getTouchSlop() + 1 + 10);
+
+ View newLastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ assertEquals("View scrolled to wrong position", lastTop, newLastChild.getTop() - 10);
+ assertEquals("Wrong view in last position", mListView.getAdapter().getCount() - 1,
+ newLastChild.getId());
+ }
+
+ @LargeTest
+ public void testLongScroll() {
+ View firstChild = mListView.getChildAt(0);
+ if (firstChild.getTop() < mListView.getListPaddingTop()) {
+ firstChild = mListView.getChildAt(1);
+ }
+
+ int firstTop = firstChild.getTop();
+
+ int distance = TouchUtils.dragViewBy(this, firstChild,
+ Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
+ (int)(mActivity.getWindowManager().getDefaultDisplay().getHeight() * 0.75f));
+
+ assertEquals("View scrolled to wrong position", firstTop
+ + (distance - ViewConfiguration.getTouchSlop() - 1), firstChild.getTop());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java
new file mode 100644
index 0000000..78d39fb
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchBottomGravityTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListBottomGravity;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen, and the list
+ * stacks from the bottom.
+ */
+public class ListTouchBottomGravityTest extends ActivityInstrumentationTestCase<ListBottomGravity> {
+ private ListBottomGravity mActivity;
+ private ListView mListView;
+
+ public ListTouchBottomGravityTest() {
+ super("com.android.frameworktest", ListBottomGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // First item should be selected
+ assertEquals(mListView.getAdapter().getCount() - 1, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testPullDown() {
+ View firstChild = mListView.getChildAt(0);
+
+ TouchUtils.dragViewToBottom(this, firstChild);
+
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ assertEquals("Last item is not touching the bottom edge",
+ mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+ @MediumTest
+ public void testPushUp() {
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ TouchUtils.dragViewToTop(this, lastChild);
+
+ lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ assertEquals("Last item is not touching the bottom edge",
+ mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java
new file mode 100644
index 0000000..ef085f8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchManyTest.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListTopGravityMany;
+
+/**
+ * Touch tests for a list where all of the items do not fit on the screen.
+ */
+public class ListTouchManyTest extends ActivityInstrumentationTestCase<ListTopGravityMany> {
+ private ListTopGravityMany mActivity;
+ private ListView mListView;
+
+ public ListTouchManyTest() {
+ super("com.android.frameworktest", ListTopGravityMany.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // First item should be selected
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testPullDown() {
+ TouchUtils.scrollToTop(this, mListView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ View firstChild = mListView.getChildAt(0);
+
+ assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+
+ assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+ firstChild.getTop());
+ }
+
+ @LargeTest
+ public void testPushUp() {
+ int originalCount = mListView.getChildCount();
+
+ TouchUtils.scrollToBottom(this, mListView);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ assertEquals("List is not scrolled to the bottom", mListView.getAdapter().getCount() - 1,
+ lastChild.getId());
+
+ assertEquals("Last item is not touching the bottom edge",
+ mListView.getHeight() - mListView.getListPaddingBottom(), lastChild.getBottom());
+
+ assertTrue(String.format("Too many children created: %d expected no more than %d",
+ mListView.getChildCount(), originalCount + 1),
+ mListView.getChildCount() <= originalCount + 1);
+ }
+
+ @LargeTest
+ public void testPress() {
+ int i;
+ int count = mListView.getChildCount();
+ mActivity.setClickedPosition(-1);
+ mActivity.setLongClickedPosition(-1);
+
+ for (i = 0; i < count; i++) {
+ View child = mListView.getChildAt(i);
+ if ((child.getTop() >= mListView.getListPaddingTop())
+ && (child.getBottom() <=
+ mListView.getHeight() - mListView.getListPaddingBottom())) {
+ TouchUtils.clickView(this, child);
+
+ assertEquals("Incorrect view position reported being clicked", i,
+ mActivity.getClickedPosition());
+ assertEquals("View falsely reported being long clicked", -1,
+ mActivity.getLongClickedPosition());
+ try {
+ Thread.sleep((long)(ViewConfiguration.getLongPressTimeout() * 1.25f));
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
+ @LargeTest
+ public void testLongPress() {
+ int i;
+ int count = mListView.getChildCount();
+ mActivity.enableLongPress();
+ mActivity.setClickedPosition(-1);
+ mActivity.setLongClickedPosition(-1);
+
+ for (i = 0; i < count; i++) {
+ View child = mListView.getChildAt(i);
+ if ((child.getTop() >= mListView.getListPaddingTop())
+ && (child.getBottom() <=
+ mListView.getHeight() - mListView.getListPaddingBottom())) {
+ TouchUtils.longClickView(this, child);
+ assertEquals("Incorrect view position reported being long clicked", i,
+ mActivity.getLongClickedPosition());
+ assertEquals("View falsely reported being clicked", -1,
+ mActivity.getClickedPosition());
+ }
+ }
+ }
+
+ @MediumTest
+ public void testNoScroll() {
+ View firstChild = mListView.getChildAt(0);
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int firstTop = firstChild.getTop();
+
+ TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ 0, -(ViewConfiguration.getTouchSlop()));
+
+ View newFirstChild = mListView.getChildAt(0);
+
+ assertEquals("View scrolled too early", firstTop, newFirstChild.getTop());
+ assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+ }
+
+ @LargeTest
+ public void testShortScroll() {
+ View firstChild = mListView.getChildAt(0);
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int firstTop = firstChild.getTop();
+
+ TouchUtils.dragViewBy(this, lastChild, Gravity.TOP | Gravity.LEFT,
+ 0, -(ViewConfiguration.getTouchSlop() + 1 + 10));
+
+ View newFirstChild = mListView.getChildAt(0);
+
+ assertEquals("View scrolled too early", firstTop, newFirstChild.getTop() + 10);
+ assertEquals("Wrong view in first position", 0, newFirstChild.getId());
+ }
+
+ @LargeTest
+ public void testLongScroll() {
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ int lastTop = lastChild.getTop();
+
+ int distance = TouchUtils.dragViewToY(this, lastChild,
+ Gravity.TOP | Gravity.LEFT, mListView.getTop());
+
+ assertEquals("View scrolled to wrong position",
+ lastTop - (distance - ViewConfiguration.getTouchSlop() - 1), lastChild.getTop());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java
new file mode 100644
index 0000000..4e5c423
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/listview/touch/ListTouchTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.listview.touch;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.widget.ListView;
+
+import com.android.frameworktest.listview.ListTopGravity;
+
+/**
+ * Touch tests for a list where all of the items fit on the screen.
+ */
+public class ListTouchTest extends ActivityInstrumentationTestCase<ListTopGravity> {
+ private ListTopGravity mActivity;
+ private ListView mListView;
+
+ public ListTouchTest() {
+ super("com.android.frameworktest", ListTopGravity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mListView = getActivity().getListView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertNotNull(mListView);
+
+ // First item should be selected
+ assertEquals(0, mListView.getSelectedItemPosition());
+ }
+
+ @MediumTest
+ public void testPullDown() {
+ View firstChild = mListView.getChildAt(0);
+
+ TouchUtils.dragViewToBottom(this, firstChild);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ firstChild = mListView.getChildAt(0);
+
+ assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+
+ assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+ firstChild.getTop());
+ }
+
+ @MediumTest
+ public void testPushUp() {
+ View lastChild = mListView.getChildAt(mListView.getChildCount() - 1);
+
+ TouchUtils.dragViewToTop(this, lastChild);
+
+ // Nothing should be selected
+ assertEquals("Selection still available after touch", -1,
+ mListView.getSelectedItemPosition());
+
+ View firstChild = mListView.getChildAt(0);
+
+ assertEquals("Item zero not the first child in the list", 0, firstChild.getId());
+
+ assertEquals("Item zero not at the top of the list", mListView.getListPaddingTop(),
+ firstChild.getTop());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java
new file mode 100644
index 0000000..38cb6a1
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutLandscapeTest.java
@@ -0,0 +1,230 @@
+/**
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.IconMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase;
+
+public class MenuLayoutLandscapeTest extends ActivityInstrumentationTestCase<MenuLayoutLandscape> {
+ private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+ private static final String SHORT_TITLE = "Item";
+
+ private MenuLayout mActivity;
+
+ public MenuLayoutLandscapeTest() {
+ super("com.android.frameworktest", MenuLayoutLandscape.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ }
+
+ private void toggleMenu() {
+ getInstrumentation().waitForIdleSync();
+ KeyUtils.tapMenuKey(this);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ /**
+ * Asserts the layout of the menu.
+ *
+ * @param expectedLayout The number of parameters is the number of rows, and
+ * each parameter is how many items on that row (the first
+ * parameter is the top-most row).
+ */
+ private void assertLayout(Integer... expectedLayout) {
+ toggleMenu();
+
+ IconMenuView iconMenuView = ((IconMenuView) mActivity.getMenuView(MenuBuilder.TYPE_ICON));
+ int[] layout = iconMenuView.getLayout();
+ int layoutNumRows = iconMenuView.getLayoutNumRows();
+
+ int expectedRows = expectedLayout.length;
+ assertEquals("Row mismatch", expectedRows, layoutNumRows);
+
+ for (int row = 0; row < expectedRows; row++) {
+ assertEquals("Col mismatch on row " + row, expectedLayout[row].intValue(),
+ layout[row]);
+ }
+ }
+
+ public void test1ShortItem() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(1)
+ .setItemTitle(0, SHORT_TITLE));
+ assertLayout(1);
+ }
+
+ public void test1LongItem() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(1)
+ .setItemTitle(0, LONG_TITLE));
+ assertLayout(1);
+ }
+
+ public void test2LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(2)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE));
+ assertLayout(1, 1);
+ }
+
+ public void test2ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(2)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE));
+ assertLayout(2);
+ }
+
+ public void test3ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ assertLayout(3);
+ }
+
+ public void test3VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ assertLayout(1, 2);
+ }
+
+ public void test3VarietyItems2() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ assertLayout(1, 2);
+ }
+
+ public void test4LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE));
+ assertLayout(2, 2);
+ }
+
+ public void test4ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE));
+ assertLayout(4);
+ }
+
+ public void test4VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE));
+ assertLayout(2, 2);
+ }
+
+ public void test5ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, SHORT_TITLE));
+ assertLayout(5);
+ }
+
+ public void test5LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, LONG_TITLE));
+ assertLayout(2, 3);
+ }
+
+ public void test5VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, LONG_TITLE));
+ assertLayout(2, 3);
+ }
+
+ public void test6LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, LONG_TITLE)
+ .setItemTitle(5, LONG_TITLE));
+ assertLayout(3, 3);
+ }
+
+ public void test6ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, SHORT_TITLE)
+ .setItemTitle(5, SHORT_TITLE));
+ assertLayout(6);
+ }
+
+ public void test6VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, SHORT_TITLE)
+ .setItemTitle(5, SHORT_TITLE));
+ assertLayout(3, 3);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java
new file mode 100644
index 0000000..a04ec62
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuLayoutPortraitTest.java
@@ -0,0 +1,231 @@
+/**
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy
+ * of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations
+ * under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.IconMenuView;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.content.pm.ActivityInfo;
+import android.test.ActivityInstrumentationTestCase;
+
+public class MenuLayoutPortraitTest extends ActivityInstrumentationTestCase<MenuLayoutPortrait> {
+ private static final String LONG_TITLE = "Really really really really really really really really really really long title";
+ private static final String SHORT_TITLE = "Item";
+
+ private MenuLayout mActivity;
+
+ public MenuLayoutPortraitTest() {
+ super("com.android.frameworktest", MenuLayoutPortrait.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ }
+
+ private void toggleMenu() {
+ getInstrumentation().waitForIdleSync();
+ KeyUtils.tapMenuKey(this);
+ getInstrumentation().waitForIdleSync();
+ }
+
+ /**
+ * Asserts the layout of the menu.
+ *
+ * @param expectedLayout The number of parameters is the number of rows, and
+ * each parameter is how many items on that row.
+ */
+ private void assertLayout(Integer... expectedLayout) {
+ toggleMenu();
+
+ IconMenuView iconMenuView = ((IconMenuView) mActivity.getMenuView(MenuBuilder.TYPE_ICON));
+ int[] layout = iconMenuView.getLayout();
+ int layoutNumRows = iconMenuView.getLayoutNumRows();
+
+ int expectedRows = expectedLayout.length;
+ assertEquals("Row mismatch", expectedRows, layoutNumRows);
+
+ for (int row = 0; row < expectedRows; row++) {
+ assertEquals("Col mismatch on row " + row, expectedLayout[row].intValue(),
+ layout[row]);
+ }
+ }
+
+ public void test1ShortItem() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(1)
+ .setItemTitle(0, SHORT_TITLE));
+ assertLayout(1);
+ }
+
+ public void test1LongItem() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(1)
+ .setItemTitle(0, LONG_TITLE));
+ assertLayout(1);
+ }
+
+ public void test2LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(2)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE));
+ assertLayout(1, 1);
+ }
+
+ public void test2ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(2)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE));
+ assertLayout(2);
+ }
+
+ public void test3ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ assertLayout(3);
+ }
+
+ public void test3VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ // We maintain the order added, so there must be 3 rows
+ assertLayout(1, 1, 1);
+ }
+
+ public void test3VarietyItems2() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(3)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE));
+ // The long can fit in first row, and two shorts in second
+ assertLayout(1, 2);
+ }
+
+ public void test4LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE));
+ assertLayout(1, 1, 2);
+ }
+
+ public void test4ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE));
+ assertLayout(2, 2);
+ }
+
+ public void test4VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(4)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE));
+ assertLayout(1, 1, 2);
+ }
+
+ public void test5ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, SHORT_TITLE));
+ assertLayout(2, 3);
+ }
+
+ public void test5LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, LONG_TITLE));
+ assertLayout(1, 2, 2);
+ }
+
+ public void test5VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(5)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, LONG_TITLE));
+ assertLayout(1, 2, 2);
+ }
+
+ public void test6LongItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, LONG_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, LONG_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, LONG_TITLE)
+ .setItemTitle(5, LONG_TITLE));
+ assertLayout(2, 2, 2);
+ }
+
+ public void test6ShortItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, SHORT_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, SHORT_TITLE)
+ .setItemTitle(4, SHORT_TITLE)
+ .setItemTitle(5, SHORT_TITLE));
+ assertLayout(3, 3);
+ }
+
+ public void test6VarietyItems() {
+ mActivity.setParams(new MenuScenario.Params()
+ .setNumItems(6)
+ .setItemTitle(0, SHORT_TITLE)
+ .setItemTitle(1, LONG_TITLE)
+ .setItemTitle(2, SHORT_TITLE)
+ .setItemTitle(3, LONG_TITLE)
+ .setItemTitle(4, SHORT_TITLE)
+ .setItemTitle(5, SHORT_TITLE));
+ assertLayout(2, 2, 2);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java
new file mode 100644
index 0000000..286533c
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/menus/MenuWith1ItemTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.menus;
+
+import com.android.frameworktest.menus.MenuWith1Item;
+import com.android.frameworktest.util.KeyUtils;
+import com.android.internal.view.menu.MenuBuilder;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+
+public class MenuWith1ItemTest extends ActivityInstrumentationTestCase<MenuWith1Item> {
+ private MenuWith1Item mActivity;
+
+ public MenuWith1ItemTest() {
+ super("com.android.frameworktest", MenuWith1Item.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mActivity);
+ assertFalse(mActivity.getButton().isInTouchMode());
+ }
+
+ @MediumTest
+ public void testItemClick() {
+
+ // Open menu, click on an item
+ KeyUtils.tapMenuKey(this);
+ getInstrumentation().waitForIdleSync();
+ assertFalse("Item seems to have been clicked before we clicked on it", mActivity
+ .wasItemClicked(0));
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ assertTrue("Item doesn't seem to have registered our click", mActivity.wasItemClicked(0));
+ }
+
+ @LargeTest
+ public void testTouchModeTransfersRemovesFocus() throws Exception {
+ // open menu, move around to give it focus
+ sendKeys(KeyEvent.KEYCODE_MENU, KeyEvent.KEYCODE_DPAD_LEFT);
+ final View menuItem = mActivity.getItemView(MenuBuilder.TYPE_ICON, 0);
+ assertTrue("menuItem.isFocused()", menuItem.isFocused());
+
+ // close the menu
+ sendKeys(KeyEvent.KEYCODE_MENU);
+ Thread.sleep(500);
+
+ // touch the screen
+ TouchUtils.clickView(this, mActivity.getButton());
+ assertTrue("should be in touch mode after touching button",
+ mActivity.getButton().isInTouchMode());
+
+ // open the menu, menu item shouldn't be focused, because we are not
+ // in touch mode
+ sendKeys(KeyEvent.KEYCODE_MENU);
+ assertTrue("menuItem.isInTouchMode()", menuItem.isInTouchMode());
+ assertFalse("menuItem.isFocused()", menuItem.isFocused());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java
new file mode 100644
index 0000000..e4dd2b8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ButtonAboveTallInternalSelectionViewTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.ButtonAboveTallInternalSelectionView;
+import com.android.frameworktest.util.InternalSelectionView;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+public class ButtonAboveTallInternalSelectionViewTest extends
+ ActivityInstrumentationTestCase<ButtonAboveTallInternalSelectionView> {
+
+ public ButtonAboveTallInternalSelectionViewTest() {
+ super("com.android.frameworktest", ButtonAboveTallInternalSelectionView.class);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("expecting the top button to have focus",
+ getActivity().getButtonAbove().isFocused());
+ assertEquals("scrollview scroll y",
+ 0,
+ getActivity().getScrollView().getScrollY());
+ assertTrue("internal selection view should be taller than screen",
+ getActivity().getIsv().getHeight() > getActivity().getScrollView().getHeight());
+
+ assertTrue("top of ISV should be on screen",
+ getActivity().getIsv().getTop() >
+ getActivity().getScrollView().getScrollY());
+
+ }
+
+ @MediumTest
+ public void testMovingFocusDownToItemTallerThanScreenStillOnScreen() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+
+ final InternalSelectionView isv = getActivity().getIsv();
+ assertTrue("internal selection view should have taken focus",
+ isv.isFocused());
+ assertEquals("internal selection view selected row",
+ 0, isv.getSelectedRow());
+ assertTrue("top of ISV should still be on screen",
+ getActivity().getIsv().getTop() >
+ getActivity().getScrollView().getScrollY());
+ }
+
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java
new file mode 100644
index 0000000..3eec37b
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleTest.java
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.RequestRectangleVisible;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.view.View;
+import android.view.KeyEvent;
+
+/**
+ * {@link RequestRectangleVisible} is set up to exercise the cases of moving a
+ * rectangle that is either off screen or not entirely on the screen onto the screen.
+ */
+public class RequestRectangleVisibleTest extends ActivityInstrumentationTestCase<RequestRectangleVisible> {
+
+ private ScrollView mScrollView;
+
+ private Button mClickToScrollFromAbove;
+ private Button mClickToScrollToUpperBlob;
+ private TextView mTopBlob;
+
+ private View mChildToScrollTo;
+
+ private TextView mBottomBlob;
+ private Button mClickToScrollToBlobLowerBlob;
+ private Button mClickToScrollFromBelow;
+
+ public RequestRectangleVisibleTest() {
+ super("com.android.frameworktest", RequestRectangleVisible.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ RequestRectangleVisible a = getActivity();
+
+ mScrollView = (ScrollView) a.findViewById(R.id.scrollView);
+ mClickToScrollFromAbove = (Button) a.findViewById(R.id.scrollToRectFromTop);
+ mClickToScrollToUpperBlob = (Button) a.findViewById(R.id.scrollToRectFromTop2);
+ mTopBlob = (TextView) a.findViewById(R.id.topBlob);
+ mChildToScrollTo = a.findViewById(R.id.childToMakeVisible);
+ mBottomBlob = (TextView) a.findViewById(R.id.bottomBlob);
+ mClickToScrollToBlobLowerBlob = (Button) a.findViewById(R.id.scrollToRectFromBottom2);
+ mClickToScrollFromBelow = (Button) a.findViewById(R.id.scrollToRectFromBottom);
+
+
+ }
+
+
+ @MediumTest
+ public void testPreconditions() {
+ assertNotNull(mScrollView);
+ assertNotNull(mClickToScrollFromAbove);
+ assertNotNull(mClickToScrollToUpperBlob);
+ assertNotNull(mTopBlob);
+ assertNotNull(mChildToScrollTo);
+ assertNotNull(mBottomBlob);
+ assertNotNull(mClickToScrollToBlobLowerBlob);
+ assertNotNull(mClickToScrollFromBelow);
+
+ assertTrue("top blob needs to be taller than the screen for many of the "
+ + "tests below to work.",
+ mTopBlob.getHeight() > mScrollView.getHeight());
+
+ assertTrue("bottom blob needs to be taller than the screen for many of the "
+ + "tests below to work.",
+ mBottomBlob.getHeight() > mScrollView.getHeight());
+
+ assertTrue("top blob needs to be lower than the fading edge region",
+ mTopBlob.getTop() > mScrollView.getVerticalFadingEdgeLength());
+ }
+
+ @MediumTest
+ public void testScrollToOffScreenRectangleFromTop() {
+ // view is off screen
+ assertTrue(mClickToScrollFromAbove.hasFocus());
+ ViewAsserts.assertOffScreenBelow(mScrollView, mChildToScrollTo);
+
+ // click
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync(); // wait for scrolling to finish
+
+ // should be on screen, positioned at the bottom (with room for
+ // fading edge)
+ ViewAsserts.assertOnScreen(mScrollView, mChildToScrollTo);
+ ViewAsserts.assertHasScreenCoordinates(
+ mScrollView, mChildToScrollTo,
+ 0,
+ mScrollView.getHeight()
+ - mChildToScrollTo.getHeight()
+ - mScrollView.getVerticalFadingEdgeLength());
+ }
+
+ @MediumTest
+ public void testScrollToPartiallyOffScreenRectFromTop() {
+ pressDownUntilViewInFocus(mClickToScrollToUpperBlob, 4);
+
+ // make sure the blob is indeed partially on screen below
+ assertOnBottomEdgeOfScreen(mScrollView, mTopBlob);
+
+ // click
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync(); // wait for scrolling to finish
+
+ // blob should have moved so top of it is at top of screen (with
+ // room for the vertical fading edge
+ ViewAsserts.assertHasScreenCoordinates(
+ mScrollView, mTopBlob, 0, mScrollView.getVerticalFadingEdgeLength());
+ }
+
+ @LargeTest
+ public void testScrollToOffScreenRectangleFromBottom() {
+ // go to bottom button
+ pressDownUntilViewInFocus(mClickToScrollFromBelow, 10);
+
+ // view is off screen above
+ assertTrue(mClickToScrollFromBelow.hasFocus());
+ ViewAsserts.assertOffScreenAbove(mScrollView, mChildToScrollTo);
+
+ // click
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync(); // wait for scrolling to finish
+
+ // on screen, positioned at top (with room for fading edge)
+ ViewAsserts.assertOnScreen(mScrollView, mChildToScrollTo);
+ ViewAsserts.assertHasScreenCoordinates(
+ mScrollView, mChildToScrollTo, 0, mScrollView.getVerticalFadingEdgeLength());
+ }
+
+
+ @LargeTest
+ public void testScrollToPartiallyOffScreenRectFromBottom() {
+ pressDownUntilViewInFocus(mClickToScrollToBlobLowerBlob, 10);
+
+ // make sure the blob is indeed partially on screen above
+ assertOnTopEdgeOfScreen(mScrollView, mBottomBlob);
+
+ // click
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync(); // wait for scrolling to finish
+
+ // blob should have moved so bottom of it is at bottom of screen
+ // with room for vertical fading edge
+ ViewAsserts.assertHasScreenCoordinates(
+ mScrollView, mBottomBlob,
+ 0,
+ mScrollView.getHeight() - mBottomBlob.getHeight()
+ - mScrollView.getVerticalFadingEdgeLength());
+ }
+
+
+ /**
+ * Press the down key until a particular view is in focus
+ * @param view The view to get in focus.
+ * @param maxKeyPress The maximum times to press down before failing.
+ */
+ private void pressDownUntilViewInFocus(View view, int maxKeyPress) {
+ int count = 0;
+ while(!view.hasFocus()) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ getInstrumentation().waitForIdleSync();
+
+ // just in case...
+ if (++count > maxKeyPress) {
+ fail("couldn't move down to bottom button within "
+ + maxKeyPress + " key presses.");
+ }
+ }
+ }
+
+ /**
+ * Assert that view overlaps the bottom edge of the screen
+ * @param origin The root view of the screen.
+ * @param view The view
+ */
+ static public void assertOnBottomEdgeOfScreen(View origin, View view) {
+ int[] xy = new int[2];
+ view.getLocationOnScreen(xy);
+
+ int[] xyRoot = new int[2];
+ origin.getLocationOnScreen(xyRoot);
+
+ int bottom = xy[1] + view.getHeight();
+ int bottomOfRoot = xyRoot[1] + origin.getHeight();
+
+ assertTrue(bottom > bottomOfRoot);
+
+ assertTrue(xy[1] < bottomOfRoot);
+ assertTrue(bottom > bottomOfRoot);
+ }
+
+ /**
+ * Assert that view overlaps the bottom edge of the screen
+ * @param origin The root view of the screen.
+ * @param view The view
+ */
+ static public void assertOnTopEdgeOfScreen(View origin, View view) {
+ int[] xy = new int[2];
+ view.getLocationOnScreen(xy);
+
+ int[] xyRoot = new int[2];
+ origin.getLocationOnScreen(xyRoot);
+
+ int bottom = xy[1] + view.getHeight();
+ int bottomOfRoot = xyRoot[1] + origin.getHeight();
+
+ assertTrue(bottom < bottomOfRoot);
+ assertTrue(bottom > xyRoot[1]);
+
+ assertTrue(xy[1] < xyRoot[1]);
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java
new file mode 100644
index 0000000..5d71466
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/RequestRectangleVisibleWithInternalScrollTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.ViewAsserts;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+/**
+ * This is suppressed because {@link TextView#scrollBy} isn't working.
+ */
+@Suppress
+public class RequestRectangleVisibleWithInternalScrollTest
+ extends ActivityInstrumentationTestCase<RequestRectangleVisibleWithInternalScroll> {
+
+ private TextView mTextBlob;
+ private Button mScrollToBlob;
+
+ private ScrollView mScrollView;
+
+
+ public RequestRectangleVisibleWithInternalScrollTest() {
+ super("com.android.frameworktest",
+ RequestRectangleVisibleWithInternalScroll.class);
+ }
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mTextBlob = getActivity().getTextBlob();
+ mScrollToBlob = getActivity().getScrollToBlob();
+
+ mScrollView = (ScrollView) getActivity().findViewById(R.id.scrollView);
+ }
+
+ public void testPreconditions() {
+ assertNotNull(mTextBlob);
+ assertNotNull(mScrollToBlob);
+ assertEquals(getActivity().getScrollYofBlob(), mTextBlob.getScrollY());
+ }
+
+ public void testMoveToChildWithScrollYBelow() {
+ assertTrue(mScrollToBlob.hasFocus());
+
+ ViewAsserts.assertOffScreenBelow(mScrollView, mTextBlob);
+
+ // click
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync(); // wait for scrolling to finish
+
+ // should be on screen, positioned at the bottom (with enough room for
+ // fading edge)
+ ViewAsserts.assertOnScreen(mScrollView, mTextBlob);
+ ViewAsserts.assertHasScreenCoordinates(
+ mScrollView, mTextBlob,
+ 0,
+ mScrollView.getHeight()
+ - mTextBlob.getHeight()
+ - mScrollView.getVerticalFadingEdgeLength());
+
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java
new file mode 100644
index 0000000..b23b567
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/ScrollViewButtonsAndLabelsTest.java
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll;
+
+import com.android.frameworktest.scroll.ScrollViewButtonsAndLabels;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.view.KeyEvent;
+
+
+public class ScrollViewButtonsAndLabelsTest
+ extends ActivityInstrumentationTestCase<ScrollViewButtonsAndLabels> {
+
+ private ScrollView mScrollView;
+ private LinearLayout mLinearLayout;
+ private int mScreenBottom;
+ private int mScreenTop;
+
+ public ScrollViewButtonsAndLabelsTest() {
+ super("com.android.frameworktest",
+ ScrollViewButtonsAndLabels.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mScrollView = getActivity().getScrollView();
+ mLinearLayout = getActivity().getLinearLayout();
+
+ int origin[] = {0, 0};
+ mScrollView.getLocationOnScreen(origin);
+ mScreenTop = origin[1];
+ mScreenBottom = origin[1] + mScrollView.getHeight();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("vertical fading edge width needs to be non-zero for this "
+ + "test to be worth anything",
+ mScrollView.getVerticalFadingEdgeLength() > 0);
+ }
+
+ // moving down to something off screen should move the element
+ // onto the screen just above the vertical fading edge
+ @LargeTest
+ public void testArrowScrollDownOffScreenVerticalFadingEdge() {
+
+ int offScreenIndex = findFirstButtonOffScreenTop2Bottom();
+ Button firstButtonOffScreen = getActivity().getButton(offScreenIndex);
+
+ for (int i = 0; i < offScreenIndex; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ getInstrumentation().waitForIdleSync();
+ assertTrue(firstButtonOffScreen.hasFocus());
+
+ assertTrue("the button we've moved to off screen must not be the last "
+ + "button in the scroll view for this test to work (since we "
+ + "are expecting the fading edge to be there).",
+ offScreenIndex < getActivity().getNumButtons());
+
+ // now we are at the first button off screen
+ int buttonLoc[] = {0, 0};
+ firstButtonOffScreen.getLocationOnScreen(buttonLoc);
+ int buttonBottom = buttonLoc[1] + firstButtonOffScreen.getHeight();
+
+ int verticalFadingEdgeLength = mScrollView
+ .getVerticalFadingEdgeLength();
+ assertEquals("bottom of button should be verticalFadingEdgeLength "
+ + "above the bottom of the screen",
+ buttonBottom, mScreenBottom - verticalFadingEdgeLength);
+ }
+
+ // there should be no offset for vertical fading edge
+ // if the item is the last one on screen
+ @LargeTest
+ public void testArrowScrollDownToBottomElementOnScreen() {
+
+ int numGroups = getActivity().getNumButtons();
+ Button lastButton = getActivity().getButton(numGroups - 1);
+
+ assertEquals("button needs to be at the very bottom of the layout for "
+ + "this test to work",
+ mLinearLayout.getHeight(), lastButton.getBottom());
+
+ // move down to last button
+ for (int i = 0; i < numGroups; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ getInstrumentation().waitForIdleSync();
+ assertTrue("last button should have focus", lastButton.hasFocus());
+
+ int buttonLoc[] = {0, 0};
+ lastButton.getLocationOnScreen(buttonLoc);
+ int buttonBottom = buttonLoc[1] + lastButton.getHeight();
+ assertEquals("button should be at very bottom of screen",
+ mScreenBottom, buttonBottom);
+ }
+
+ @LargeTest
+ public void testArrowScrollUpOffScreenVerticalFadingEdge() {
+ // get to bottom button
+ int numGroups = goToBottomButton();
+
+ // go up to first off screen button
+ int offScreenIndex = findFirstButtonOffScreenBottom2Top();
+ Button offScreenButton = getActivity().getButton(offScreenIndex);
+ int clicksToOffScreenIndex = numGroups - offScreenIndex - 1;
+ for (int i = 0; i < clicksToOffScreenIndex; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ getInstrumentation().waitForIdleSync();
+ assertTrue("we want to be at offScreenButton", offScreenButton.hasFocus());
+
+ // top should take into account fading edge
+ int buttonLoc[] = {0, 0};
+ offScreenButton.getLocationOnScreen(buttonLoc);
+ assertEquals("top should take into account fading edge",
+ mScreenTop + mScrollView.getVerticalFadingEdgeLength(), buttonLoc[1]);
+ }
+
+
+ @LargeTest
+ public void testArrowScrollUpToTopElementOnScreen() {
+ // get to bottom button
+ int numButtons = goToBottomButton();
+
+ // go back to the top
+ for (int i = 0; i < numButtons; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+ getInstrumentation().waitForIdleSync();
+
+ Button topButton = getActivity().getButton(0);
+ assertTrue("should be back at top button", topButton.hasFocus());
+
+
+ int buttonLoc[] = {0, 0};
+ topButton.getLocationOnScreen(buttonLoc);
+ assertEquals("top of top button should be at top of screen; no need to take"
+ + " into account vertical fading edge.",
+ mScreenTop, buttonLoc[1]);
+ }
+
+ private int goToBottomButton() {
+ int numButtons = getActivity().getNumButtons();
+ Button lastButton = getActivity().getButton(numButtons - 1);
+
+ for (int i = 0; i < numButtons; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ getInstrumentation().waitForIdleSync();
+ assertTrue("we want to be at the last button", lastButton.hasFocus());
+ return numButtons;
+ }
+
+ // search from top to bottom for the first button off screen
+ private int findFirstButtonOffScreenTop2Bottom() {
+ int origin[] = {0, 0};
+ mScrollView.getLocationOnScreen(origin);
+ int screenHeight = mScrollView.getHeight();
+
+ for (int i = 0; i < getActivity().getNumButtons(); i++) {
+
+ int buttonLoc[] = {0, 0};
+ Button button = getActivity().getButton(i);
+ button.getLocationOnScreen(buttonLoc);
+
+ if (buttonLoc[1] - origin[1] > screenHeight) {
+ return i;
+ }
+ }
+ fail("couldn't find first button off screen");
+ return -1; // this won't execute, but the compiler needs it
+ }
+
+ private int findFirstButtonOffScreenBottom2Top() {
+ int origin[] = {0, 0};
+ mScrollView.getLocationOnScreen(origin);
+
+ for (int i = getActivity().getNumButtons() - 1; i >= 0; i--) {
+
+ int buttonLoc[] = {0, 0};
+ Button button = getActivity().getButton(i);
+ button.getLocationOnScreen(buttonLoc);
+
+ if (buttonLoc[1] < 0) {
+ return i;
+ }
+ }
+ fail("couldn't find first button off screen");
+ return -1; // this won't execute, but the compiler needs it
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
new file mode 100644
index 0000000..6b78560
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ButtonsWithTallTextViewInBetweenTest.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.ButtonsWithTallTextViewInBetween;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+public class ButtonsWithTallTextViewInBetweenTest
+ extends ActivityInstrumentationTestCase<ButtonsWithTallTextViewInBetween> {
+
+ private ScrollView mScrollView;
+ private Button mTopButton;
+ private TextView mMiddleFiller;
+ private TextView mBottomButton;
+
+ public ButtonsWithTallTextViewInBetweenTest() {
+ super("com.android.frameworktest", ButtonsWithTallTextViewInBetween.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mScrollView = getActivity().getScrollView();
+ mTopButton = getActivity().getTopButton();
+ mMiddleFiller = getActivity().getMiddleFiller();
+ mBottomButton = getActivity().getBottomButton();
+ }
+
+ private Rect mTempRect = new Rect();
+
+ private int getTopWithinScrollView(View descendant) {
+ descendant.getDrawingRect(mTempRect);
+ mScrollView.offsetDescendantRectToMyCoords(descendant, mTempRect);
+ return mTempRect.top;
+ }
+
+ private int getBottomWithinScrollView(View descendant) {
+ descendant.getDrawingRect(mTempRect);
+ mScrollView.offsetDescendantRectToMyCoords(descendant, mTempRect);
+ return mTempRect.bottom;
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("top button should be shorter than max scroll amount",
+ mTopButton.getHeight() <
+ mScrollView.getMaxScrollAmount());
+ assertTrue("bottom button should be further than max scroll amount off screen",
+ getTopWithinScrollView(mBottomButton)- mScrollView.getBottom() > mScrollView.getMaxScrollAmount());
+ }
+
+ @MediumTest
+ public void testPanTopButtonOffScreenLosesFocus() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertEquals("scroll view should be scrolled by the max amount for one "
+ + "arrow navigation",
+ mScrollView.getMaxScrollAmount(),
+ mScrollView.getScrollY());
+
+ assertTrue("top button should be off screen",
+ getBottomWithinScrollView(mTopButton) < mScrollView.getScrollY());
+
+ assertFalse("top button should have lost focus",
+ mTopButton.isFocused());
+
+ assertTrue("scroll view should be focused", mScrollView.isFocused());
+ }
+
+ @MediumTest
+ public void testScrollDownToBottomButton() throws Exception {
+ final int screenBottom = mScrollView.getScrollY() + mScrollView.getHeight();
+ final int numDownsToButtonButton =
+ ((getBottomWithinScrollView(mBottomButton) - screenBottom)) / mScrollView.getMaxScrollAmount() + 1;
+
+ for (int i = 0; i < numDownsToButtonButton; i++) {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ assertTrue("bottombutton.isFocused", mBottomButton.isFocused());
+
+ assertEquals("should be fully scrolled to bottom",
+ getActivity().getLinearLayout().getHeight() - mScrollView.getHeight(),
+ mScrollView.getScrollY());
+ }
+
+ @MediumTest
+ public void testPanBottomButtonOffScreenLosesFocus() throws Exception {
+ mBottomButton.post(new Runnable() {
+ public void run() {
+ mBottomButton.requestFocus();
+ }
+ });
+
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("bottombutton.isFocused", mBottomButton.isFocused());
+ final int maxScroll = getActivity().getLinearLayout().getHeight()
+ - mScrollView.getHeight();
+ assertEquals("should be fully scrolled to bottom",
+ maxScroll,
+ mScrollView.getScrollY());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+
+ assertEquals("scroll view should have scrolled by the max amount for one "
+ + "arrow navigation",
+ maxScroll - mScrollView.getMaxScrollAmount(),
+ mScrollView.getScrollY());
+
+ assertTrue("bottom button should be off screen",
+ getTopWithinScrollView(mBottomButton) > mScrollView.getScrollY() + mScrollView.getHeight());
+
+ assertFalse("bottom button should have lost focus",
+ mBottomButton.isFocused());
+
+ assertTrue("scroll view should be focused", mScrollView.isFocused());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java
new file mode 100644
index 0000000..689eb19
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/ShortButtonsTest.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.ShortButtons;
+
+import android.graphics.Rect;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.ScrollView;
+
+public class ShortButtonsTest extends ActivityInstrumentationTestCase<ShortButtons> {
+
+ private ScrollView mScrollView;
+
+ public ShortButtonsTest() {
+ super("com.android.frameworktest", ShortButtons.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mScrollView = getActivity().getScrollView();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("buttons should be shorter than screen",
+ getActivity().getButtonAt(0).getHeight()
+ < mScrollView.getHeight());
+
+ assertTrue("should be enough buttons to have some scrolled off screen",
+ getActivity().getLinearLayout().getHeight()
+ > getActivity().getScrollView().getHeight());
+ }
+
+ @LargeTest
+ public void testScrollDownToBottomThroughButtons() throws Exception {
+ final int numButtons = getActivity().getNumButtons();
+
+ for (int i = 0; i < numButtons; i++) {
+ String prefix = "after " + i + " downs expected button " + i;
+ final Button button = getActivity().getButtonAt(i);
+ assertTrue(prefix + " to have focus", button.isFocused());
+ assertTrue(prefix + " to be on screen", isButtonOnScreen(button));
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+
+ assertEquals("should be fully scrolled to bottom",
+ getActivity().getLinearLayout().getHeight() - mScrollView.getHeight(),
+ mScrollView.getScrollY());
+ }
+
+ @LargeTest
+ public void testScrollFromBottomToTopThroughButtons() throws Exception {
+ final int numButtons = getActivity().getNumButtons();
+
+ final Button lastButton = getActivity().getButtonAt(numButtons - 1);
+
+ lastButton.post(new Runnable() {
+ public void run() {
+ lastButton.requestFocus();
+ }
+ });
+
+ getInstrumentation().waitForIdleSync();
+
+ assertTrue("lastButton.isFocused()", lastButton.isFocused());
+
+ for (int i = numButtons - 1; i >= 0; i--) {
+ String prefix = "after " + i + " ups expected button " + i;
+ final Button button = getActivity().getButtonAt(i);
+ assertTrue(prefix + " to have focus", button.isFocused());
+ assertTrue(prefix + " to be on screen", isButtonOnScreen(button));
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ }
+
+ assertEquals("should be fully scrolled to top",
+ 0,
+ mScrollView.getScrollY());
+ }
+
+ private Rect mTempRect = new Rect();
+ protected boolean isButtonOnScreen(Button b) {
+ b.getDrawingRect(mTempRect);
+ mScrollView.offsetDescendantRectToMyCoords(b, mTempRect);
+ return mTempRect.bottom >= mScrollView.getScrollY()
+ && mTempRect.top <= (mScrollView.getScrollY() + mScrollView.getHeight());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java
new file mode 100644
index 0000000..573045d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/scroll/arrowscroll/TallTextAboveButtonTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.scroll.arrowscroll;
+
+import com.android.frameworktest.scroll.TallTextAboveButton;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+public class TallTextAboveButtonTest extends ActivityInstrumentationTestCase<TallTextAboveButton> {
+ private ScrollView mScrollView;
+ private TextView mTopText;
+ private TextView mBottomButton;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mScrollView = getActivity().getScrollView();
+ mTopText = getActivity().getContentChildAt(0);
+ mBottomButton = getActivity().getContentChildAt(1);
+ }
+
+ public TallTextAboveButtonTest() {
+ super("com.android.frameworktest", TallTextAboveButton.class);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("top text should be larger than screen",
+ mTopText.getHeight() > mScrollView.getHeight());
+ assertTrue("scroll view should have focus (because nothing else focusable "
+ + "is on screen), but " + getActivity().getScrollView().findFocus() + " does instead",
+ getActivity().getScrollView().isFocused());
+ }
+
+ @MediumTest
+ public void testGainFocusAsScrolledOntoScreen() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue("button should have scrolled onto screen",
+ mBottomButton.getBottom() >= mScrollView.getBottom());
+ assertTrue("button should have gained focus as it was scrolled completely "
+ + "into view", mBottomButton.isFocused());
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertTrue("scroll view should have focus, but " + getActivity().getScrollView().findFocus() + " does instead",
+ getActivity().getScrollView().isFocused());
+ }
+
+ @MediumTest
+ public void testScrollingButtonOffScreenLosesFocus() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue("button should have focus", mBottomButton.isFocused());
+ sendKeys(KeyEvent.KEYCODE_DPAD_UP);
+ assertTrue("scroll view should have focus, but " + getActivity().getScrollView().findFocus() + " does instead",
+ getActivity().getScrollView().isFocused());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java
new file mode 100644
index 0000000..42888ff
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/settings/RingtonePickerActivityTest.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.settings;
+
+import com.android.frameworktest.settings.RingtonePickerActivityLauncher;
+
+import android.app.Instrumentation;
+import android.database.Cursor;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.provider.MediaStore;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.Suppress;
+import android.view.KeyEvent;
+
+/**
+ * Tests the RingtonePickerActivity.
+ * <p>
+ * There is a launcher for launching the RingtonePickerActivity (RPA) since the RPA needs
+ * to be a subactivity. We don't have a reference to the actual RPA.
+ * <p>
+ * This relies heavily on keypresses getting to the right widget. It depends on:
+ * <li> Less than NUM_RINGTONES_AND_SOME ringtones on the system
+ * <li> Pressing arrow-down a ton will eventually end up on the 'Cancel' button
+ * <li> From the 'Cancel' button, pressing arrow-left will end up on 'OK' button
+ */
+@Suppress
+public class RingtonePickerActivityTest extends ActivityInstrumentationTestCase<RingtonePickerActivityLauncher> {
+
+ private static final int NUM_RINGTONES_AND_SOME = 20;
+ private RingtonePickerActivityLauncher mActivity;
+ private Instrumentation mInstrumentation;
+
+ public RingtonePickerActivityTest() {
+ super("com.android.frameworktest", RingtonePickerActivityLauncher.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mInstrumentation = getInstrumentation();
+ assertNotNull(mActivity);
+ assertFalse(mActivity.resultReceived);
+ assertNotNull(mInstrumentation);
+ }
+
+ public void testDefault() {
+ mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ // Go to top
+ goTo(true);
+ // Select default ringtone
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ // Go to bottom/cancel button
+ goTo(false);
+ // Select OK button
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNotNull(mActivity.result);
+ assertTrue(RingtoneManager.isDefault(mActivity.pickedUri));
+ }
+
+ public void testFirst() {
+ mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ // Go to top
+ goTo(true);
+ // Select first (non-default) ringtone
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_CENTER);
+ // Go to bottom/cancel button
+ goTo(false);
+ // Select OK button
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNotNull(mActivity.result);
+ assertNotNull(mActivity.pickedUri);
+ assertFalse(RingtoneManager.isDefault(mActivity.pickedUri));
+ }
+
+ public void testExisting() {
+ // We need to get an existing ringtone first, so launch it, pick first,
+ // and keep that URI
+ testFirst();
+ Uri firstUri = mActivity.pickedUri;
+
+ mActivity.launchRingtonePickerActivity(true, firstUri, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ //// Hit cancel:
+
+ // Go to bottom
+ goTo(false);
+ // Select Cancel button
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertEquals(mActivity.pickedUri, firstUri);
+ }
+
+ public void testExistingButDifferent() {
+ // We need to get an existing ringtone first, so launch it, pick first,
+ // and keep that URI
+ testFirst();
+ Uri firstUri = mActivity.pickedUri;
+
+ mActivity.launchRingtonePickerActivity(true, firstUri, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ //// Pick second:
+
+ // Go to top
+ goTo(true);
+ // Select second (non-default) ringtone
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN, KeyEvent.KEYCODE_DPAD_DOWN,
+ KeyEvent.KEYCODE_DPAD_CENTER);
+ // Go to bottom/cancel button
+ goTo(false);
+ // Select OK button
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNotNull(mActivity.result);
+ assertTrue(!firstUri.equals(mActivity.pickedUri));
+ }
+
+ public void testCancel() {
+ mActivity.launchRingtonePickerActivity(true, null, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ // Go to bottom
+ goTo(false);
+ // Select Cancel button
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNull(mActivity.result);
+ }
+
+ public void testNoDefault() {
+ mActivity.launchRingtonePickerActivity(false, null, RingtoneManager.TYPE_ALL);
+ mInstrumentation.waitForIdleSync();
+
+ // Go to top
+ goTo(true);
+ // Select first (non-default) ringtone
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ // Go to bottom/cancel button
+ goTo(false);
+ // Select OK button
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNotNull(mActivity.result);
+ assertNotNull(mActivity.pickedUri);
+ assertFalse(RingtoneManager.isDefault(mActivity.pickedUri));
+ }
+
+ public void testNotifications() {
+ mActivity.launchRingtonePickerActivity(false, null, RingtoneManager.TYPE_NOTIFICATION);
+ mInstrumentation.waitForIdleSync();
+
+ // Move to top of list
+ goTo(true);
+ // Select first ringtone in list
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ // Move all the way down (will focus 'Cancel')
+ goTo(false);
+ // Move left and click (will click 'Ok')
+ sendKeys(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.KEYCODE_DPAD_CENTER);
+
+ // Wait until main thread is idle
+ mInstrumentation.waitForIdleSync();
+
+ assertTrue(mActivity.resultReceived);
+ assertNotNull(mActivity.result);
+ assertNotNull(mActivity.pickedUri);
+
+ // Get the path of the picked ringtone
+ Uri uri = mActivity.pickedUri;
+ Cursor c = mActivity.getContentResolver().query(uri, new String[] { "_data" },
+ null, null, null);
+ assertTrue("Query for selected ringtone URI does not have a result", c.moveToFirst());
+ String path = c.getString(0);
+ // Quick check to see if the ringtone is a notification
+ assertTrue("The path of the selected ringtone did not contain \"notification\"",
+ path.contains("notifications"));
+ }
+
+ private void goTo(boolean top) {
+ // Get to the buttons at the bottom (top == false), or the top (top == true)
+ for (int i = 0; i < NUM_RINGTONES_AND_SOME; i++) {
+ sendKeys(top ? KeyEvent.KEYCODE_DPAD_UP : KeyEvent.KEYCODE_DPAD_DOWN);
+ }
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java
new file mode 100644
index 0000000..9b309c4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/HtmlTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.text;
+
+import android.test.InstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Html;
+import android.text.Spanned;
+import android.text.style.StyleSpan;
+import android.graphics.Typeface;
+
+public class HtmlTest extends InstrumentationTestCase {
+
+ @MediumTest
+ public void testSingleTagOnWhileString() {
+ Spanned spanned = Html.fromHtml("<b>hello</b>");
+ Object[] spans = spanned.getSpans(-1, 100, Object.class);
+ assertEquals(1, spans.length);
+ Object span = spans[0];
+ assertEquals(0, spanned.getSpanStart(span));
+ assertEquals(5, spanned.getSpanEnd(span));
+ }
+
+ @MediumTest
+ public void testEmptyFontTag() {
+ Spanned spanned = Html.fromHtml("Hello <font color=\"#ff00ff00\"></font>");
+ Object[] spans = spanned.getSpans(0, 100, Object.class);
+ // TODO: figure out what the spans should be after the crashes are fixed and assert them.
+ }
+
+ /** Tests that the parser can handle mal-formed HTML. */
+ @MediumTest
+ public void testBadHtml() {
+ Spanned spanned = Html.fromHtml("Hello <b>b<i>bi</b>i</i>");
+ Object[] spans = spanned.getSpans(0, 100, Object.class);
+ assertEquals(Typeface.ITALIC, ((StyleSpan) spans[0]).getStyle());
+ assertEquals(7, spanned.getSpanStart(spans[0]));
+ assertEquals(9, spanned.getSpanEnd(spans[0]));
+ assertEquals(Typeface.BOLD, ((StyleSpan) spans[1]).getStyle());
+ assertEquals(6, spanned.getSpanStart(spans[1]));
+ assertEquals(9, spanned.getSpanEnd(spans[1]));
+ assertEquals(Typeface.ITALIC, ((StyleSpan) spans[2]).getStyle());
+ assertEquals(9, spanned.getSpanStart(spans[2]));
+ assertEquals(10, spanned.getSpanEnd(spans[2]));
+ }
+
+ @MediumTest
+ public void testSymbols() {
+ String spanned = Html.fromHtml("© > <").toString();
+ assertEquals("\u00a9 > <", spanned);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java
new file mode 100644
index 0000000..a807977
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringBuilderTest.java
@@ -0,0 +1,11 @@
+package com.android.frameworktest.text;
+
+import android.text.Spannable;
+import android.text.SpannableStringBuilder;
+
+public class SpannableStringBuilderTest extends SpannableTest {
+
+ protected Spannable newSpannableWithText(String text) {
+ return new SpannableStringBuilder(text);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java
new file mode 100644
index 0000000..311df23
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableStringTest.java
@@ -0,0 +1,11 @@
+package com.android.frameworktest.text;
+
+import android.text.Spannable;
+import android.text.SpannableString;
+
+public class SpannableStringTest extends SpannableTest {
+
+ protected Spannable newSpannableWithText(String text) {
+ return new SpannableString(text);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java
new file mode 100644
index 0000000..a5f6836
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/text/SpannableTest.java
@@ -0,0 +1,34 @@
+package com.android.frameworktest.text;
+
+import android.test.InstrumentationTestCase;
+import android.test.MoreAsserts;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.text.Spannable;
+
+public abstract class SpannableTest extends InstrumentationTestCase {
+
+ protected abstract Spannable newSpannableWithText(String text);
+
+ @MediumTest
+ public void testGetSpans() {
+ Spannable spannable = newSpannableWithText("abcdef");
+ Object emptySpan = new Object();
+ spannable.setSpan(emptySpan, 1, 1, 0);
+ Object unemptySpan = new Object();
+ spannable.setSpan(unemptySpan, 1, 2, 0);
+
+ Object[] spans;
+
+ // Empty spans are included when they merely abut the query region
+ // but other spans are not, unless the query region is empty, in
+ // in which case any abutting spans are returned.
+ spans = spannable.getSpans(0, 1, Object.class);
+ MoreAsserts.assertEquals(new Object[]{emptySpan}, spans);
+ spans = spannable.getSpans(0, 2, Object.class);
+ MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans);
+ spans = spannable.getSpans(1, 2, Object.class);
+ MoreAsserts.assertEquals(new Object[]{emptySpan, unemptySpan}, spans);
+ spans = spannable.getSpans(2, 2, Object.class);
+ MoreAsserts.assertEquals(new Object[]{unemptySpan}, spans);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java
new file mode 100644
index 0000000..d274d0d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/ChangeTouchModeTest.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfButtons1;
+import com.android.frameworktest.layout.linear.LLOfButtons2;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+
+/**
+ * Tests that the touch mode changes from various events, and that the state
+ * persists across activities.
+ */
+public class ChangeTouchModeTest extends ActivityInstrumentationTestCase<LLOfButtons1> {
+
+ public ChangeTouchModeTest() {
+ super("com.android.frameworktest", LLOfButtons1.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testPreconditions() throws Exception {
+ assertFalse("touch mode", getActivity().isInTouchMode());
+ }
+
+ @MediumTest
+ public void testTouchingScreenEntersTouchMode() throws Exception {
+ assertInTouchModeAfterTap(this, getActivity().getFirstButton());
+ assertTrue("touch mode", getActivity().isInTouchMode());
+ }
+
+ // TODO: reenable when more reliable
+ public void DISABLE_testDpadDirectionLeavesTouchMode() throws Exception {
+ assertInTouchModeAfterClick(this, getActivity().getFirstButton());
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+ assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_RIGHT, getActivity().getFirstButton());
+ assertFalse("touch mode", getActivity().isInTouchMode());
+ }
+
+ public void TODO_touchTrackBallMovementLeavesTouchMode() throws Exception {
+
+ }
+
+ @MediumTest
+ public void testTouchModeFalseAcrossActivites() throws Exception {
+
+ getInstrumentation().waitForIdleSync();
+
+ LLOfButtons2 otherActivity = null;
+ try {
+ otherActivity =
+ launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+ assertNotNull(otherActivity);
+ assertFalse(otherActivity.isInTouchMode());
+ } finally {
+ if (otherActivity != null) {
+ otherActivity.finish();
+ }
+ }
+ }
+
+ @LargeTest
+ public void testTouchModeTrueAcrossActivites() throws Exception {
+ assertInTouchModeAfterClick(this, getActivity().getFirstButton());
+ LLOfButtons2 otherActivity = null;
+ try {
+ otherActivity =
+ launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+ assertNotNull(otherActivity);
+ assertTrue(otherActivity.isInTouchMode());
+ } finally {
+ if (otherActivity != null) {
+ otherActivity.finish();
+ }
+ }
+ }
+
+ @LargeTest
+ public void testTouchModeChangedInOtherActivity() throws Exception {
+
+ assertFalse("touch mode", getActivity().isInTouchMode());
+
+ LLOfButtons2 otherActivity = null;
+ try {
+ otherActivity =
+ launchActivity("com.android.frameworktest", LLOfButtons2.class, null);
+ assertNotNull(otherActivity);
+ assertFalse(otherActivity.isInTouchMode());
+ assertInTouchModeAfterClick(this, otherActivity.getFirstButton());
+ assertTrue(otherActivity.isInTouchMode());
+ } finally {
+ if (otherActivity != null) {
+ otherActivity.finish();
+ }
+ }
+
+ // need to wait for async update back to window to occur
+ Thread.sleep(200);
+
+ assertTrue("touch mode", getActivity().isInTouchMode());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java
new file mode 100644
index 0000000..7cd6444
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/FocusableInTouchModeClickTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfTwoFocusableInTouchMode;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class FocusableInTouchModeClickTest extends ActivityInstrumentationTestCase2<LLOfTwoFocusableInTouchMode> {
+
+ public FocusableInTouchModeClickTest() {
+ super("com.android.frameworktest", LLOfTwoFocusableInTouchMode.class);
+ }
+
+ protected void setUp() throws Exception {
+ super.setUp();
+ setActivityInitialTouchMode(true);
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("should start in touch mode", getActivity().getButton1().isInTouchMode());
+ assertTrue(getActivity().getButton1().isFocused());
+ }
+
+ @LargeTest
+ public void testClickGivesFocusNoClickFired() {
+ TouchUtils.clickView(this, getActivity().getButton2());
+ assertTrue("click should give focusable in touch mode focus",
+ getActivity().getButton2().isFocused());
+ assertFalse("getting focus should result in no on click",
+ getActivity().isB2Fired());
+
+ TouchUtils.clickView(this, getActivity().getButton2());
+ assertTrue("subsequent click while focused should fire on click",
+ getActivity().isB2Fired());
+ }
+
+ @MediumTest
+ public void testTapGivesFocusNoClickFired() {
+ TouchUtils.touchAndCancelView(this, getActivity().getButton2());
+ assertFalse("button shouldn't have fired click", getActivity().isB2Fired());
+ assertFalse("button shouldn't have focus", getActivity().getButton2().isFocused());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java
new file mode 100644
index 0000000..6403435
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/StartInTouchWithViewInFocusTest.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLEditTextThenButton;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.EditText;
+
+public class StartInTouchWithViewInFocusTest extends
+ ActivityInstrumentationTestCase2<LLEditTextThenButton> {
+
+ private EditText mEditText;
+
+ private Button mButton;
+
+ public StartInTouchWithViewInFocusTest() {
+ super("com.android.frameworktest", LLEditTextThenButton.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ this.setActivityInitialTouchMode(true);
+ mEditText = getActivity().getEditText();
+ mButton = getActivity().getButton();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertTrue("should start in touch mode", mEditText.isInTouchMode());
+ assertTrue("edit text is focusable in touch mode, should have focus", mEditText.isFocused());
+ }
+
+ // TODO: reenable when more reliable
+ public void DISABLE_testKeyDownLeavesTouchModeAndGoesToNextView() {
+ assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_DOWN, mEditText);
+ assertFalse("should have left touch mode", mEditText.isInTouchMode());
+ assertTrue("should have given focus to next view", mButton.isFocused());
+ }
+
+ // TODO: reenable when more reliable
+ public void DISABLE_testNonDirectionalKeyExitsTouchMode() {
+ assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_A, mEditText);
+ assertFalse("should have left touch mode", mEditText.isInTouchMode());
+ assertTrue("edit text should still have focus", mEditText.isFocused());
+ }
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java
new file mode 100644
index 0000000..1a0c833
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusChangeTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLOfButtons1;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertNotInTouchModeAfterKey;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+/**
+ * Make sure focus isn't kept by buttons when entering touch mode.
+ *
+ * When in touch mode and hitting the d-pad, we should leave touch mode and the
+ * top most focusable gets focus.
+ */
+public class TouchModeFocusChangeTest extends ActivityInstrumentationTestCase<LLOfButtons1> {
+ private LLOfButtons1 mActivity;
+ private Button mFirstButton;
+
+ public TouchModeFocusChangeTest() {
+ super("com.android.frameworktest", LLOfButtons1.class);
+ }
+
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mActivity = getActivity();
+ mFirstButton = mActivity.getFirstButton();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertFalse("we should not be in touch mode", mActivity.isInTouchMode());
+ assertTrue("top button should have focus", mFirstButton.isFocused());
+ }
+
+ @MediumTest
+ public void testTouchButtonNotTakeFocus() {
+ assertInTouchModeAfterTap(this, mFirstButton);
+
+ assertTrue("should be in touch mode", mActivity.isInTouchMode());
+ assertFalse("button.isFocused",
+ mFirstButton.isFocused());
+ assertFalse("button.hasFocus",
+ mFirstButton.hasFocus());
+ assertNull("activity shouldn't have focus", mActivity.getCurrentFocus());
+ assertFalse("linear layout should not have focus",
+ mActivity.getLayout().hasFocus());
+
+ assertTrue("button's onClickListener should have fired",
+ mActivity.buttonClickListenerFired());
+ }
+
+ // TODO: reenable when more reliable
+ public void DISABLE_testLeaveTouchModeWithDpadEvent() {
+ assertInTouchModeAfterClick(this, mFirstButton);
+
+ assertTrue("should be in touch mode", mActivity.isInTouchMode());
+ assertFalse("button should not have focus when touched",
+ mFirstButton.isFocused());
+
+ assertNotInTouchModeAfterKey(this, KeyEvent.KEYCODE_DPAD_RIGHT, mFirstButton);
+ assertFalse("should be out of touch mode", mActivity.isInTouchMode());
+ assertTrue("first button (the top most focusable) should have gained focus",
+ mFirstButton.isFocused());
+ }
+
+
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java
new file mode 100644
index 0000000..86925b5
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/touchmode/TouchModeFocusableTest.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.touchmode;
+
+import com.android.frameworktest.layout.linear.LLEditTextThenButton;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterTap;
+import static com.android.frameworktest.util.TouchModeFlexibleAsserts.assertInTouchModeAfterClick;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+import android.widget.EditText;
+
+/**
+ * Some views, like edit texts, can keep and gain focus even when in touch mode.
+ */
+public class TouchModeFocusableTest extends ActivityInstrumentationTestCase<LLEditTextThenButton> {
+ private EditText mEditText;
+ private Button mButton;
+
+
+ public TouchModeFocusableTest() {
+ super("com.android.frameworktest", LLEditTextThenButton.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mEditText = getActivity().getEditText();
+ mButton = getActivity().getButton();
+ }
+
+ @MediumTest
+ public void testPreconditions() {
+ assertFalse("should not be in touch mode to start off", mButton.isInTouchMode());
+ assertTrue("edit text should have focus", mEditText.isFocused());
+ assertTrue("edit text should be focusable in touch mode", mEditText.isFocusableInTouchMode());
+ }
+
+ @MediumTest
+ public void testClickButtonEditTextKeepsFocus() {
+ assertInTouchModeAfterTap(this, mButton);
+ assertTrue("should be in touch mode", mButton.isInTouchMode());
+ assertTrue("edit text should still have focus", mEditText.isFocused());
+ }
+
+ @LargeTest
+ public void testClickEditTextGivesItFocus() {
+ // go down to button
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+ assertTrue("button should have focus", mButton.isFocused());
+
+ assertInTouchModeAfterClick(this, mEditText);
+ assertTrue("clicking edit text should have entered touch mode", mButton.isInTouchMode());
+ assertTrue("clicking edit text should have given it focus", mEditText.isFocused());
+ }
+
+
+ // entering touch mode takes focus away from the currently focused item if it
+ // isn't focusable in touch mode.
+ @LargeTest
+ public void testEnterTouchModeGivesFocusBackToFocusableInTouchMode() {
+ sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
+
+ assertTrue("button should have focus",
+ mButton.isFocused());
+
+ assertInTouchModeAfterClick(this, mButton);
+ assertTrue("should be in touch mode", mButton.isInTouchMode());
+ assertNull("nothing should have focus", getActivity().getCurrentFocus());
+ assertFalse("layout should not have focus",
+ getActivity().getLayout().hasFocus());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java
new file mode 100644
index 0000000..b5e7473
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/BigCacheTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.BigCache;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.graphics.Bitmap;
+
+/**
+ * Builds the drawing cache of two Views, one smaller than the maximum cache size,
+ * one larger than the maximum cache size. The latter should always have a null
+ * drawing cache.
+ */
+public class BigCacheTest extends ActivityInstrumentationTestCase<BigCache> {
+ private View mTiny;
+ private View mLarge;
+
+ public BigCacheTest() {
+ super("com.android.frameworktest", BigCache.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final BigCache activity = getActivity();
+ mTiny = activity.findViewById(R.id.a);
+ mLarge = activity.findViewById(R.id.b);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mTiny);
+ assertNotNull(mLarge);
+ }
+
+ @MediumTest
+ public void testDrawingCacheBelowMaximumSize() throws Exception {
+ final int max = ViewConfiguration.getMaximumDrawingCacheSize();
+ assertTrue(mTiny.getWidth() * mTiny.getHeight() * 2 < max);
+ assertNotNull(createCacheForView(mTiny));
+ }
+
+ @MediumTest
+ public void testDrawingCacheAboveMaximumSize() throws Exception {
+ final int max = ViewConfiguration.getMaximumDrawingCacheSize();
+ assertTrue(mLarge.getWidth() * mLarge.getHeight() * 2 > max);
+ assertNull(createCacheForView(mLarge));
+ }
+
+ private Bitmap createCacheForView(final View view) {
+ final Bitmap[] cache = new Bitmap[1];
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ view.setDrawingCacheEnabled(true);
+ view.invalidate();
+ view.buildDrawingCache();
+ cache[0] = view.getDrawingCache();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ return cache[0];
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java
new file mode 100644
index 0000000..ef3ecee
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledLongpressTest.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.Longpress;
+import com.android.frameworktest.R;
+import com.android.frameworktest.util.KeyUtils;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+/**
+ * Exercises {@link android.view.View}'s longpress plumbing by testing the
+ * disabled case.
+ */
+public class DisabledLongpressTest extends ActivityInstrumentationTestCase<Longpress> {
+ private View mSimpleView;
+ private boolean mLongClicked;
+
+ public DisabledLongpressTest() {
+ super("com.android.frameworktest", Longpress.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final Longpress a = getActivity();
+ mSimpleView = a.findViewById(R.id.simple_view);
+ mSimpleView.setOnLongClickListener(new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ mLongClicked = true;
+ return true;
+ }
+ });
+ // The View#setOnLongClickListener will ensure the View is long
+ // clickable, we reverse that here
+ mSimpleView.setLongClickable(false);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mLongClicked = false;
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mSimpleView);
+ assertTrue(mSimpleView.hasFocus());
+ assertFalse(mLongClicked);
+ }
+
+ @LargeTest
+ public void testKeypadLongClick() throws Exception {
+ mSimpleView.requestFocus();
+ getInstrumentation().waitForIdleSync();
+ KeyUtils.longClick(this);
+
+ getInstrumentation().waitForIdleSync();
+ assertFalse(mLongClicked);
+ }
+
+ @LargeTest
+ public void testTouchLongClick() throws Exception {
+ TouchUtils.longClickView(this, mSimpleView);
+ getInstrumentation().waitForIdleSync();
+ assertFalse(mLongClicked);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java
new file mode 100644
index 0000000..d9ed033
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/DisabledTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.widget.Button;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * Exercises {@link android.view.View}'s disabled property.
+ */
+public class DisabledTest extends ActivityInstrumentationTestCase<Disabled> {
+ private Button mDisabled;
+ private View mDisabledParent;
+ private boolean mClicked;
+ private boolean mParentClicked;
+
+ public DisabledTest() {
+ super("com.android.frameworktest", Disabled.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final Disabled a = getActivity();
+ mDisabled = (Button) a.findViewById(R.id.disabledButton);
+ mDisabled.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mClicked = true;
+ }
+ });
+
+ mDisabledParent = a.findViewById(R.id.clickableParent);
+ mDisabledParent.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ mParentClicked = true;
+ }
+ });
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mClicked = false;
+ mParentClicked = false;
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mDisabled);
+ assertNotNull(mDisabledParent);
+ assertFalse(mDisabled.isEnabled());
+ assertTrue(mDisabledParent.isEnabled());
+ assertTrue(mDisabled.hasFocus());
+ }
+
+ @MediumTest
+ public void testKeypadClick() throws Exception {
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+ getInstrumentation().waitForIdleSync();
+ assertFalse(mClicked);
+ assertFalse(mParentClicked);
+ }
+
+ @LargeTest
+ public void testTouchClick() throws Exception {
+ TouchUtils.clickView(this, mDisabled);
+ getInstrumentation().waitForIdleSync();
+ assertFalse(mClicked);
+ assertFalse(mParentClicked);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java
new file mode 100644
index 0000000..8a8d728
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/GlobalFocusChangeTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.FlakyTest;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.TouchUtils;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.frameworktest.R;
+
+public class GlobalFocusChangeTest extends ActivityInstrumentationTestCase<GlobalFocusChange> {
+ private GlobalFocusChange mActivity;
+ private View mLeft;
+ private View mRight;
+
+ public GlobalFocusChangeTest() {
+ super("com.android.frameworktest", GlobalFocusChange.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mActivity = getActivity();
+ mLeft = mActivity.findViewById(R.id.left);
+ mRight = mActivity.findViewById(R.id.right);
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ mActivity.reset();
+ super.tearDown();
+ }
+
+ @FlakyTest(tolerance = 4)
+ @LargeTest
+ public void testFocusChange() throws Exception {
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+ assertFalse(mLeft.isFocused());
+ assertTrue(mRight.isFocused());
+
+ assertSame(mLeft, mActivity.mOldFocus);
+ assertSame(mRight, mActivity.mNewFocus);
+ }
+
+ @FlakyTest(tolerance = 4)
+ @MediumTest
+ public void testEnterTouchMode() throws Exception {
+ assertTrue(mLeft.isFocused());
+
+ TouchUtils.tapView(this, mLeft);
+
+ assertSame(mLeft, mActivity.mOldFocus);
+ assertSame(null, mActivity.mNewFocus);
+ }
+
+ @FlakyTest(tolerance = 4)
+ @MediumTest
+ public void testLeaveTouchMode() throws Exception {
+ assertTrue(mLeft.isFocused());
+
+ TouchUtils.tapView(this, mLeft);
+ sendKeys(KeyEvent.KEYCODE_DPAD_RIGHT);
+
+ assertTrue(mLeft.isFocused());
+
+ assertSame(null, mActivity.mOldFocus);
+ assertSame(mLeft, mActivity.mNewFocus);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java
new file mode 100644
index 0000000..dd1382d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/IncludeTest.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.Include;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+
+public class IncludeTest extends ActivityInstrumentationTestCase<Include> {
+ public IncludeTest() {
+ super("com.android.frameworktest", Include.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testIncluded() throws Exception {
+ final Include activity = getActivity();
+
+ final View button1 = activity.findViewById(R.id.included_button);
+ assertNotNull("The layout include_button was not included", button1);
+
+ final View button2 = activity.findViewById(R.id.included_button_overriden);
+ assertNotNull("The layout include_button was not included with overriden id", button2);
+ }
+
+ @MediumTest
+ public void testIncludedWithLayoutParams() throws Exception {
+ final Include activity = getActivity();
+
+ final View button1 = activity.findViewById(R.id.included_button);
+ final View button2 = activity.findViewById(R.id.included_button_overriden);
+
+ assertTrue("Both buttons should have different width",
+ button1.getLayoutParams().width != button2.getLayoutParams().width);
+ assertTrue("Both buttons should have different height",
+ button1.getLayoutParams().height != button2.getLayoutParams().height);
+ }
+
+ @MediumTest
+ public void testIncludedWithVisibility() throws Exception {
+ final Include activity = getActivity();
+ final View button1 = activity.findViewById(R.id.included_button_visibility);
+
+ assertEquals("Included button should be invisible", View.INVISIBLE, button1.getVisibility());
+ }
+
+ @MediumTest
+ public void testIncludedWithSize() throws Exception {
+ final Include activity = getActivity();
+ final View button1 = activity.findViewById(R.id.included_button_with_size);
+
+ final ViewGroup.LayoutParams lp = button1.getLayoutParams();
+ assertEquals("Included button should be 23dip x 23dip", 23, lp.width);
+ assertEquals("Included button should be 23dip x 23dip", 23, lp.height);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java
new file mode 100644
index 0000000..37106f6
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/LongpressTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.Longpress;
+import com.android.frameworktest.R;
+import com.android.frameworktest.util.KeyUtils;
+import android.test.TouchUtils;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+/**
+ * Exercises {@link android.view.View}'s longpress plumbing.
+ */
+public class LongpressTest extends ActivityInstrumentationTestCase<Longpress> {
+ private View mSimpleView;
+ private boolean mLongClicked;
+
+ public LongpressTest() {
+ super("com.android.frameworktest", Longpress.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final Longpress a = getActivity();
+ mSimpleView = a.findViewById(R.id.simple_view);
+ mSimpleView.setOnLongClickListener(new OnLongClickListener() {
+ public boolean onLongClick(View v) {
+ mLongClicked = true;
+ return true;
+ }
+ });
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+
+ mLongClicked = false;
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mSimpleView);
+ assertTrue(mSimpleView.hasFocus());
+ assertFalse(mLongClicked);
+ }
+
+ @LargeTest
+ public void testKeypadLongClick() throws Exception {
+ mSimpleView.requestFocus();
+ getInstrumentation().waitForIdleSync();
+ KeyUtils.longClick(this);
+
+ getInstrumentation().waitForIdleSync();
+ assertTrue(mLongClicked);
+ }
+
+ @LargeTest
+ public void testTouchLongClick() throws Exception {
+ TouchUtils.longClickView(this, mSimpleView);
+ getInstrumentation().waitForIdleSync();
+ assertTrue(mLongClicked);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java
new file mode 100644
index 0000000..612ebd4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/MergeTest.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.Merge;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.ViewGroup;
+
+public class MergeTest extends ActivityInstrumentationTestCase<Merge> {
+ public MergeTest() {
+ super("com.android.frameworktest", Merge.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testMerged() throws Exception {
+ final Merge activity = getActivity();
+ final ViewGroup layout = activity.getLayout();
+
+ assertEquals("The layout wasn't merged", 7, layout.getChildCount());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java
new file mode 100644
index 0000000..3dcb252
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RemoteViewsActivityTest.java
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.os.Parcel;
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.InflateException;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RemoteViews;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.view.RemoteViewsActivity;
+
+public class RemoteViewsActivityTest extends ActivityInstrumentationTestCase<RemoteViewsActivity> {
+ public RemoteViewsActivityTest() {
+ super("com.android.frameworktest", RemoteViewsActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testGood() throws Exception {
+ final RemoteViewsActivity activity = getActivity();
+
+ RemoteViews orig = new RemoteViews("com.android.frameworktest",
+ R.layout.remote_view_test_good);
+ Parcel p = Parcel.obtain();
+ orig.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+
+ ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+
+ View result = r.apply(activity, parent);
+
+ p.recycle();
+
+ assertTrue("LinearLayout not inflated", result.findViewById(R.id.linear) != null);
+ assertTrue("TextView not inflated", result.findViewById(R.id.text) != null);
+ assertTrue("ImageView not inflated", result.findViewById(R.id.image) != null);
+ assertTrue("FrameLayout not inflated", result.findViewById(R.id.frame) != null);
+ assertTrue("RelateiveLayout not inflated", result.findViewById(R.id.relative) != null);
+ assertTrue("AbsoluteLayout not inflated", result.findViewById(R.id.absolute) != null);
+ assertTrue("ProgressBar not inflated", result.findViewById(R.id.progress) != null);
+ assertTrue("ImageButton not inflated", result.findViewById(R.id.image_button) != null);
+ assertTrue("Button not inflated", result.findViewById(R.id.button) != null);
+ }
+
+ @MediumTest
+ public void testDerivedClass() throws Exception {
+ final RemoteViewsActivity activity = getActivity();
+
+ RemoteViews orig = new RemoteViews("com.android.frameworktest",
+ R.layout.remote_view_test_bad_1);
+ Parcel p = Parcel.obtain();
+ orig.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+
+ ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+
+ boolean exceptionThrown = false;
+ View result = null;
+
+ try {
+ result = r.apply(activity, parent);
+ } catch (InflateException e) {
+ exceptionThrown = true;
+ }
+
+ p.recycle();
+
+ assertTrue("Derived class (EditText) allowed to be inflated", exceptionThrown);
+ assertNull("Derived class (EditText) allowed to be inflated", result);
+ }
+
+ @MediumTest
+ public void testWebView() throws Exception {
+ final RemoteViewsActivity activity = getActivity();
+
+ RemoteViews orig = new RemoteViews("com.android.frameworktest",
+ R.layout.remote_view_test_bad_2);
+ Parcel p = Parcel.obtain();
+ orig.writeToParcel(p, 0);
+ p.setDataPosition(0);
+
+ RemoteViews r = RemoteViews.CREATOR.createFromParcel(p);
+
+ ViewGroup parent = (ViewGroup) activity.findViewById(R.id.parent);
+
+ boolean exceptionThrown = false;
+ View result = null;
+
+ try {
+ result = r.apply(activity, parent);
+ } catch (InflateException e) {
+ exceptionThrown = true;
+ }
+
+ p.recycle();
+
+ assertTrue("WebView allowed to be inflated", exceptionThrown);
+ assertNull("WebView allowed to be inflated", result);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java
new file mode 100644
index 0000000..dc8fcd8
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/RunQueueTest.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+
+public class RunQueueTest extends ActivityInstrumentationTestCase<RunQueue> {
+ public RunQueueTest() {
+ super("com.android.frameworktest", RunQueue.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testRunnableRan() throws Exception {
+ final RunQueue activity = getActivity();
+ getInstrumentation().waitForIdleSync();
+ assertTrue("The runnable did not run", activity.runnableRan);
+ }
+
+ @MediumTest
+ public void testRunnableCancelled() throws Exception {
+ final RunQueue activity = getActivity();
+ getInstrumentation().waitForIdleSync();
+ assertTrue("The runnable was not cancelled", activity.runnableCancelled);
+ }
+
+ @MediumTest
+ public void testListenerFired() throws Exception {
+ final RunQueue activity = getActivity();
+ getInstrumentation().waitForIdleSync();
+ assertTrue("The global layout listener did not fire", activity.globalLayout);
+ }
+
+ @MediumTest
+ public void testTreeObserverKilled() throws Exception {
+ final RunQueue activity = getActivity();
+ getInstrumentation().waitForIdleSync();
+ assertFalse("The view tree observer is still alive", activity.viewTreeObserver.isAlive());
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java
new file mode 100644
index 0000000..fceec51
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewGroupChildrenTest.java
@@ -0,0 +1,268 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.R;
+import com.android.frameworktest.view.ViewGroupChildren;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.ViewAsserts;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+/**
+ * Exercises {@link android.view.ViewGroup}'s ability to add/remove children.
+ */
+public class ViewGroupChildrenTest extends ActivityInstrumentationTestCase<ViewGroupChildren> {
+ private ViewGroup mGroup;
+
+ public ViewGroupChildrenTest() {
+ super("com.android.frameworktest", ViewGroupChildren.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final ViewGroupChildren a = getActivity();
+ mGroup = (ViewGroup) a.findViewById(R.id.group);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mGroup);
+ }
+
+ @MediumTest
+ public void testStartsEmpty() throws Exception {
+ assertEquals("A ViewGroup should have no child by default", 0, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testAddChild() throws Exception {
+ View view = createView("1");
+ mGroup.addView(view);
+
+ assertEquals(1, mGroup.getChildCount());
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupContains(mGroup, view);
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testAddChildAtFront() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ for (int i = 0; i < 24; i++) {
+ View view = createView(String.valueOf(i + 1));
+ mGroup.addView(view);
+ }
+
+ View view = createView("X");
+ mGroup.addView(view, 0);
+
+ assertEquals(25, mGroup.getChildCount());
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupContains(mGroup, view);
+ assertSame(view, mGroup.getChildAt(0));
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testAddChildInMiddle() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ for (int i = 0; i < 24; i++) {
+ View view = createView(String.valueOf(i + 1));
+ mGroup.addView(view);
+ }
+
+ View view = createView("X");
+ mGroup.addView(view, 12);
+
+ assertEquals(25, mGroup.getChildCount());
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupContains(mGroup, view);
+ assertSame(view, mGroup.getChildAt(12));
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testAddChildren() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ for (int i = 0; i < 24; i++) {
+ View view = createView(String.valueOf(i + 1));
+ mGroup.addView(view);
+
+ ViewAsserts.assertGroupContains(mGroup, view);
+ }
+ assertEquals(24, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChild() throws Exception {
+ View view = createView("1");
+ mGroup.addView(view);
+
+ ViewAsserts.assertGroupIntegrity(mGroup);
+
+ mGroup.removeView(view);
+
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupNotContains(mGroup, view);
+
+ assertEquals(0, mGroup.getChildCount());
+ assertNull(view.getParent());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildren() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ for (int i = views.length - 1; i >= 0; i--) {
+ mGroup.removeViewAt(i);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+ assertNull(views[i].getParent());
+ }
+
+ assertEquals(0, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildrenBulk() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ mGroup.removeViews(6, 7);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ for (int i = 6; i < 13; i++) {
+ ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+ assertNull(views[i].getParent());
+ }
+
+ assertEquals(17, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildrenBulkAtFront() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ mGroup.removeViews(0, 7);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ for (int i = 0; i < 7; i++) {
+ ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+ assertNull(views[i].getParent());
+ }
+
+ assertEquals("8", ((TextView) mGroup.getChildAt(0)).getText());
+ assertEquals(17, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildrenBulkAtEnd() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ mGroup.removeViews(17, 7);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ for (int i = 17; i < 24; i++) {
+ ViewAsserts.assertGroupNotContains(mGroup, views[i]);
+ assertNull(views[i].getParent());
+ }
+ assertEquals("17", ((TextView) mGroup.getChildAt(mGroup.getChildCount() - 1)).getText());
+ assertEquals(17, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildAtFront() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ mGroup.removeViewAt(0);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupNotContains(mGroup, views[0]);
+ assertNull(views[0].getParent());
+
+ assertEquals(views.length - 1, mGroup.getChildCount());
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testRemoveChildInMiddle() throws Exception {
+ // 24 should be greater than ViewGroup.ARRAY_CAPACITY_INCREMENT
+ final View[] views = new View[24];
+
+ for (int i = 0; i < views.length; i++) {
+ views[i] = createView(String.valueOf(i + 1));
+ mGroup.addView(views[i]);
+ }
+
+ mGroup.removeViewAt(12);
+ ViewAsserts.assertGroupIntegrity(mGroup);
+ ViewAsserts.assertGroupNotContains(mGroup, views[12]);
+ assertNull(views[12].getParent());
+
+ assertEquals(views.length - 1, mGroup.getChildCount());
+ }
+
+ private TextView createView(String text) {
+ TextView view = new TextView(getActivity());
+ view.setText(text);
+ view.setLayoutParams(new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT
+ ));
+ return view;
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java
new file mode 100644
index 0000000..89bd646
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ViewStubTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.StubbedView;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.test.UiThreadTest;
+import android.view.View;
+import android.view.ViewStub;
+
+public class ViewStubTest extends ActivityInstrumentationTestCase<StubbedView> {
+ public ViewStubTest() {
+ super("com.android.frameworktest", StubbedView.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ }
+
+ @MediumTest
+ public void testStubbed() throws Exception {
+ final StubbedView activity = getActivity();
+
+ final View stub = activity.findViewById(R.id.viewStub);
+ assertNotNull("The ViewStub does not exist", stub);
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testInflated() throws Exception {
+ final StubbedView activity = getActivity();
+
+ final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStub);
+ final View swapped = stub.inflate();
+
+ assertNotNull("The inflated view is null", swapped);
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testInflatedId() throws Exception {
+ final StubbedView activity = getActivity();
+
+ final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStubWithId);
+ final View swapped = stub.inflate();
+
+ assertNotNull("The inflated view is null", swapped);
+ assertTrue("The inflated view has no id", swapped.getId() != View.NO_ID);
+ assertTrue("The inflated view has the wrong id", swapped.getId() == R.id.stub_inflated);
+ }
+
+ @UiThreadTest
+ @MediumTest
+ public void testInflatedLayoutParams() throws Exception {
+ final StubbedView activity = getActivity();
+
+ final ViewStub stub = (ViewStub) activity.findViewById(R.id.viewStubWithId);
+ final View swapped = stub.inflate();
+
+ assertNotNull("The inflated view is null", swapped);
+
+ assertEquals("Both stub and inflated should same width",
+ stub.getLayoutParams().width, swapped.getLayoutParams().width);
+ assertEquals("Both stub and inflated should same height",
+ stub.getLayoutParams().height, swapped.getLayoutParams().height);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java
new file mode 100644
index 0000000..77b281d
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/VisibilityTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.Visibility;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.widget.Button;
+import android.widget.TextView;
+import android.view.View;
+import static android.view.KeyEvent.*;
+
+/**
+ * Exercises {@link android.view.View}'s ability to change visibility between
+ * GONE, VISIBLE and INVISIBLE.
+ */
+public class VisibilityTest extends ActivityInstrumentationTestCase<Visibility> {
+ private TextView mRefUp;
+ private TextView mRefDown;
+ private TextView mVictim;
+ private Button mVisible;
+ private Button mInvisible;
+ private Button mGone;
+
+ public VisibilityTest() {
+ super("com.android.frameworktest", Visibility.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final Visibility a = getActivity();
+ mRefUp = (TextView) a.findViewById(R.id.refUp);
+ mRefDown = (TextView) a.findViewById(R.id.refDown);
+ mVictim = (TextView) a.findViewById(R.id.victim);
+ mVisible = (Button) a.findViewById(R.id.vis);
+ mInvisible = (Button) a.findViewById(R.id.invis);
+ mGone = (Button) a.findViewById(R.id.gone);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mRefUp);
+ assertNotNull(mRefDown);
+ assertNotNull(mVictim);
+ assertNotNull(mVisible);
+ assertNotNull(mInvisible);
+ assertNotNull(mGone);
+
+ assertTrue(mVisible.hasFocus());
+ }
+
+ @MediumTest
+ public void testVisibleToInvisible() throws Exception {
+ sendKeys("DPAD_RIGHT");
+ assertTrue(mInvisible.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+ int newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+ }
+
+ @MediumTest
+ public void testVisibleToGone() throws Exception {
+ //sendKeys("2*DPAD_RIGHT");
+ sendRepeatedKeys(2, KEYCODE_DPAD_RIGHT);
+ assertTrue(mGone.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.GONE, mVictim.getVisibility());
+
+ int refDownTop = mRefDown.getTop();
+ assertEquals(oldTop, refDownTop);
+ }
+
+ @LargeTest
+ public void testGoneToVisible() throws Exception {
+ sendKeys("2*DPAD_RIGHT");
+ assertTrue(mGone.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.GONE, mVictim.getVisibility());
+
+ int refDownTop = mRefDown.getTop();
+ assertEquals(oldTop, refDownTop);
+
+ sendKeys("2*DPAD_LEFT DPAD_CENTER");
+ assertEquals(View.VISIBLE, mVictim.getVisibility());
+
+ int newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+ }
+
+ @MediumTest
+ public void testGoneToInvisible() throws Exception {
+ sendKeys("2*DPAD_RIGHT");
+ assertTrue(mGone.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.GONE, mVictim.getVisibility());
+
+ int refDownTop = mRefDown.getTop();
+ assertEquals(oldTop, refDownTop);
+
+ sendKeys(KEYCODE_DPAD_LEFT, KEYCODE_DPAD_CENTER);
+ assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+ int newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+ }
+
+ @MediumTest
+ public void testInvisibleToVisible() throws Exception {
+ sendKeys("DPAD_RIGHT");
+ assertTrue(mInvisible.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+ int newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+
+ sendKeys("DPAD_LEFT DPAD_CENTER");
+ assertEquals(View.VISIBLE, mVictim.getVisibility());
+
+ newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+ }
+
+ @MediumTest
+ public void testInvisibleToGone() throws Exception {
+ sendKeys("DPAD_RIGHT");
+ assertTrue(mInvisible.hasFocus());
+
+ int oldTop = mVictim.getTop();
+
+ sendKeys("DPAD_CENTER");
+ assertEquals(View.INVISIBLE, mVictim.getVisibility());
+
+ int newTop = mVictim.getTop();
+ assertEquals(oldTop, newTop);
+
+ sendKeys("DPAD_RIGHT DPAD_CENTER");
+ assertEquals(View.GONE, mVictim.getVisibility());
+
+ int refDownTop = mRefDown.getTop();
+ assertEquals(oldTop, refDownTop);
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java
new file mode 100644
index 0000000..cd646e4
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/view/ZeroSizedTest.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.frameworktest.view;
+
+import com.android.frameworktest.view.ZeroSized;
+import com.android.frameworktest.R;
+
+import android.test.ActivityInstrumentationTestCase;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.graphics.Bitmap;
+
+/**
+ * Builds the drawing cache of Views of various dimension. The assumption is that
+ * a View with a 0-sized dimension (width or height) will always have a null
+ * drawing cache.
+ */
+public class ZeroSizedTest extends ActivityInstrumentationTestCase<ZeroSized> {
+ private View mWithDimension;
+ private View mWithNoWdith;
+ private View mWithNoHeight;
+ private View mWithNoDimension;
+
+ public ZeroSizedTest() {
+ super("com.android.frameworktest", ZeroSized.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ final ZeroSized activity = getActivity();
+ mWithDimension = activity.findViewById(R.id.dimension);
+ mWithNoWdith = activity.findViewById(R.id.noWidth);
+ mWithNoHeight = activity.findViewById(R.id.noHeight);
+ mWithNoDimension = activity.findViewById(R.id.noDimension);
+ }
+
+ @MediumTest
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mWithDimension);
+ assertNotNull(mWithNoWdith);
+ assertNotNull(mWithNoHeight);
+ assertNotNull(mWithNoDimension);
+ }
+
+ @MediumTest
+ public void testDrawingCacheWithDimension() throws Exception {
+ assertTrue(mWithDimension.getWidth() > 0);
+ assertTrue(mWithDimension.getHeight() > 0);
+ assertNotNull(createCacheForView(mWithDimension));
+ }
+
+ @MediumTest
+ public void testDrawingCacheWithNoWidth() throws Exception {
+ assertTrue(mWithNoWdith.getWidth() == 0);
+ assertTrue(mWithNoWdith.getHeight() > 0);
+ assertNull(createCacheForView(mWithNoWdith));
+ }
+
+ @MediumTest
+ public void testDrawingCacheWithNoHeight() throws Exception {
+ assertTrue(mWithNoHeight.getWidth() > 0);
+ assertTrue(mWithNoHeight.getHeight() == 0);
+ assertNull(createCacheForView(mWithNoHeight));
+ }
+
+ @MediumTest
+ public void testDrawingCacheWithNoDimension() throws Exception {
+ assertTrue(mWithNoDimension.getWidth() == 0);
+ assertTrue(mWithNoDimension.getHeight() == 0);
+ assertNull(createCacheForView(mWithNoDimension));
+ }
+
+ private Bitmap createCacheForView(final View view) {
+ final Bitmap[] cache = new Bitmap[1];
+ getActivity().runOnUiThread(new Runnable() {
+ public void run() {
+ view.setDrawingCacheEnabled(true);
+ view.invalidate();
+ view.buildDrawingCache();
+ cache[0] = view.getDrawingCache();
+ }
+ });
+ getInstrumentation().waitForIdleSync();
+ return cache[0];
+ }
+}
diff --git a/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
new file mode 100644
index 0000000..ecb7d3a
--- /dev/null
+++ b/tests/FrameworkTest/tests/src/com/android/frameworktest/widget/ListViewTest.java
@@ -0,0 +1,139 @@
+package com.android.frameworktest.widget;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.test.InstrumentationTestCase;
+import android.test.mock.MockContext;
+import android.test.suitebuilder.annotation.MediumTest;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListView;
+
+import java.util.List;
+
+/**
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
+ * in compliance with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
+ * express or implied. See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class ListViewTest extends InstrumentationTestCase {
+
+ /**
+ * If a view in a ListView requests a layout it should be remeasured.
+ */
+ @MediumTest
+ public void testRequestLayout() throws Exception {
+ MockContext context = new MockContext2();
+ ListView listView = new ListView(context);
+ List<String> items = Lists.newArrayList("hello");
+ Adapter<String> adapter = new Adapter<String>(context, 0, items);
+ listView.setAdapter(adapter);
+
+ int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+
+ adapter.notifyDataSetChanged();
+ listView.measure(measureSpec, measureSpec);
+ listView.layout(0, 0, 100, 100);
+
+ MockView childView = (MockView) listView.getChildAt(0);
+
+ childView.requestLayout();
+ childView.onMeasureCalled = false;
+ listView.measure(measureSpec, measureSpec);
+ listView.layout(0, 0, 100, 100);
+ Assert.assertTrue(childView.onMeasureCalled);
+ }
+
+ /**
+ * The list view should handle the disappearance of the only selected item, even when that item
+ * was selected before its disappearance.
+ *
+ */
+ @MediumTest
+ public void testNoSelectableItems() throws Exception {
+ MockContext context = new MockContext2();
+ ListView listView = new ListView(context);
+ // We use a header as the unselectable item to remain after the selectable one is removed.
+ listView.addHeaderView(new View(context), null, false);
+ List<String> items = Lists.newArrayList("hello");
+ Adapter<String> adapter = new Adapter<String>(context, 0, items);
+ listView.setAdapter(adapter);
+
+ listView.setSelection(1);
+
+ int measureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY);
+
+ adapter.notifyDataSetChanged();
+ listView.measure(measureSpec, measureSpec);
+ listView.layout(0, 0, 100, 100);
+
+ items.remove(0);
+
+ adapter.notifyDataSetChanged();
+ listView.measure(measureSpec, measureSpec);
+ listView.layout(0, 0, 100, 100);
+ }
+
+ private class MockContext2 extends MockContext {
+
+ @Override
+ public Resources getResources() {
+ return getInstrumentation().getTargetContext().getResources();
+ }
+
+ @Override
+ public Resources.Theme getTheme() {
+ return getInstrumentation().getTargetContext().getTheme();
+ }
+
+ @Override
+ public Object getSystemService(String name) {
+ if (Context.LAYOUT_INFLATER_SERVICE.equals(name)) {
+ return getInstrumentation().getTargetContext().getSystemService(name);
+ }
+ return super.getSystemService(name);
+ }
+ }
+
+ private class MockView extends View {
+
+ public boolean onMeasureCalled = false;
+
+ public MockView(Context context) {
+ super(context);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ onMeasureCalled = true;
+ }
+ }
+
+ private class Adapter<T> extends ArrayAdapter<T> {
+
+ public Adapter(Context context, int resource, List<T> objects) {
+ super(context, resource, objects);
+ }
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent) {
+ return new MockView(getContext());
+ }
+ }
+
+}
diff --git a/tests/ImfTest/Android.mk b/tests/ImfTest/Android.mk
new file mode 100755
index 0000000..eb5327b
--- /dev/null
+++ b/tests/ImfTest/Android.mk
@@ -0,0 +1,15 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Only compile source java files in this apk.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := ImfTest
+
+include $(BUILD_PACKAGE)
+
+# Use the following include to make our test apk.
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/ImfTest/AndroidManifest.xml b/tests/ImfTest/AndroidManifest.xml
new file mode 100755
index 0000000..55e5d38
--- /dev/null
+++ b/tests/ImfTest/AndroidManifest.xml
@@ -0,0 +1,144 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.imftest">
+
+ <application>
+
+ <activity android:name=".samples.InputTypeActivity" android:label="Input Type Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ButtonActivity" android:label="Button Activity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityNonScrollablePanScan" android:label="Big ET !Scroll Pan/Scan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityNoScrollPanScan" android:label="ManyEditTextActivityNoScrollPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityNonScrollableResize" android:label="Big ET !Scroll Resize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityScrollablePanScan" android:label="Big ET Scroll Pan/Scan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BigEditTextActivityScrollableResize" android:label="Big ET Scroll Resize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.EditTextActivityDialog" android:label="ET Dialog">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityScrollPanScan" android:label="ManyEditTextActivityScrollPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.ManyEditTextActivityScrollResize" android:label="ManyEditTextActivityScrollResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BottomEditTextActivityPanScan" android:label="BottomEditTextActivityPanScan">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.BottomEditTextActivityResize" android:label="BottomEditTextActivityResize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.OneEditTextActivitySelected" android:label="OneEditTextActivitySelected">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.OneEditTextActivityNotSelected" android:label="OneEditTextActivityNotSelected">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.AutoCompleteTextViewActivityPortrait" android:label="AutoCompleteTextViewActivityPortrait" android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.AutoCompleteTextViewActivityLandscape" android:label="AutoCompleteTextViewActivityLandscape" android:screenOrientation="landscape">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ <activity android:name=".samples.DialogActivity" android:label="DialogActivity" android:screenOrientation="portrait">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER" />
+ <category android:name="android.intent.category.IMF_TEST" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
new file mode 100644
index 0000000..e8ffa1c
--- /dev/null
+++ b/tests/ImfTest/res/layout/dialog_edit_text_no_scroll.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2009 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:padding="20dip"
+ android:orientation="vertical">
+
+ <View
+ android:id="@+id/blank"
+ android:layout_height="0dip"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"/>
+
+ <EditText
+ android:id="@+id/dialog_edit_text"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium" />
+
+</LinearLayout>
diff --git a/tests/ImfTest/res/layout/full_screen_edit_text.xml b/tests/ImfTest/res/layout/full_screen_edit_text.xml
new file mode 100755
index 0000000..f22aa2f
--- /dev/null
+++ b/tests/ImfTest/res/layout/full_screen_edit_text.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<EditText xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/data"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:minLines="15"
+ android:gravity="top"/>
+
diff --git a/tests/ImfTest/res/layout/one_edit_text_activity.xml b/tests/ImfTest/res/layout/one_edit_text_activity.xml
new file mode 100755
index 0000000..09925e1
--- /dev/null
+++ b/tests/ImfTest/res/layout/one_edit_text_activity.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:orientation="vertical"
+ android:baselineAligned="false">
+
+ <View android:id="@+id/blank"
+ android:layout_height="0dip"
+ android:layout_width="fill_parent"
+ android:layout_weight="1"
+ />
+
+ <EditText android:id="@+id/dialog_edit_text"
+ android:layout_height="wrap_content"
+ android:layout_width="fill_parent"
+ android:scrollHorizontally="true"
+ android:textAppearance="?android:attr/textAppearanceMedium"
+ />
+ </LinearLayout>
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+</LinearLayout>
diff --git a/tests/ImfTest/res/layout/sample_edit_text.xml b/tests/ImfTest/res/layout/sample_edit_text.xml
new file mode 100755
index 0000000..99a5cf8
--- /dev/null
+++ b/tests/ImfTest/res/layout/sample_edit_text.xml
@@ -0,0 +1,53 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/samples/SampleCode/res/layout/baseline_1.xml
+**
+** Copyright 2007, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+>
+ <LinearLayout
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:minHeight="?android:attr/listPreferredItemHeight"
+ android:orientation="horizontal"
+ android:baselineAligned="false"
+ android:gravity="center_vertical"
+ >
+
+ <TextView android:id="@+id/label"
+ android:layout_width="100dip"
+ android:layout_height="wrap_content"
+ android:gravity="right|center_vertical"
+ />
+
+ <EditText android:id="@+id/data"
+ android:layout_width="0dip"
+ android:layout_weight="1"
+ android:layout_height="wrap_content"
+ android:layout_marginLeft="8dip"
+ />
+ </LinearLayout>
+
+ <View
+ android:layout_width="fill_parent"
+ android:layout_height="1dip"
+ android:background="@android:drawable/divider_horizontal_dark"
+ />
+</LinearLayout>
diff --git a/tests/ImfTest/res/values/config.xml b/tests/ImfTest/res/values/config.xml
new file mode 100644
index 0000000..5ae40a3
--- /dev/null
+++ b/tests/ImfTest/res/values/config.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/**
+ * Copyright (c) 2009, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<resources>
+ <bool name="def_expect_ime_autopop">false</bool>
+</resources>
diff --git a/tests/ImfTest/res/values/strings.xml b/tests/ImfTest/res/values/strings.xml
new file mode 100755
index 0000000..fc87480
--- /dev/null
+++ b/tests/ImfTest/res/values/strings.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+**
+** Copyright 2008, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- Strings for sample activities -->
+ <string name="normal_edit_text_label">Normal</string>
+ <string name="uri_edit_text_label">Uri</string>
+ <string name="email_address_edit_text_label">Email Address</string>
+ <string name="email_subject_edit_text_label">Email Subject</string>
+ <string name="email_content_edit_text_label">Email Content</string>
+ <string name="person_name_edit_text_label">Person Name</string>
+ <string name="postal_address_edit_text_label">Postal Address</string>
+ <string name="password_edit_text_label">Password</string>
+ <string name="search_string_edit_text_label">Search String</string>
+ <string name="web_edit_text_label">Web Edit Text</string>
+ <string name="signed_number_edit_text_label">Signed Number</string>
+ <string name="decimal_number_edit_text_label">Decimal Number</string>
+ <string name="phone_number_edit_text_label">Phone Number</string>
+ <string name="normal_datetime_edit_text_label">Datetime</string>
+ <string name="date_edit_text_label">Date</string>
+ <string name="time_edit_text_label">Time</string>
+ <string name="cap_chars_edit_text_label">Cap Chars</string>
+ <string name="cap_words_edit_text_label">Cap Words</string>
+ <string name="multiline_edit_text_label">Multiline</string>
+ <string name="search_edit_text_label">Search (flag)</string>
+ <string name="cap_sentences_edit_text_label">Cap Sentences</string>
+ <string name="auto_complete_edit_text_label">Auto Complete</string>
+ <string name="auto_correct_edit_text_label">Auto Correct</string>
+ <string name="test_dialog">Test Dialog</string>
+ <string name="open_dialog_scrollable">open scrollable dialog</string>
+ <string name="open_dialog_nonscrollable">open nonscrollable dialog</string>
+
+
+</resources>
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
new file mode 100644
index 0000000..9638d34a
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityLandscape.java
@@ -0,0 +1,85 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.app.ActivityManagerNative;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.provider.MediaStore;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView forced to landscape mode
+ */
+public class AutoCompleteTextViewActivityLandscape extends Activity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.auto_complete_list);
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+ textView.setAdapter(adapter);
+ }
+
+ static final String[] COUNTRIES = new String[] {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+ "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+ "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
new file mode 100644
index 0000000..58651e1
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/AutoCompleteTextViewActivityPortrait.java
@@ -0,0 +1,79 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.widget.AutoCompleteTextView;
+import android.widget.ArrayAdapter;
+
+import com.android.internal.R;
+
+/*
+ * Activity with AutoCompleteTextView (Candidate bar should not appear)
+ */
+public class AutoCompleteTextViewActivityPortrait extends Activity
+{
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.auto_complete_list);
+
+ ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
+ android.R.layout.simple_dropdown_item_1line, COUNTRIES);
+ AutoCompleteTextView textView = (AutoCompleteTextView) findViewById(R.id.edit);
+ textView.setAdapter(adapter);
+ }
+
+ static final String[] COUNTRIES = new String[] {
+ "Afghanistan", "Albania", "Algeria", "American Samoa", "Andorra",
+ "Angola", "Anguilla", "Antarctica", "Antigua and Barbuda", "Argentina",
+ "Armenia", "Aruba", "Australia", "Austria", "Azerbaijan",
+ "Bahrain", "Bangladesh", "Barbados", "Belarus", "Belgium",
+ "Belize", "Benin", "Bermuda", "Bhutan", "Bolivia",
+ "Bosnia and Herzegovina", "Botswana", "Bouvet Island", "Brazil", "British Indian Ocean Territory",
+ "British Virgin Islands", "Brunei", "Bulgaria", "Burkina Faso", "Burundi",
+ "Cote d'Ivoire", "Cambodia", "Cameroon", "Canada", "Cape Verde",
+ "Cayman Islands", "Central African Republic", "Chad", "Chile", "China",
+ "Christmas Island", "Cocos (Keeling) Islands", "Colombia", "Comoros", "Congo",
+ "Cook Islands", "Costa Rica", "Croatia", "Cuba", "Cyprus", "Czech Republic",
+ "Democratic Republic of the Congo", "Denmark", "Djibouti", "Dominica", "Dominican Republic",
+ "East Timor", "Ecuador", "Egypt", "El Salvador", "Equatorial Guinea", "Eritrea",
+ "Estonia", "Ethiopia", "Faeroe Islands", "Falkland Islands", "Fiji", "Finland",
+ "Former Yugoslav Republic of Macedonia", "France", "French Guiana", "French Polynesia",
+ "French Southern Territories", "Gabon", "Georgia", "Germany", "Ghana", "Gibraltar",
+ "Greece", "Greenland", "Grenada", "Guadeloupe", "Guam", "Guatemala", "Guinea", "Guinea-Bissau",
+ "Guyana", "Haiti", "Heard Island and McDonald Islands", "Honduras", "Hong Kong", "Hungary",
+ "Iceland", "India", "Indonesia", "Iran", "Iraq", "Ireland", "Israel", "Italy", "Jamaica",
+ "Japan", "Jordan", "Kazakhstan", "Kenya", "Kiribati", "Kuwait", "Kyrgyzstan", "Laos",
+ "Latvia", "Lebanon", "Lesotho", "Liberia", "Libya", "Liechtenstein", "Lithuania", "Luxembourg",
+ "Macau", "Madagascar", "Malawi", "Malaysia", "Maldives", "Mali", "Malta", "Marshall Islands",
+ "Martinique", "Mauritania", "Mauritius", "Mayotte", "Mexico", "Micronesia", "Moldova",
+ "Monaco", "Mongolia", "Montserrat", "Morocco", "Mozambique", "Myanmar", "Namibia",
+ "Nauru", "Nepal", "Netherlands", "Netherlands Antilles", "New Caledonia", "New Zealand",
+ "Nicaragua", "Niger", "Nigeria", "Niue", "Norfolk Island", "North Korea", "Northern Marianas",
+ "Norway", "Oman", "Pakistan", "Palau", "Panama", "Papua New Guinea", "Paraguay", "Peru",
+ "Philippines", "Pitcairn Islands", "Poland", "Portugal", "Puerto Rico", "Qatar",
+ "Reunion", "Romania", "Russia", "Rwanda", "Sqo Tome and Principe", "Saint Helena",
+ "Saint Kitts and Nevis", "Saint Lucia", "Saint Pierre and Miquelon",
+ "Saint Vincent and the Grenadines", "Samoa", "San Marino", "Saudi Arabia", "Senegal",
+ "Seychelles", "Sierra Leone", "Singapore", "Slovakia", "Slovenia", "Solomon Islands",
+ "Somalia", "South Africa", "South Georgia and the South Sandwich Islands", "South Korea",
+ "Spain", "Sri Lanka", "Sudan", "Suriname", "Svalbard and Jan Mayen", "Swaziland", "Sweden",
+ "Switzerland", "Syria", "Taiwan", "Tajikistan", "Tanzania", "Thailand", "The Bahamas",
+ "The Gambia", "Togo", "Tokelau", "Tonga", "Trinidad and Tobago", "Tunisia", "Turkey",
+ "Turkmenistan", "Turks and Caicos Islands", "Tuvalu", "Virgin Islands", "Uganda",
+ "Ukraine", "United Arab Emirates", "United Kingdom",
+ "United States", "United States Minor Outlying Islands", "Uruguay", "Uzbekistan",
+ "Vanuatu", "Vatican City", "Venezuela", "Vietnam", "Wallis and Futuna", "Western Sahara",
+ "Yemen", "Yugoslavia", "Zambia", "Zimbabwe"
+ };
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
new file mode 100644
index 0000000..9754381
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScan.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollablePanScan extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+
+ ((LinearLayout) mRootView).addView(view);
+
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
new file mode 100644
index 0000000..701795f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResize.java
@@ -0,0 +1,49 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityNonScrollableResize extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((LinearLayout) mRootView), false);
+
+ ((LinearLayout) mRootView).addView(view);
+
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
new file mode 100644
index 0000000..bb3f767
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScan.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollablePanScan extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+
+ mRootView = new ScrollView(this);
+ ((ScrollView) mRootView).setFillViewport(true);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+
+ mLayout.addView(view);
+
+ ((ScrollView) mRootView).addView(mLayout);
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
new file mode 100644
index 0000000..f2cae1c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BigEditTextActivityScrollableResize.java
@@ -0,0 +1,57 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class BigEditTextActivityScrollableResize extends Activity {
+
+ private View mRootView;
+ private View mDefaultFocusedView;
+ private LinearLayout mLayout;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+
+ mRootView = new ScrollView(this);
+ ((ScrollView) mRootView).setFillViewport(true);
+ mRootView.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ View view = getLayoutInflater().inflate(
+ R.layout.full_screen_edit_text, ((ScrollView) mRootView), false);
+
+ mLayout.addView(view);
+
+ ((ScrollView) mRootView).addView(mLayout);
+ mDefaultFocusedView = view.findViewById(R.id.data);
+
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
new file mode 100644
index 0000000..51f5045
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityPanScan.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Pan&Scan)
+ */
+public class BottomEditTextActivityPanScan extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+ mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+ ((LinearLayout) mRootView).addView(view);
+
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
new file mode 100644
index 0000000..eb94b4f
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/BottomEditTextActivityResize.java
@@ -0,0 +1,46 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+import android.widget.TextView;
+
+import com.android.imftest.R;
+
+/*
+ * Activity with EditText at the bottom (Resize)
+ */
+public class BottomEditTextActivityResize extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ View view = getLayoutInflater().inflate(R.layout.one_edit_text_activity, ((LinearLayout) mRootView), false);
+ mDefaultFocusedView = view.findViewById(R.id.dialog_edit_text);
+ ((LinearLayout) mRootView).addView(view);
+
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
new file mode 100644
index 0000000..1191f19
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ButtonActivity.java
@@ -0,0 +1,62 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+
+public class ButtonActivity extends Activity
+{
+ static boolean mKeyboardIsActive = false;
+ public static final int BUTTON_ID = 0;
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ final ButtonActivity instance = this;
+
+ final Button myButton = new Button(this);
+ myButton.setClickable(true);
+ myButton.setText("Keyboard UP!");
+ myButton.setId(BUTTON_ID);
+ myButton.setFocusableInTouchMode(true);
+ myButton.setOnClickListener(new View.OnClickListener()
+ {
+ public void onClick (View v)
+ {
+ InputMethodManager imm = InputMethodManager.getInstance(instance);
+ if (mKeyboardIsActive)
+ {
+ imm.hideSoftInputFromInputMethod(v.getWindowToken(), 0);
+ myButton.setText("Keyboard UP!");
+
+ }
+ else
+ {
+ myButton.requestFocusFromTouch();
+ imm.showSoftInput(v, 0);
+ myButton.setText("Keyboard DOWN!");
+ }
+
+ mKeyboardIsActive = !mKeyboardIsActive;
+ }
+ });
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ layout.addView(myButton);
+ setContentView(layout);
+ mRootView = layout;
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
new file mode 100644
index 0000000..e49301c
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/DialogActivity.java
@@ -0,0 +1,102 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.Button;
+import android.view.LayoutInflater;
+import android.app.Dialog;
+
+import com.android.internal.R;
+
+public class DialogActivity extends Activity {
+
+ private static final int DIALOG_WITHOUT_EDITTEXT = 0;
+ private static final int DIALOG_WITH_EDITTEXT = 1;
+
+ private LinearLayout mLayout;
+ private LayoutInflater mInflater;
+ private Button mButton1;
+ private Button mButton2;
+ private EditText mEditText;
+
+
+ @Override
+ protected void onCreate(Bundle icicle)
+ {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mButton1 = new Button(this);
+ mButton1.setText("Dialog WITHOUT EditText");//(R.string.open_dialog_scrollable);
+ mButton1.setOnClickListener(new View.OnClickListener()
+ {
+ public void onClick(View v)
+ {
+ showDialog(DIALOG_WITHOUT_EDITTEXT);
+ }
+ });
+
+ mButton2 = new Button(this);
+ mButton2.setText("Dialog WITH EditText");//(R.string.open_dialog_nonscrollable);
+ mButton2.setOnClickListener(new View.OnClickListener()
+ {
+ public void onClick(View v)
+ {
+ showDialog(DIALOG_WITH_EDITTEXT);
+ }
+ });
+
+ mEditText = new EditText(this);
+ mLayout.addView(mEditText);
+ mLayout.addView(mButton1);
+ mLayout.addView(mButton2);
+
+ setContentView(mLayout);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id)
+ {
+ switch (id)
+ {
+ case DIALOG_WITHOUT_EDITTEXT:
+ return createDialog(false);
+ case DIALOG_WITH_EDITTEXT:
+ return createDialog(true);
+ }
+
+ return super.onCreateDialog(id);
+ }
+
+ protected Dialog createDialog(boolean bEditText)
+ {
+ LinearLayout layout;
+ layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ if(bEditText)
+ {
+ EditText editText;
+ editText = new EditText(this);
+ layout.addView(editText);
+ }
+
+ Dialog d = new Dialog(this);
+ d.setTitle("The DIALOG!!!");
+ d.setCancelable(true);
+ d.setContentView(layout);
+ return d;
+ }
+
+ }
diff --git a/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
new file mode 100644
index 0000000..bd1e934
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/EditTextActivityDialog.java
@@ -0,0 +1,96 @@
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+
+public class EditTextActivityDialog extends Activity {
+
+ private static final int SCROLLABLE_DIALOG_ID = 0;
+ private static final int NONSCROLLABLE_DIALOG_ID = 1;
+
+ private LinearLayout mLayout;
+ private ScrollView mScrollView;
+ private LayoutInflater mInflater;
+ private Button mButton1;
+ private Button mButton2;
+
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mButton1 = new Button(this);
+ mButton1.setText(R.string.open_dialog_scrollable);
+ mButton1.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ showDialog(SCROLLABLE_DIALOG_ID);
+ }
+ });
+
+ mButton2 = new Button(this);
+ mButton2.setText(R.string.open_dialog_nonscrollable);
+ mButton2.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ showDialog(NONSCROLLABLE_DIALOG_ID);
+ }
+ });
+
+ mLayout.addView(mButton1);
+ mLayout.addView(mButton2);
+
+ setContentView(mLayout);
+ }
+
+ @Override
+ protected Dialog onCreateDialog(int id) {
+ switch (id) {
+ case SCROLLABLE_DIALOG_ID:
+ return createDialog(true);
+ case NONSCROLLABLE_DIALOG_ID:
+ return createDialog(false);
+ }
+
+ return super.onCreateDialog(id);
+ }
+
+ protected Dialog createDialog(boolean scrollable) {
+ View layout;
+ EditText editText;
+
+ if (scrollable) {
+ layout = new ScrollView(EditTextActivityDialog.this);
+ ((ScrollView) layout).setMinimumHeight(mLayout.getHeight());
+
+ ((ScrollView) layout).addView((
+ LinearLayout) View.inflate(EditTextActivityDialog.this,
+ R.layout.dialog_edit_text_no_scroll, null));
+ } else {
+ layout = View.inflate(EditTextActivityDialog.this,
+ R.layout.dialog_edit_text_no_scroll, null);
+ }
+
+ Dialog d = new Dialog(EditTextActivityDialog.this);
+ d.setTitle(getString(R.string.test_dialog));
+ d.setCancelable(true);
+ d.setContentView(layout);
+ return d;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
new file mode 100755
index 0000000..17f6bdc
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/InputTypeActivity.java
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.app.Activity;
+import android.widget.EditText;
+import android.widget.LinearLayout;
+import android.widget.Button;
+import android.widget.ScrollView;
+import android.widget.TextView;
+import android.os.Bundle;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+import android.view.ViewRoot;
+import android.view.inputmethod.EditorInfo;
+import android.content.Context;
+
+public class InputTypeActivity extends Activity {
+
+ private LinearLayout mLayout;
+ private ScrollView mScrollView;
+ private LayoutInflater mInflater;
+ private ViewGroup mParent;
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mScrollView = new ScrollView(this);
+
+ mLayout = new LinearLayout(this);
+ mLayout.setOrientation(LinearLayout.VERTICAL);
+ mLayout.setLayoutParams(new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.FILL_PARENT,
+ ViewGroup.LayoutParams.FILL_PARENT));
+
+ mInflater = getLayoutInflater();
+ mParent = mLayout;
+
+ /* Normal Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL,
+ R.string.normal_edit_text_label));
+
+ /* Normal Edit Text w/Cap Chars Flag*/
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS,
+ R.string.cap_chars_edit_text_label));
+
+ /* Normal Edit Text w/Cap Words Flag*/
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS,
+ R.string.cap_words_edit_text_label));
+
+ /* Normal Edit Text w/Cap Multiline Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE,
+ R.string.multiline_edit_text_label));
+
+ /* Normal Edit Text w/Cap Sentences Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES,
+ R.string.cap_sentences_edit_text_label));
+
+ /* Normal Edit Text w/Auto-complete Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_COMPLETE,
+ R.string.auto_complete_edit_text_label));
+
+ /* Normal Edit Text w/Auto-correct Flag */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_NORMAL|EditorInfo.TYPE_TEXT_FLAG_AUTO_CORRECT,
+ R.string.auto_correct_edit_text_label));
+
+ /* Uri Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_URI,
+ R.string.uri_edit_text_label));
+
+ /* Email Address Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
+ R.string.email_address_edit_text_label));
+
+ /* Email Subject Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_EMAIL_SUBJECT,
+ R.string.email_subject_edit_text_label));
+
+ /* Email Content Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_LONG_MESSAGE,
+ R.string.email_content_edit_text_label));
+
+ /* Person Name Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PERSON_NAME,
+ R.string.person_name_edit_text_label));
+
+ /* Postal Address Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_POSTAL_ADDRESS,
+ R.string.postal_address_edit_text_label));
+
+ /* Password Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_PASSWORD,
+ R.string.password_edit_text_label));
+
+ /* Web Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_TEXT|EditorInfo.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT,
+ R.string.web_edit_text_label));
+
+ /* Signed Number Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_SIGNED,
+ R.string.signed_number_edit_text_label));
+
+ /* Decimal Number Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_NUMBER|EditorInfo.TYPE_NUMBER_FLAG_DECIMAL,
+ R.string.decimal_number_edit_text_label));
+
+ /* Phone Number Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_PHONE,
+ R.string.phone_number_edit_text_label));
+
+ /* Normal Datetime Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_NORMAL,
+ R.string.normal_datetime_edit_text_label));
+
+ /* Date Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_DATE,
+ R.string.date_edit_text_label));
+
+ /* Time Edit Text */
+ mLayout.addView(buildEntryView(EditorInfo.TYPE_CLASS_DATETIME|EditorInfo.TYPE_DATETIME_VARIATION_TIME,
+ R.string.time_edit_text_label));
+
+ mScrollView.addView(mLayout);
+ setContentView(mScrollView);
+ }
+
+ private View buildEntryView(int inputType, int label) {
+
+
+ View view = mInflater.inflate(R.layout.sample_edit_text, mParent, false);
+
+ EditText editText = (EditText) view.findViewById(R.id.data);
+ editText.setInputType(inputType);
+
+ TextView textView = (TextView) view.findViewById(R.id.label);
+ textView.setText(label);
+
+ return view;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
new file mode 100644
index 0000000..54ab57a
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScan.java
@@ -0,0 +1,50 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Non-Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityNoScrollPanScan extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 9;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ mRootView = new LinearLayout(this);
+ ((LinearLayout) mRootView).setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ ((LinearLayout) mRootView).addView(editText);
+ }
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
new file mode 100644
index 0000000..b228d34
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScan.java
@@ -0,0 +1,52 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Full screen of EditTexts (Scrollable, Pan&Scan)
+ */
+public class ManyEditTextActivityScrollPanScan extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 12;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ mRootView = new ScrollView(this);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ layout.addView(editText);
+ }
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
new file mode 100644
index 0000000..777fbae
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/ManyEditTextActivityScrollResize.java
@@ -0,0 +1,45 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.View;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.widget.EditText;
+import android.widget.ScrollView;
+
+/*
+ * Full screen of EditTexts (Scrollable, Resize)
+ */
+public class ManyEditTextActivityScrollResize extends Activity
+{
+ public static final int NUM_EDIT_TEXTS = 12;
+
+ private View mRootView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+ mRootView = new ScrollView(this);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+
+ for (int i=0; i<NUM_EDIT_TEXTS; i++)
+ {
+ final EditText editText = new EditText(this);
+ editText.setText(String.valueOf(i));
+ editText.setId(i);
+ layout.addView(editText);
+ }
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ this.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+}
\ No newline at end of file
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
new file mode 100644
index 0000000..88a3447
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivityNotSelected.java
@@ -0,0 +1,56 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.os.Debug;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with non-EditText view selected initially
+ */
+public class OneEditTextActivityNotSelected extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ mRootView = new ScrollView(this);
+
+ EditText editText = new EditText(this);
+ Button button = new Button(this);
+ button.setText("The focus is here.");
+ button.setFocusableInTouchMode(true);
+ button.requestFocus();
+ mDefaultFocusedView = button;
+ layout.addView(button);
+ layout.addView(editText);
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
diff --git a/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
new file mode 100644
index 0000000..1b80263
--- /dev/null
+++ b/tests/ImfTest/src/com/android/imftest/samples/OneEditTextActivitySelected.java
@@ -0,0 +1,51 @@
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.LinearLayout;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.EditText;
+import android.widget.Button;
+import android.widget.TextView;
+import android.widget.ScrollView;
+
+import com.android.internal.R;
+
+/*
+ * Activity with EditText selected initially
+ */
+public class OneEditTextActivitySelected extends Activity
+{
+ private View mRootView;
+ private View mDefaultFocusedView;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ LinearLayout layout = new LinearLayout(this);
+ layout.setOrientation(LinearLayout.VERTICAL);
+ mRootView = new ScrollView(this);
+
+ EditText editText = new EditText(this);
+ editText.requestFocus();
+ mDefaultFocusedView = editText;
+ layout.addView(editText);
+
+ ((ScrollView) mRootView).addView(layout);
+ setContentView(mRootView);
+ }
+
+ public View getRootView() {
+ return mRootView;
+ }
+
+ public View getDefaultFocusedView() {
+ return mDefaultFocusedView;
+ }
+}
diff --git a/tests/ImfTest/tests/Android.mk b/tests/ImfTest/tests/Android.mk
new file mode 100755
index 0000000..0f1924c
--- /dev/null
+++ b/tests/ImfTest/tests/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := ImfTestTests
+
+LOCAL_INSTRUMENTATION_FOR := ImfTest
+
+include $(BUILD_PACKAGE)
diff --git a/tests/ImfTest/tests/AndroidManifest.xml b/tests/ImfTest/tests/AndroidManifest.xml
new file mode 100755
index 0000000..122d202
--- /dev/null
+++ b/tests/ImfTest/tests/AndroidManifest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.imftest.tests">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ This declares that this app uses the instrumentation test runner targeting
+ the package of com.android.imftest. To run the tests use the command:
+ "adb shell am instrument -w com.android.imftest.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.imftest"
+ android:label="imf tests"/>
+
+</manifest>
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
new file mode 100755
index 0000000..a1c5fd2
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollablePanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityNonScrollablePanScan> {
+
+ public final String TAG = "BigEditTextActivityNonScrollablePanScanTests";
+
+ public BigEditTextActivityNonScrollablePanScanTests() {
+ super(BigEditTextActivityNonScrollablePanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityNonScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
new file mode 100755
index 0000000..2e0b0eb
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityNonScrollableResizeTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityNonScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityNonScrollableResize> {
+
+ public final String TAG = "BigEditTextActivityNonScrollableResizeTests";
+
+ public BigEditTextActivityNonScrollableResizeTests() {
+ super(BigEditTextActivityNonScrollableResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityNonScrollableResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
new file mode 100755
index 0000000..d3eefb5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollablePanScanTests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollablePanScanTests extends ImfBaseTestCase<BigEditTextActivityScrollablePanScan> {
+
+ public final String TAG = "BigEditTextActivityScrollablePanScanTests";
+
+ public BigEditTextActivityScrollablePanScanTests() {
+ super(BigEditTextActivityScrollablePanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() { // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityScrollablePanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
new file mode 100755
index 0000000..5c40e6d
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BigEditTextActivityScrollableResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BigEditTextActivityScrollableResizeTests extends ImfBaseTestCase<BigEditTextActivityScrollableResize> {
+
+ public final String TAG = "BigEditTextActivityScrollableResizeTests";
+
+ public BigEditTextActivityScrollableResizeTests() {
+ super(BigEditTextActivityScrollableResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BigEditTextActivityScrollableResize) mTargetActivity).getRootView();
+ View servedView = ((BigEditTextActivityScrollableResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
new file mode 100755
index 0000000..9a93133
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityPanScanTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityPanScanTests extends ImfBaseTestCase<BottomEditTextActivityPanScan> {
+
+ public final String TAG = "BottomEditTextActivityPanScanTests";
+
+ public BottomEditTextActivityPanScanTests() {
+ super(BottomEditTextActivityPanScan.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentPanScan() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BottomEditTextActivityPanScan) mTargetActivity).getRootView();
+ View servedView = ((BottomEditTextActivityPanScan) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
new file mode 100755
index 0000000..9a69fd5
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/BottomEditTextActivityResizeTests.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+import com.android.imftest.R;
+
+
+public class BottomEditTextActivityResizeTests extends ImfBaseTestCase<BottomEditTextActivityResize> {
+
+ public final String TAG = "BottomEditTextActivityResizeTests";
+
+ public BottomEditTextActivityResizeTests() {
+ super(BottomEditTextActivityResize.class);
+ }
+
+ @LargeTest
+ public void testAppAdjustmentResize() {
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ View rootView = ((BottomEditTextActivityResize) mTargetActivity).getRootView();
+ View servedView = ((BottomEditTextActivityResize) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
new file mode 100755
index 0000000..ae900c3
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ButtonActivityTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.widget.Button;
+
+
+public class ButtonActivityTest extends ImfBaseTestCase<ButtonActivity> {
+
+ final public String TAG = "ButtonActivityTest";
+
+ public ButtonActivityTest() {
+ super(ButtonActivity.class);
+ }
+
+ @LargeTest
+ public void testButtonActivatesIme() {
+
+ final Button button = (Button) mTargetActivity.findViewById(ButtonActivity.BUTTON_ID);
+
+ // Push button
+ // Bring the target EditText into focus.
+ mTargetActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ button.requestFocus();
+ }
+ });
+
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ // Give it a couple seconds
+ pause(2000);
+
+ // We should have initialized imm.mServedView and imm.mCurrentTextBoxAttribute
+ assertTrue(mImm.isActive());
+ // imm.mServedInputConnection should be null since Button doesn't override onCreateInputConnection().
+ assertFalse(mImm.isAcceptingText());
+
+ destructiveCheckImeInitialState(mTargetActivity.getRootView(), button);
+
+ }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
new file mode 100755
index 0000000..61dc611
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ImfBaseTestCase.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.os.SystemClock;
+import android.test.InstrumentationTestCase;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.inputmethod.InputMethodManager;
+
+import com.android.imftest.R;
+
+public abstract class ImfBaseTestCase<T extends Activity> extends InstrumentationTestCase {
+
+ /*
+ * The amount of time we are willing to wait for the IME to appear after a user action
+ * before we give up and fail the test.
+ */
+ public final long WAIT_FOR_IME = 5000;
+
+ /*
+ * Unfortunately there is now way for us to know how tall the IME is,
+ * so we have to hard code a minimum and maximum value.
+ */
+ public final int IME_MIN_HEIGHT = 150;
+ public final int IME_MAX_HEIGHT = 300;
+
+ public final String TARGET_PACKAGE_NAME = "com.android.imftest";
+ protected InputMethodManager mImm;
+ protected T mTargetActivity;
+ protected boolean mExpectAutoPop;
+ private Class<T> mTargetActivityClass;
+
+ public ImfBaseTestCase(Class<T> activityClass) {
+ mTargetActivityClass = activityClass;
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+
+ mTargetActivity = launchActivity(TARGET_PACKAGE_NAME, mTargetActivityClass, null);
+ mExpectAutoPop = mTargetActivity.getResources().getBoolean(R.bool.def_expect_ime_autopop);
+ mImm = InputMethodManager.getInstance(mTargetActivity);
+ }
+
+ // Utility test methods
+ public void verifyEditTextAdjustment(final View editText, int rootViewHeight) {
+
+ int[] origLocation = new int[2];
+ int[] newLocation = new int[2];
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+
+ // Bring the target EditText into focus.
+ mTargetActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ editText.requestFocus();
+ }
+ });
+
+ // Get the original location of the EditText.
+ editText.getLocationOnScreen(origLocation);
+
+ // Tap the EditText to bring up the IME.
+ sendKeys(KeyEvent.KEYCODE_DPAD_CENTER);
+
+ // Wait until the EditText pops above the IME or until we hit the timeout.
+ editText.getLocationOnScreen(newLocation);
+ long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+ while (newLocation[1] > rootViewHeight - IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+ editText.getLocationOnScreen(newLocation);
+ pause(100);
+ }
+
+ assertTrue(newLocation[1] <= rootViewHeight - IME_MIN_HEIGHT);
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
+ }
+
+ public void destructiveCheckImeInitialState(View rootView, View servedView) {
+ if (mExpectAutoPop && (mTargetActivity.getWindow().getAttributes().
+ softInputMode&WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST)
+ == WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) {
+ assertTrue(destructiveCheckImeUp(rootView, servedView));
+ } else {
+ assertFalse(destructiveCheckImeUp(rootView, servedView));
+ }
+ }
+
+ public boolean destructiveCheckImeUp(View rootView, View servedView) {
+ int origHeight;
+ int newHeight;
+
+ origHeight = rootView.getHeight();
+
+ // Tell the keyboard to go away.
+ mImm.hideSoftInputFromWindow(servedView.getWindowToken(), 0);
+
+ // Give it five seconds to adjust
+ newHeight = rootView.getHeight();
+ long timeoutTime = SystemClock.uptimeMillis() + WAIT_FOR_IME;
+ while (Math.abs(newHeight - origHeight) < IME_MIN_HEIGHT && SystemClock.uptimeMillis() < timeoutTime) {
+ newHeight = rootView.getHeight();
+ }
+
+ return (Math.abs(origHeight - newHeight) >= IME_MIN_HEIGHT);
+ }
+
+ void pause(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ }
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
new file mode 100755
index 0000000..278efb1
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityBaseTestCase.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.app.Activity;
+import android.widget.EditText;
+
+
+public abstract class ManyEditTextActivityBaseTestCase<T extends Activity> extends ImfBaseTestCase<T> {
+
+ public ManyEditTextActivityBaseTestCase(Class<T> activityClass){
+ super(activityClass);
+ }
+
+ public abstract void testAllEditTextsAdjust();
+
+ public void verifyAllEditTextAdjustment(int numEditTexts, int rootViewHeight) {
+
+ for (int i = 0; i < numEditTexts; i++) {
+ final EditText lastEditText = (EditText) mTargetActivity.findViewById(i);
+ verifyEditTextAdjustment(lastEditText, rootViewHeight);
+ }
+
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
new file mode 100755
index 0000000..4f8d14e
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityNoScrollPanScanTests.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityNoScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityNoScrollPanScan> {
+
+ public final String TAG = "ManyEditTextActivityNoScrollPanScanTests";
+
+ public ManyEditTextActivityNoScrollPanScanTests() {
+ super(ManyEditTextActivityNoScrollPanScan.class);
+ }
+
+
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
new file mode 100755
index 0000000..7f98f7f
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollPanScanTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollPanScanTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollPanScan> {
+
+ public final String TAG = "ManyEditTextActivityScrollPanScanTests";
+
+
+ public ManyEditTextActivityScrollPanScanTests() {
+ super(ManyEditTextActivityScrollPanScan.class);
+ }
+
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
new file mode 100755
index 0000000..68dae87
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/ManyEditTextActivityScrollResizeTests.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+
+
+public class ManyEditTextActivityScrollResizeTests extends ManyEditTextActivityBaseTestCase<ManyEditTextActivityScrollResize> {
+
+ public final String TAG = "ManyEditTextActivityScrollResizeTests";
+
+
+ public ManyEditTextActivityScrollResizeTests() {
+ super(ManyEditTextActivityScrollResize.class);
+ }
+
+ @LargeTest
+ public void testAllEditTextsAdjust() {
+ verifyAllEditTextAdjustment(mTargetActivity.NUM_EDIT_TEXTS,
+ mTargetActivity.getRootView().getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
new file mode 100755
index 0000000..ed5b0c9
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivityNotSelectedTests.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.View;
+
+
+public class OneEditTextActivityNotSelectedTests extends ImfBaseTestCase<OneEditTextActivityNotSelected> {
+
+ public final String TAG = "OneEditTextActivityNotSelectedTests";
+
+ public OneEditTextActivityNotSelectedTests() {
+ super(OneEditTextActivityNotSelected.class);
+ }
+
+ @LargeTest
+ public void testSoftKeyboardNoAutoPop() {
+
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ assertFalse(mImm.isAcceptingText());
+
+ View rootView = ((OneEditTextActivityNotSelected) mTargetActivity).getRootView();
+ View servedView = ((OneEditTextActivityNotSelected) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
new file mode 100755
index 0000000..42fcd66
--- /dev/null
+++ b/tests/ImfTest/tests/src/com/android/imftest/samples/OneEditTextActivitySelectedTests.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.imftest.samples;
+
+import com.android.imftest.R;
+
+import android.test.suitebuilder.annotation.LargeTest;
+import android.view.KeyEvent;
+import android.view.View;
+
+
+public class OneEditTextActivitySelectedTests extends ImfBaseTestCase<OneEditTextActivitySelected> {
+
+ public final String TAG = "OneEditTextActivitySelectedTests";
+
+ public OneEditTextActivitySelectedTests() {
+ super(OneEditTextActivitySelected.class);
+ }
+
+ @LargeTest
+ public void testSoftKeyboardAutoPop() {
+
+ // Give the IME 2 seconds to appear.
+ pause(2000);
+
+ assertTrue(mImm.isAcceptingText());
+
+ View rootView = ((OneEditTextActivitySelected) mTargetActivity).getRootView();
+ View servedView = ((OneEditTextActivitySelected) mTargetActivity).getDefaultFocusedView();
+
+ assertNotNull(rootView);
+ assertNotNull(servedView);
+
+ destructiveCheckImeInitialState(rootView, servedView);
+
+ verifyEditTextAdjustment(servedView, rootView.getMeasuredHeight());
+ }
+
+}
diff --git a/tests/SmokeTest/Android.mk b/tests/SmokeTest/Android.mk
new file mode 100644
index 0000000..0adfd4c
--- /dev/null
+++ b/tests/SmokeTest/Android.mk
@@ -0,0 +1,16 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+# This builds "SmokeTestApp"
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+LOCAL_PACKAGE_NAME := SmokeTestApp
+
+include $(BUILD_PACKAGE)
+
+# This builds "SmokeTest"
+include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
diff --git a/tests/SmokeTest/AndroidManifest.xml b/tests/SmokeTest/AndroidManifest.xml
new file mode 100644
index 0000000..f141bdc
--- /dev/null
+++ b/tests/SmokeTest/AndroidManifest.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2008 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.smoketest">
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+ <activity android:name=".SmokeTestActivity"
+ android:label="Smoke Tests">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.TEST" />
+ </intent-filter>
+ </activity>
+
+ </application>
+
+</manifest>
diff --git a/tests/SmokeTest/README b/tests/SmokeTest/README
new file mode 100644
index 0000000..40218cf
--- /dev/null
+++ b/tests/SmokeTest/README
@@ -0,0 +1,8 @@
+The tests in this folder are a very controlled set of tests that will be run by
+the build system on every single build. They are intended to run very quickly.
+Please use caution when adding tests here.
+
+If you wish to run these tests, issue the command:
+
+adb shell am instrument \
+ -w com.android.smoketest/.tests.SmokeTestInstrumentationTestRunner
diff --git a/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java b/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java
new file mode 100644
index 0000000..6bc5fd2
--- /dev/null
+++ b/tests/SmokeTest/src/com/android/smoketest/SmokeTestActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import android.app.LauncherActivity;
+import android.content.Intent;
+
+/**
+ * Initial launcher for UI access to smoke tests. This does not actually launch the tests,
+ * it simply provides manual access to the various UI activities that are used by the tests.
+ *
+ * To run all of the tests in this suite:
+ * adb shell am instrument \
+ * -w com.android.smoketest/.tests.SmokeTestInstrumentationTestRunner
+ */
+public class SmokeTestActivity extends LauncherActivity {
+
+ @Override
+ protected Intent getTargetIntent() {
+ // TODO: partition into categories by label like the sample code app
+ Intent targetIntent = new Intent(Intent.ACTION_MAIN, null);
+ // TODO: Do we add a new top-level intent? Or just leave it hardcoded like this?
+ targetIntent.addCategory("android.intent.category.SMOKETEST_INSTRUMENTATION_TEST");
+ targetIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return targetIntent;
+ }
+}
diff --git a/tests/SmokeTest/tests/Android.mk b/tests/SmokeTest/tests/Android.mk
new file mode 100644
index 0000000..86bf23d
--- /dev/null
+++ b/tests/SmokeTest/tests/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+# We only want this apk build for tests.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+# Include all test java files.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+# Notice that we don't have to include the src files of SmokeTestApp because, by
+# running the tests using an instrumentation targeting SmokeTestApp, we
+# automatically get all of its classes loaded into our environment.
+
+LOCAL_PACKAGE_NAME := SmokeTest
+
+LOCAL_INSTRUMENTATION_FOR := SmokeTestApp
+
+include $(BUILD_PACKAGE)
+
diff --git a/tests/SmokeTest/tests/AndroidManifest.xml b/tests/SmokeTest/tests/AndroidManifest.xml
new file mode 100644
index 0000000..517eb1e
--- /dev/null
+++ b/tests/SmokeTest/tests/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.smoketest.tests">
+
+ <!-- We add an application tag here just so that we can indicate that
+ this package needs to link against the android.test library,
+ which is needed when building test cases. -->
+ <application>
+ <uses-library android:name="android.test.runner" />
+ </application>
+
+ <!--
+ This declares that this app uses the instrumentation test runner targeting
+ the package of com.android.smoketest. To run the tests use the command:
+ "adb shell am instrument -w com.android.smoketest.tests/android.test.InstrumentationTestRunner"
+ -->
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.smoketest"
+ android:label="System Smoke Tests"/>
+
+</manifest>
diff --git a/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
new file mode 100644
index 0000000..85b91f1
--- /dev/null
+++ b/tests/SmokeTest/tests/src/com/android/smoketest/ProcessErrorsTest.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.smoketest;
+
+import com.android.internal.os.RuntimeInit;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.server.data.CrashData;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * This smoke test is designed to quickly sniff for any error conditions
+ * encountered after initial startup.
+ */
+public class ProcessErrorsTest extends AndroidTestCase {
+
+ private final String TAG = "ProcessErrorsTest";
+
+ protected ActivityManager mActivityManager;
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mActivityManager = (ActivityManager)
+ getContext().getSystemService(Context.ACTIVITY_SERVICE);
+ }
+
+ public void testSetUpConditions() throws Exception {
+ assertNotNull(mActivityManager);
+ }
+
+ public void testNoProcessErrors() throws Exception {
+ List<ActivityManager.ProcessErrorStateInfo> errList;
+ errList = mActivityManager.getProcessesInErrorState();
+
+ // note: this contains information about each process that is currently in an error
+ // condition. if the list is empty (null) then "we're good".
+
+ // if the list is non-empty, then it's useful to report the contents of the list
+ // we'll put a copy in the log, and we'll report it back to the framework via the assert.
+ final String reportMsg = reportListContents(errList);
+ if (reportMsg != null) {
+ Log.w(TAG, reportMsg);
+ }
+
+ // report a non-empty list back to the test framework
+ assertNull(reportMsg, errList);
+ }
+
+ /**
+ * This helper function will dump the actual error reports.
+ *
+ * @param errList The error report containing one or more error records.
+ * @return Returns a string containing all of the errors.
+ */
+ private String reportListContents(List<ActivityManager.ProcessErrorStateInfo> errList) {
+ if (errList == null) return null;
+
+ StringBuilder builder = new StringBuilder();
+
+ Iterator<ActivityManager.ProcessErrorStateInfo> iter = errList.iterator();
+ while (iter.hasNext()) {
+ ActivityManager.ProcessErrorStateInfo entry = iter.next();
+
+ String condition;
+ switch (entry.condition) {
+ case ActivityManager.ProcessErrorStateInfo.CRASHED:
+ condition = "CRASHED";
+ break;
+ case ActivityManager.ProcessErrorStateInfo.NOT_RESPONDING:
+ condition = "ANR";
+ break;
+ default:
+ condition = "<unknown>";
+ break;
+ }
+
+ String stackTrace = null;
+ try {
+ if (entry.crashData != null) {
+ CrashData cd = RuntimeInit.unmarshallException(entry.crashData);
+ stackTrace = cd.toString();
+ }
+ } catch (RuntimeException e) { }
+ if (stackTrace == null) {
+ stackTrace = "<no stack trace>";
+ }
+
+ final String entryReport = "Process error " + condition + " " + entry.shortMsg +
+ " detected in " + entry.processName + " " + entry.tag +
+ ". \n" + stackTrace;
+
+ builder.append(entryReport).append(" ");
+ }
+ return builder.toString();
+ }
+
+}
diff --git a/tests/SslLoad/Android.mk b/tests/SslLoad/Android.mk
new file mode 100644
index 0000000..f75be8d
--- /dev/null
+++ b/tests/SslLoad/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := SslLoad
+
+include $(BUILD_PACKAGE)
diff --git a/tests/SslLoad/AndroidManifest.xml b/tests/SslLoad/AndroidManifest.xml
new file mode 100644
index 0000000..497b1c7
--- /dev/null
+++ b/tests/SslLoad/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.sslload">
+ <uses-permission android:name="android.permission.INTERNET" />
+ <application>
+ <activity android:name="SslLoad" android:label="SSL Load">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/SslLoad/src/com/android/sslload/SslLoad.java b/tests/SslLoad/src/com/android/sslload/SslLoad.java
new file mode 100644
index 0000000..9a08024
--- /dev/null
+++ b/tests/SslLoad/src/com/android/sslload/SslLoad.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.sslload;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Calendar;
+import java.util.Map;
+
+import android.app.Activity;
+import android.content.res.Resources;
+import android.media.MediaPlayer;
+import android.os.Handler;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.TextView;
+import android.net.http.AndroidHttpClient;
+import android.util.Log;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.HttpResponse;
+
+public class SslLoad extends Activity implements OnClickListener, Runnable {
+
+ private static final String TAG = SslLoad.class.getSimpleName();
+
+ private Button button;
+ private boolean running = false;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Thread requestThread = new Thread(this);
+ requestThread.setDaemon(true);
+ requestThread.start();
+
+ button = new Button(this);
+ button.setText("GO");
+ button.setOnClickListener(this);
+
+ setContentView(button);
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+
+ synchronized (this) {
+ running = false;
+ }
+ }
+
+ public void onClick(View v) {
+ synchronized (this) {
+ running = !running;
+ button.setText(running ? "STOP" : "GO");
+ if (running) {
+ this.notifyAll();
+ }
+ }
+ }
+
+ public void run() {
+ boolean error = false;
+ while (true) {
+ synchronized (this) {
+ while (!running) {
+ try {
+ this.wait();
+ } catch (InterruptedException e) { /* ignored */ }
+ }
+ }
+
+ AndroidHttpClient client = AndroidHttpClient.newInstance(
+ "Mozilla/5.001 (windows; U; NT4.0; en-us) Gecko/25250101");
+ try {
+ // Cert. is for "www.google.com", not "google.com".
+ String url = error ? "https://google.com/"
+ : "https://www.google.com";
+ client.execute(new HttpGet(url),
+ new ResponseHandler<Void>() {
+ public Void handleResponse(HttpResponse response) {
+ /* ignore */
+ return null;
+ }
+ });
+ Log.i(TAG, "Request succeeded.");
+ } catch (IOException e) {
+ Log.w(TAG, "Request failed.", e);
+ }
+
+ client.close();
+
+ try {
+ Thread.sleep(1000);
+ } catch (InterruptedException e) { /* ignored */ }
+
+ error = !error;
+ }
+ }
+}
diff --git a/tests/StatusBar/Android.mk b/tests/StatusBar/Android.mk
new file mode 100644
index 0000000..44f5099
--- /dev/null
+++ b/tests/StatusBar/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := test
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := StatusBarTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/StatusBar/AndroidManifest.xml b/tests/StatusBar/AndroidManifest.xml
new file mode 100644
index 0000000..9bba79c
--- /dev/null
+++ b/tests/StatusBar/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.statusbartest">
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.STATUS_BAR" />
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application>
+ <activity android:name="StatusBarTest" android:label="_StatusBar">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="NotificationTestList" android:label="_Notifications">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="ToastTest" android:label="_Toasts">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="PowerTest" android:label="_Power">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
diff --git a/tests/StatusBar/res/drawable/app_gmail.png b/tests/StatusBar/res/drawable/app_gmail.png
new file mode 100644
index 0000000..beaaacf
--- /dev/null
+++ b/tests/StatusBar/res/drawable/app_gmail.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/app_phone.png b/tests/StatusBar/res/drawable/app_phone.png
new file mode 100644
index 0000000..2748c1c
--- /dev/null
+++ b/tests/StatusBar/res/drawable/app_phone.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_chat.png b/tests/StatusBar/res/drawable/ic_statusbar_chat.png
new file mode 100644
index 0000000..e08cddb
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_chat.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_email.png b/tests/StatusBar/res/drawable/ic_statusbar_email.png
new file mode 100644
index 0000000..19c9005
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_email.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png b/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png
new file mode 100644
index 0000000..ced62d7
--- /dev/null
+++ b/tests/StatusBar/res/drawable/ic_statusbar_missedcall.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon1.png b/tests/StatusBar/res/drawable/icon1.png
new file mode 100644
index 0000000..abfb6fa
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon1.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon2.png b/tests/StatusBar/res/drawable/icon2.png
new file mode 100644
index 0000000..564b38b
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon2.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon3.png b/tests/StatusBar/res/drawable/icon3.png
new file mode 100644
index 0000000..e765d8f
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon3.png
Binary files differ
diff --git a/tests/StatusBar/res/drawable/icon4.png b/tests/StatusBar/res/drawable/icon4.png
new file mode 100644
index 0000000..5f33885
--- /dev/null
+++ b/tests/StatusBar/res/drawable/icon4.png
Binary files differ
diff --git a/tests/StatusBar/res/layout/chrono_notification.xml b/tests/StatusBar/res/layout/chrono_notification.xml
new file mode 100644
index 0000000..913a860
--- /dev/null
+++ b/tests/StatusBar/res/layout/chrono_notification.xml
@@ -0,0 +1,41 @@
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="80sp"
+ android:orientation="horizontal"
+ >
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="fill_parent"
+ android:layout_weight="0"
+ android:orientation="vertical"
+ >
+
+ <ImageView android:id="@+id/icon"
+ android:layout_width="wrap_content"
+ android:layout_height="45dp"
+ android:layout_gravity="center"
+ android:scaleType="fitCenter"
+ android:src="@android:drawable/sym_def_app_icon"
+ />
+
+ <Chronometer android:id="@+id/time"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:singleLine="true"
+ android:textColor="#ffffffff" />
+
+ </LinearLayout>
+
+ <TextView android:id="@+id/appName"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:layout_weight="1"
+ android:paddingTop="4dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+
+</LinearLayout>
+
diff --git a/tests/StatusBar/res/raw/ringer.mp3 b/tests/StatusBar/res/raw/ringer.mp3
new file mode 100644
index 0000000..aa052e7
--- /dev/null
+++ b/tests/StatusBar/res/raw/ringer.mp3
Binary files differ
diff --git a/tests/StatusBar/res/values/strings.xml b/tests/StatusBar/res/values/strings.xml
new file mode 100644
index 0000000..0c2cf0d
--- /dev/null
+++ b/tests/StatusBar/res/values/strings.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="mainLabel">Hello <u>th<ignore>e</ignore>re</u>, <i>you</i> <b>Activity</b>!</string>
+ <string name="back">Back</string>
+ <string name="clear">Clear</string>
+</resources>
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
new file mode 100644
index 0000000..e1a0e7d
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -0,0 +1,517 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.ListActivity;
+import android.app.PendingIntent;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.TextView;
+import android.os.PowerManager;
+
+public class NotificationTestList extends TestActivity
+{
+ private final static String TAG = "NotificationTestList";
+
+ NotificationManager mNM;
+ Vibrator mVibrator = new Vibrator();
+ Handler mHandler = new Handler();
+
+ long mChronometerBase = 0;
+
+ @Override
+ protected String tag() {
+ return TAG;
+ }
+
+ @Override
+ protected Test[] tests() {
+ mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
+
+ return mTests;
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("Crash") {
+ public void run()
+ {
+ PowerManager.WakeLock wl
+ = ((PowerManager)NotificationTestList.this.getSystemService("power"))
+ .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "crasher");
+ wl.acquire();
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ throw new RuntimeException("Die!");
+ }
+ }, 10000);
+
+ }
+ },
+
+ new Test("No view") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon1, "No view",
+ System.currentTimeMillis());
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("No intent") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon1, "No intent",
+ System.currentTimeMillis());
+ n.setLatestEventInfo(NotificationTestList.this, "No intent",
+ "No intent", null);
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Layout") {
+ public void run()
+ {
+
+ mNM.notify(1, new Notification(NotificationTestList.this,
+ R.drawable.ic_statusbar_missedcall,
+ null, System.currentTimeMillis()-(1000*60*60*24),
+ "(453) 123-2328",
+ "", null));
+
+ mNM.notify(2, new Notification(NotificationTestList.this,
+ R.drawable.ic_statusbar_email,
+ null, System.currentTimeMillis(),
+ "Mark Willem, Me (2)",
+ "Re: Didn't you get the memo?", null));
+
+ mNM.notify(3, new Notification(NotificationTestList.this,
+ R.drawable.ic_statusbar_chat,
+ null, System.currentTimeMillis()+(1000*60*60*24),
+ "Sophia Winterlanden",
+ "Lorem ipsum dolor sit amet.", null));
+ }
+ },
+
+ new StateStress("Stress - Ongoing / Latest", 100, 100, new Runnable[] {
+ new Runnable() {
+ public void run() {
+ Log.d(TAG, "Stress - Ongoing/Latest 0");
+ Notification n = new Notification(NotificationTestList.this,
+ R.drawable.icon3,
+ null, System.currentTimeMillis(), "Stress - Ongoing",
+ "Notify me!!!", null);
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+ mNM.notify(1, n);
+ }
+ },
+ new Runnable() {
+ public void run() {
+ Log.d(TAG, "Stress - Ongoing/Latest 1");
+ Notification n = new Notification(NotificationTestList.this,
+ R.drawable.icon4,
+ null, System.currentTimeMillis(), "Stress - Latest",
+ "Notify me!!!", null);
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+ mNM.notify(1, n);
+ }
+ }
+ }),
+
+ new Test("Long") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.defaults |= Notification.DEFAULT_SOUND ;
+ n.vibrate = new long[] {
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+ 300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 };
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Default All") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.defaults |= Notification.DEFAULT_ALL;
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Default All, once") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.defaults |= Notification.DEFAULT_ALL;
+ n.flags |= Notification.FLAG_ONLY_ALERT_ONCE ;
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Content Sound") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.sound = Uri.parse(
+ "content://media/internal/audio/media/7");
+
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Resource Sound") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.sound = Uri.parse(
+ "android.resource://com.android.notificationtest/raw/ringer");
+ Log.d(TAG, "n.sound=" + n.sound);
+
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Sound and Cancel") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.sound = Uri.parse(
+ "content://media/internal/audio/media/7");
+
+ mNM.notify(1, n);
+ SystemClock.sleep(200);
+ mNM.cancel(1);
+ }
+ },
+
+ new Test("Vibrate") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.vibrate = new long[] { 0, 700, 500, 1000 };
+
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Vibrate and cancel") {
+ public void run()
+ {
+ Notification n = new Notification();
+ n.vibrate = new long[] { 0, 700, 500, 1000 };
+
+ mNM.notify(1, n);
+ SystemClock.sleep(500);
+ mNM.cancel(1);
+ }
+ },
+
+ new Test("Vibrate pattern") {
+ public void run()
+ {
+ mVibrator.vibrate(new long[] { 250, 1000, 500, 2000 }, -1);
+ }
+ },
+
+ new Test("Vibrate pattern repeating") {
+ public void run()
+ {
+ mVibrator.vibrate(new long[] { 250, 1000, 500 }, 1);
+ }
+ },
+
+ new Test("Vibrate 3s") {
+ public void run()
+ {
+ mVibrator.vibrate(3000);
+ }
+ },
+
+ new Test("Vibrate 100s") {
+ public void run()
+ {
+ mVibrator.vibrate(100000);
+ }
+ },
+
+ new Test("Vibrate off") {
+ public void run()
+ {
+ mVibrator.cancel();
+ }
+ },
+
+ new Test("Cancel #1") {
+ public void run() {
+ mNM.cancel(1);
+ }
+ },
+
+ new Test("Cancel #1 in 3 sec") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ Log.d(TAG, "Cancelling now...");
+ mNM.cancel(1);
+ }
+ }, 3000);
+ }
+ },
+
+ new Test("Cancel #2") {
+ public void run() {
+ mNM.cancel(2);
+ }
+ },
+
+ new Test("Persistent #1") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon1, "tick tick tick",
+ System.currentTimeMillis());
+ n.setLatestEventInfo(NotificationTestList.this, "Persistent #1",
+ "This is a notification!!!", makeIntent());
+ mNM.notify(1, n);
+ }
+ },
+
+ new Test("Persistent #1 in 3 sec") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon1,
+ " "
+ + "tick tock tick tock\n\nSometimes notifications can "
+ + "be really long and wrap to more than one line.\n"
+ + "Sometimes."
+ + "Ohandwhathappensifwehaveonereallylongstringarewesure"
+ + "thatwesegmentitcorrectly?\n",
+ System.currentTimeMillis());
+ n.setLatestEventInfo(NotificationTestList.this,
+ "Still Persistent #1",
+ "This is still a notification!!!",
+ makeIntent());
+ mNM.notify(1, n);
+ }
+ }, 3000);
+ }
+ },
+
+ new Test("Persistent #2") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon2, "tock tock tock",
+ System.currentTimeMillis());
+ n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
+ "Notify me!!!", makeIntent());
+ mNM.notify(2, n);
+ }
+ },
+
+ new Test("Persistent #2 Vibrate") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon2, "tock tock tock",
+ System.currentTimeMillis());
+ n.setLatestEventInfo(NotificationTestList.this, "Persistent #2",
+ "Notify me!!!", makeIntent());
+ n.defaults = Notification.DEFAULT_VIBRATE;
+ mNM.notify(2, n);
+ }
+ },
+
+ new Test("Chronometer Start") {
+ public void run() {
+ Notification n = new Notification(R.drawable.icon2, "me me me me",
+ System.currentTimeMillis());
+ n.contentView = new RemoteViews(getPackageName(), R.layout.chrono_notification);
+ mChronometerBase = SystemClock.elapsedRealtime();
+ n.contentView.setChronometer(R.id.time, mChronometerBase, "Yay! (%s)", true);
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+ n.contentIntent = makeIntent();
+ mNM.notify(2, n);
+ }
+ },
+
+ new Test("Chronometer Stop") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ Log.d(TAG, "Chronometer Stop");
+ Notification n = new Notification();
+ n.icon = R.drawable.icon1;
+ n.contentView = new RemoteViews(getPackageName(),
+ R.layout.chrono_notification);
+ n.contentView.setChronometer(R.id.time, mChronometerBase, null, false);
+ n.contentIntent = makeIntent();
+ mNM.notify(2, n);
+ }
+ }, 3000);
+ }
+ },
+
+ new Test("Sequential Persistent") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(2, notificationWithNumbers(2));
+ }
+ },
+
+ new Test("Replace Persistent") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(1, notificationWithNumbers(1));
+ }
+ },
+
+ new Test("Run and Cancel (n=1)") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(1));
+ mNM.cancel(1);
+ }
+ },
+
+ new Test("Run an Cancel (n=2)") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(2, notificationWithNumbers(2));
+ mNM.cancel(2);
+ }
+ },
+
+ // Repeatedly notify and cancel -- triggers bug #670627
+ new Test("Bug 670627") {
+ public void run() {
+ for (int i = 0; i < 10; i++) {
+ Log.d(TAG, "Add two notifications");
+ mNM.notify(1, notificationWithNumbers(1));
+ mNM.notify(2, notificationWithNumbers(2));
+ Log.d(TAG, "Cancel two notifications");
+ mNM.cancel(1);
+ mNM.cancel(2);
+ }
+ }
+ },
+
+ new Test("Ten Notifications") {
+ public void run() {
+ for (int i = 0; i < 2; i++) {
+ Notification n = new Notification(NotificationTestList.this, R.drawable.icon2,
+ null, System.currentTimeMillis(), "Persistent #" + i,
+ "Notify me!!!" + i, null);
+ n.flags |= Notification.FLAG_ONGOING_EVENT;
+ n.number = i;
+ mNM.notify((i+1)*10, n);
+ }
+ for (int i = 2; i < 10; i++) {
+ Notification n = new Notification(NotificationTestList.this, R.drawable.icon2,
+ null, System.currentTimeMillis(), "Persistent #" + i,
+ "Notify me!!!" + i, null);
+ n.number = i;
+ mNM.notify((i+1)*10, n);
+ }
+ }
+ },
+
+ new Test("Cancel eight notifications") {
+ public void run() {
+ for (int i = 1; i < 9; i++) {
+ mNM.cancel((i+1)*10);
+ }
+ }
+ },
+
+ new Test("Persistent with numbers 1") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(1));
+ }
+ },
+
+ new Test("Persistent with numbers 222") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(22));
+ }
+ },
+
+ new Test("Persistent with numbers 333") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(333));
+ }
+ },
+
+ new Test("Persistent with numbers 4444") {
+ public void run() {
+ mNM.notify(1, notificationWithNumbers(4444));
+ }
+ },
+
+ };
+
+ private Notification notificationWithNumbers(int num) {
+ Notification n = new Notification(this, R.drawable.icon2, null, System.currentTimeMillis(),
+ "Persistent #2", "Notify me!!!", null);
+ n.number = num;
+ return n;
+ }
+
+ private PendingIntent makeIntent() {
+ Intent intent = new Intent(Intent.ACTION_MAIN);
+ intent.setComponent(new android.content.ComponentName(
+ "com.android.contacts",
+ "com.android.contacts.ContactsActivity"));
+ return PendingIntent.getActivity(this, 0, intent, 0);
+ }
+
+ class StateStress extends Test {
+ StateStress(String name, int pause, int iterations, Runnable[] tasks) {
+ super(name);
+ mPause = pause;
+ mTasks = tasks;
+ mIteration = iterations;
+ }
+ Runnable[] mTasks;
+ int mNext;
+ int mIteration;
+ long mPause;
+ Runnable mRunnable = new Runnable() {
+ public void run() {
+ mTasks[mNext].run();
+ mNext++;
+ if (mNext >= mTasks.length) {
+ mNext = 0;
+ mIteration--;
+ if (mIteration <= 0) {
+ return;
+ }
+ }
+ mHandler.postDelayed(mRunnable, mPause);
+ }
+ };
+ public void run() {
+ mNext = 0;
+ mHandler.postDelayed(mRunnable, mPause);
+ }
+ }
+}
+
diff --git a/tests/StatusBar/src/com/android/statusbartest/PowerTest.java b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
new file mode 100644
index 0000000..f236a4b
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/PowerTest.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.os.RemoteException;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.LocalPowerManager;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public class PowerTest extends TestActivity
+{
+ private final static String TAG = "PowerTest";
+ IPowerManager mPowerManager;
+ int mPokeState = 0;
+ IBinder mPokeToken = new Binder();
+ Handler mHandler = new Handler();
+
+ @Override
+ protected String tag() {
+ return TAG;
+ }
+
+ @Override
+ protected Test[] tests() {
+ mPowerManager = IPowerManager.Stub.asInterface(ServiceManager.getService("power"));
+
+ return mTests;
+ }
+ private Test[] mTests = new Test[] {
+ new Test("Touch events don't poke") {
+ public void run() {
+ mPokeState |= LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ new Test("Touch events poke") {
+ public void run() {
+ mPokeState &= ~LocalPowerManager.POKE_LOCK_IGNORE_CHEEK_EVENTS;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ new Test("Short timeout") {
+ public void run() {
+ mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+ mPokeState |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ new Test("Medium timeout") {
+ public void run() {
+ mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+ mPokeState |= LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ new Test("Normal timeout") {
+ public void run() {
+ mPokeState &= ~LocalPowerManager.POKE_LOCK_TIMEOUT_MASK;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ new Test("Illegal timeout") {
+ public void run() {
+ mPokeState |= LocalPowerManager.POKE_LOCK_SHORT_TIMEOUT
+ | LocalPowerManager.POKE_LOCK_MEDIUM_TIMEOUT;
+ try {
+ mPowerManager.setPokeLock(mPokeState, mPokeToken, TAG);
+ } catch (RemoteException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ },
+ };
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
new file mode 100644
index 0000000..275e5cb6
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/StatusBarTest.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.StatusBarManager;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public class StatusBarTest extends TestActivity
+{
+ private final static String TAG = "StatusBarTest";
+ StatusBarManager mStatusBarManager;
+ NotificationManager mNotificationManager;
+ Handler mHandler = new Handler();
+
+ @Override
+ protected String tag() {
+ return TAG;
+ }
+
+ @Override
+ protected Test[] tests() {
+ mStatusBarManager = (StatusBarManager)getSystemService(STATUS_BAR_SERVICE);
+ mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+
+ return mTests;
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("Disable Alerts") {
+ public void run() {
+ mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ALERTS);
+ }
+ },
+ new Test("Disable Expand in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND);
+ }
+ }, 3000);
+ }
+ },
+ new Test("Disable Notifications in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.disable(StatusBarManager.DISABLE_NOTIFICATION_ICONS);
+ }
+ }, 3000);
+ }
+ },
+ new Test("Disable Both in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.disable(StatusBarManager.DISABLE_EXPAND
+ | StatusBarManager.DISABLE_NOTIFICATION_ICONS);
+ }
+ }, 3000);
+ }
+ },
+ new Test("Disable None in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.disable(0);
+ }
+ }, 3000);
+ }
+ },
+ new Test("Notify in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mNotificationManager.notify(1,
+ new Notification(StatusBarTest.this,
+ R.drawable.ic_statusbar_missedcall,
+ "tick tick tick",
+ System.currentTimeMillis()-(1000*60*60*24),
+ "(453) 123-2328",
+ "", null
+ ));
+ }
+ }, 3000);
+ }
+ },
+ new Test("Cancel Notification in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mNotificationManager.cancel(1);
+ }
+ }, 3000);
+ }
+ },
+ new Test("Expand in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.expand();
+ }
+ }, 3000);
+ }
+ },
+ new Test("Expand in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.expand();
+ }
+ }, 3000);
+ }
+ },
+ new Test("Collapse in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.collapse();
+ }
+ }, 3000);
+ }
+ },
+ new Test("Toggle in 3 sec.") {
+ public void run() {
+ mHandler.postDelayed(new Runnable() {
+ public void run() {
+ mStatusBarManager.toggle();
+ }
+ }, 3000);
+ }
+ },
+ };
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/TestActivity.java b/tests/StatusBar/src/com/android/statusbartest/TestActivity.java
new file mode 100644
index 0000000..6a8c62e
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/TestActivity.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.ListActivity;
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.os.Vibrator;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.os.PowerManager;
+
+public abstract class TestActivity extends ListActivity
+{
+ Test[] mTests;
+
+ protected abstract String tag();
+ protected abstract Test[] tests();
+
+ abstract class Test {
+ String name;
+ Test(String n) {
+ name = n;
+ }
+ abstract void run();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ mTests = tests();
+
+ String[] labels = new String[mTests.length];
+ for (int i=0; i<mTests.length; i++) {
+ labels[i] = mTests[i].name;
+ }
+
+ setListAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, labels));
+ }
+
+ @Override
+ public void onListItemClick(ListView l, View v, int position, long id)
+ {
+ Test t = mTests[position];
+ Log.d(tag(), "Test: " + t.name);
+ t.run();
+ }
+
+}
diff --git a/tests/StatusBar/src/com/android/statusbartest/ToastTest.java b/tests/StatusBar/src/com/android/statusbartest/ToastTest.java
new file mode 100644
index 0000000..018c9f2
--- /dev/null
+++ b/tests/StatusBar/src/com/android/statusbartest/ToastTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.statusbartest;
+
+import android.app.ListActivity;
+import android.app.PendingIntent;
+import android.widget.ArrayAdapter;
+import android.view.View;
+import android.widget.ListView;
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.net.Uri;
+import android.os.SystemClock;
+import android.view.Gravity;
+import android.widget.RemoteViews;
+import android.widget.Toast;
+import android.widget.TextView;
+import android.os.PowerManager;
+
+public class ToastTest extends TestActivity
+{
+ private final static String TAG = "ToastTest";
+
+ Handler mHandler = new Handler();
+ Toast mToast1;
+ Toast mToast2;
+
+ @Override
+ protected String tag() {
+ return TAG;
+ }
+
+ @Override
+ protected Test[] tests() {
+ return mTests;
+ }
+
+ private Test[] mTests = new Test[] {
+ new Test("Make Toast #1") {
+ public void run()
+ {
+ mToast1 = Toast.makeText(ToastTest.this, "hi 1", Toast.LENGTH_SHORT);
+ }
+ },
+
+ new Test("Show Toast #1") {
+ public void run()
+ {
+ mToast1.show();
+ }
+ },
+
+ new Test("Update Toast #1") {
+ public void run()
+ {
+ TextView view = new TextView(ToastTest.this);
+ view.setText("replaced!");
+ mToast1.setView(view);
+ mToast1.show();
+ }
+ },
+
+ new Test("Make Toast #2") {
+ public void run()
+ {
+ mToast2 = Toast.makeText(ToastTest.this, "hi 2", Toast.LENGTH_SHORT);
+ }
+ },
+
+ new Test("Show Toast #2") {
+ public void run()
+ {
+ mToast2.show();
+ }
+ },
+
+ new Test("Gravity Toast LEFT") {
+ public void run()
+ {
+ Toast toast = Toast.makeText(ToastTest.this, "LEFT", Toast.LENGTH_SHORT);
+ toast.setGravity(Gravity.LEFT, 0, 0);
+ toast.show();
+ }
+ },
+
+ new Test("Gravity Toast FILL_HORIZONTAL") {
+ public void run()
+ {
+ Toast toast = Toast.makeText(ToastTest.this, "FILL_HORIZONTAL",
+ Toast.LENGTH_SHORT);
+ toast.setGravity(Gravity.FILL_HORIZONTAL, 0, 0);
+ toast.show();
+ }
+ },
+
+ };
+}
+
diff --git a/tests/framework-tests/Android.mk b/tests/framework-tests/Android.mk
new file mode 100644
index 0000000..5053e7d
--- /dev/null
+++ b/tests/framework-tests/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/tests/framework-tests/README b/tests/framework-tests/README
new file mode 100644
index 0000000..7b46b25
--- /dev/null
+++ b/tests/framework-tests/README
@@ -0,0 +1,5 @@
+This package contains tests which need to access package-private members in the framework code.
+To do this, the tests must be loaded in the same class loader as the classes which they are
+testing. This package is loaded in the boot classpath.
+
+Run these tests via AndroidTests -> FrameworkTests.
diff --git a/tests/framework-tests/src/Android.mk b/tests/framework-tests/src/Android.mk
new file mode 100644
index 0000000..54e33a4
--- /dev/null
+++ b/tests/framework-tests/src/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE := framework-tests
+
+LOCAL_JAVA_LIBRARIES := android.policy_phone android.test.runner
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/tests/framework-tests/src/android/test/FrameworkTests.java b/tests/framework-tests/src/android/test/FrameworkTests.java
new file mode 100644
index 0000000..b5f6292
--- /dev/null
+++ b/tests/framework-tests/src/android/test/FrameworkTests.java
@@ -0,0 +1,28 @@
+package android.test;
+
+import com.android.internal.os.LoggingPrintStreamTest;
+import android.util.EventLogFunctionalTest;
+import android.util.EventLogTest;
+import junit.framework.TestSuite;
+import com.android.internal.http.multipart.MultipartTest;
+import com.android.internal.policy.impl.LockPatternKeyguardViewTest;
+
+/**
+ * Tests that are loaded in the boot classpath along with the Android framework
+ * classes. This enables you to access package-private members in the framework
+ * classes; doing so is not possible when the test classes are loaded in an
+ * application classloader.
+ */
+public class FrameworkTests {
+ public static TestSuite suite() {
+ TestSuite suite = new TestSuite(FrameworkTests.class.getName());
+
+ suite.addTestSuite(MultipartTest.class);
+ suite.addTestSuite(EventLogTest.class);
+ suite.addTestSuite(EventLogFunctionalTest.class);
+ suite.addTestSuite(LoggingPrintStreamTest.class);
+ suite.addTestSuite(LockPatternKeyguardViewTest.class);
+
+ return suite;
+ }
+}
diff --git a/tests/framework-tests/src/android/text/PackedIntVectorTest.java b/tests/framework-tests/src/android/text/PackedIntVectorTest.java
new file mode 100644
index 0000000..78cdee9
--- /dev/null
+++ b/tests/framework-tests/src/android/text/PackedIntVectorTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.text;
+
+import android.text.PackedIntVector;
+import junit.framework.TestCase;
+
+/**
+ * PackedIntVectorTest tests the features of android.util.PackedIntVector.
+ */
+public class PackedIntVectorTest extends TestCase {
+
+ public void testBasic() throws Exception {
+ for (int width = 0; width < 10; width++) {
+ PackedIntVector p = new PackedIntVector(width);
+ int[] ins = new int[width];
+
+ for (int height = width * 2; height < width * 4; height++) {
+ assertEquals(p.width(), width);
+
+ // Test adding rows.
+
+ for (int i = 0; i < height; i++) {
+ int at;
+
+ if (i % 2 == 0) {
+ at = i;
+ } else {
+ at = p.size() - i;
+ }
+
+ for (int j = 0; j < width; j++) {
+ ins[j] = i + j;
+ }
+
+ if (i == height / 2) {
+ p.insertAt(at, null);
+ } else {
+ p.insertAt(at, ins);
+ }
+
+ assertEquals(p.size(), i + 1);
+
+ for (int j = 0; j < width; j++) {
+ if (i == height / 2) {
+ assertEquals(0, p.getValue(at, j));
+ } else {
+ assertEquals(p.getValue(at, j), i + j);
+ }
+ }
+ }
+
+ // Test setting values.
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ p.setValue(i, j, i * j);
+
+ assertEquals(p.getValue(i, j), i * j);
+ }
+ }
+
+ // Test offsetting values.
+
+ for (int j = 0; j < width; j++) {
+ p.adjustValuesBelow(j * 2, j, j + 27);
+ }
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int expect = i * j;
+
+ if (i >= j * 2) {
+ expect += j + 27;
+ }
+
+ assertEquals(p.getValue(i, j), expect);
+ }
+ }
+
+ for (int j = 0; j < width; j++) {
+ p.adjustValuesBelow(j, j, j * j + 14);
+ }
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ int expect = i * j;
+
+ if (i >= j * 2) {
+ expect += j + 27;
+ }
+ if (i >= j) {
+ expect += j * j + 14;
+ }
+
+ assertEquals(p.getValue(i, j), expect);
+ }
+ }
+
+ // Test undoing offsets.
+
+ for (int j = 0; j < width; j++) {
+ p.adjustValuesBelow(j * 2, j, -(j + 27));
+ p.adjustValuesBelow(j, j, -(j * j + 14));
+ }
+
+ for (int i = 0; i < height; i++) {
+ for (int j = 0; j < width; j++) {
+ assertEquals(p.getValue(i, j), i * j);
+ }
+ }
+
+ // Test deleting rows.
+
+ while (p.size() > 0) {
+ int osize = p.size();
+ int del = osize / 3;
+
+ if (del == 0) {
+ del = 1;
+ }
+
+ int at = (osize - del) / 2;
+ p.deleteAt(at, del);
+
+ assertEquals(p.size(), osize - del);
+
+ for (int i = 0; i < at; i++) {
+ for (int j = 0; j < width; j++) {
+ assertEquals(p.getValue(i, j), i * j);
+ }
+ }
+
+ for (int i = at; i < p.size(); i++) {
+ for (int j = 0; j < width; j++) {
+ assertEquals(p.getValue(i, j), (i + height - p.size()) * j);
+ }
+ }
+ }
+
+ assertEquals(0, p.size());
+ }
+ }
+ }
+}
diff --git a/tests/framework-tests/src/android/util/EventLogFunctionalTest.java b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
new file mode 100644
index 0000000..8263083
--- /dev/null
+++ b/tests/framework-tests/src/android/util/EventLogFunctionalTest.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import android.os.Process;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.TestCase;
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+
+/**
+ * Functional tests of EventLog.
+ */
+
+public class EventLogFunctionalTest extends TestCase {
+ private static final String TAG = "EventLogFunctionalTest";
+
+ private static final int TAG_SIZE = 4;
+ private static final int TYPE_FIELD_SIZE = 1;
+ private static final int STARTING_POS_OF_PAYLOAD = TAG_SIZE + TYPE_FIELD_SIZE;
+
+ private static final int TEST_TAG = 42;
+ private static final int TEST_TAG2 = 314;
+
+ //todo: For now all we do is test the returned length. More to come.
+ public void testLogOfPosInt() throws Exception {
+ final int numBytes = EventLog.writeEvent(TEST_TAG, 0x01020304);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 4, numBytes);
+ }
+
+ //todo: For now all we do is test the returned length. More to come.
+ public void testLogOfPosLong() throws Exception {
+ final int numBytes = EventLog.writeEvent(TEST_TAG2, 0x0102030405060708L);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 8, numBytes);
+ }
+
+ //todo: For now all we do is test the returned length. More to come.
+ public void testLogOfString() throws Exception {
+ final String valueStr = "foo bar baz";
+ final int numBytes = EventLog.writeEvent(TEST_TAG, valueStr);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 4 + valueStr.length() + 1, numBytes);
+ }
+
+ public void testLogOfListWithOneInt() throws Exception {
+ final EventLog.List list = new EventLog.List(1234);
+ final int numBytes = EventLog.writeEvent(TEST_TAG, list);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1, numBytes);
+ }
+
+ public void testLogOfListWithMultipleInts() throws Exception {
+ final EventLog.List list = new EventLog.List(1234, 2345, 3456);
+ final int numBytes = EventLog.writeEvent(TEST_TAG, list);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
+ }
+
+ public void testLogOfListWithEmbeddedList() throws Exception {
+ final EventLog.List list = new EventLog.List(
+ new EventLog.List(1234, 2345, 3456));
+ final int numBytes = EventLog.writeEvent(TEST_TAG, list);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 2 + 1 + 1 + 4 + 1 + 4 + 1 + 4 + 1, numBytes);
+ }
+
+ public void testEventLargerThanInitialBufferCapacity() throws Exception {
+ final Integer[] array = new Integer[127];
+ for (int i = 0; i < array.length; i++) {
+ array[i] = i;
+ }
+ final EventLog.List list = new EventLog.List((Object[]) array);
+ final int numBytes = EventLog.writeEvent(TEST_TAG, list);
+ Assert.assertEquals(STARTING_POS_OF_PAYLOAD + 1 + (5 * array.length) + 1, numBytes);
+ }
+
+ // This test is obsolete. See http://b/issue?id=1262082
+ public void disableTestReadSimpleEvent() throws Exception {
+ long when = System.currentTimeMillis();
+ EventLog.writeEvent(2718, 12345);
+ Log.i(TAG, "Wrote simple event at T=" + when);
+
+ ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
+ EventLog.readEvents(new int[] { 2718 }, list);
+
+ boolean found = false;
+ for (EventLog.Event event : list) {
+ assertEquals(event.getTag(), 2718);
+ long eventTime = event.getTimeNanos() / 1000000;
+ Log.i(TAG, " Found event T=" + eventTime);
+ if (eventTime > when - 100 && eventTime < when + 1000) {
+ assertEquals(event.getProcessId(), Process.myPid());
+ assertEquals(event.getThreadId(), Process.myTid());
+ assertEquals(event.getData(), 12345);
+
+ assertFalse(found);
+ found = true;
+ }
+ }
+
+ assertTrue(found);
+ }
+
+ // This test is obsolete. See http://b/issue?id=1262082
+ public void disableTestReadCompoundEntry() throws Exception {
+ long when = System.currentTimeMillis();
+ EventLog.writeEvent(2719,
+ new EventLog.List(1l, new EventLog.List("2", "three", "4"), 5));
+ Log.i(TAG, "Wrote compound event at T=" + when);
+
+ ArrayList<EventLog.Event> list = new ArrayList<EventLog.Event>();
+ EventLog.readEvents(new int[] { 2719 }, list);
+
+ boolean found = false;
+ for (EventLog.Event event : list) {
+ long eventTime = event.getTimeNanos() / 1000000;
+ Log.i(TAG, " Found event T=" + eventTime);
+ if (eventTime > when - 100 && eventTime < when + 1000) {
+ EventLog.List data = (EventLog.List) event.getData();
+ assertEquals(data.getNumItems(), 3);
+
+ EventLog.List nested = (EventLog.List) data.getItem(1);
+ assertEquals(nested.getNumItems(), 3);
+
+ assertEquals(data.getItem(0), 1l);
+ assertEquals(nested.getItem(0), "2");
+ assertEquals(nested.getItem(1), "three");
+ assertEquals(nested.getItem(2), "4");
+ assertEquals(data.getItem(2), 5);
+
+ assertFalse(found);
+ found = true;
+ }
+ }
+
+ assertTrue(found);
+ }
+
+ public void testEventLogTagsFile() throws Exception {
+ EventLogTags tags = new EventLogTags();
+ assertEquals(tags.get("answer").mTag, 42);
+ assertEquals(tags.get("pi").mTag, 314);
+ assertEquals(tags.get("e").mTag, 2718);
+ assertEquals(tags.get(42).mName, "answer");
+ assertEquals(tags.get(314).mName, "pi");
+ assertEquals(tags.get(2718).mName, "e");
+ }
+}
diff --git a/tests/framework-tests/src/android/util/EventLogTest.java b/tests/framework-tests/src/android/util/EventLogTest.java
new file mode 100644
index 0000000..4a5d888
--- /dev/null
+++ b/tests/framework-tests/src/android/util/EventLogTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.util;
+
+import com.google.android.collect.Lists;
+
+import junit.framework.Assert;
+import junit.framework.TestCase;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * tests for {@link EventLog}
+ */
+
+public class EventLogTest extends TestCase {
+ private static final int TEST_TAG = 42;
+
+ public void testIllegalListTypesThrowException() throws Exception {
+ try {
+ EventLog.writeEvent(TEST_TAG, new EventLog.List(new Object()));
+ fail("Can't create List with any old Object");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ try {
+ EventLog.writeEvent(TEST_TAG, new EventLog.List((byte) 1));
+ fail("Can't create List with any old byte");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ void assertIntInByteArrayEquals(int expected, byte[] buf, int pos) {
+ ByteBuffer computedBuf = ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder());
+ int computed = computedBuf.getInt(pos);
+ Assert.assertEquals(expected, computed);
+ }
+
+ void assertLongInByteArrayEquals(long expected, byte[] buf, int pos) {
+ ByteBuffer computedBuf = ByteBuffer.wrap(buf).order(ByteOrder.nativeOrder());
+ long computed = computedBuf.getLong(pos);
+ Assert.assertEquals(expected, computed);
+ }
+
+ void assertStringInByteArrayEquals(String expected, byte[] buf, int pos) {
+ byte[] expectedBytes = expected.getBytes();
+ Assert.assertTrue(expectedBytes.length <= buf.length - pos);
+ for (byte expectedByte : expectedBytes) {
+ Assert.assertEquals(expectedByte, buf[pos++]);
+ }
+ }
+}
diff --git a/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java b/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java
new file mode 100644
index 0000000..8b48ed0
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/http/multipart/MultipartTest.java
@@ -0,0 +1,102 @@
+package com.android.internal.http.multipart;
+
+import junit.framework.TestCase;
+import org.apache.http.Header;
+import org.apache.http.util.EncodingUtils;
+
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+
+public class MultipartTest extends TestCase {
+
+ public void testParts() throws Exception {
+ StringBuffer filebuffer = new StringBuffer();
+ String filepartStr = "this is file part";
+ filebuffer.append(filepartStr);
+ File upload = File.createTempFile("Multipart", "test");
+
+ FileWriter outFile = new FileWriter(upload);
+ BufferedWriter out = new BufferedWriter(outFile);
+ try {
+ out.write(filebuffer.toString());
+ out.flush();
+ } finally {
+ out.close();
+ }
+
+ Part[] parts = new Part[3];
+ parts[0] = new StringPart("stringpart", "PART1!!");
+ parts[1] = new FilePart(upload.getName(), upload);
+ parts[2] = new StringPart("stringpart", "PART2!!");
+
+ MultipartEntity me = new MultipartEntity(parts);
+ ByteArrayOutputStream os = new ByteArrayOutputStream();
+ me.writeTo(os);
+ Header h = me.getContentType();
+ String boundry = EncodingUtils.getAsciiString(me.getMultipartBoundary());
+ StringBuffer contentType = new StringBuffer("multipart/form-data");
+ contentType.append("; boundary=");
+ contentType.append(boundry);
+ assertEquals("Multipart content type error", contentType.toString(), h.getValue());
+ final String CRLF = "\r\n";
+ StringBuffer output = new StringBuffer();
+
+ output.append("--");
+ output.append(boundry);
+ output.append(CRLF);
+
+ output.append("Content-Disposition: form-data; name=\"stringpart\"");
+ output.append(CRLF);
+ output.append("Content-Type: text/plain; charset=US-ASCII");
+ output.append(CRLF);
+ output.append("Content-Transfer-Encoding: 8bit");
+ output.append(CRLF);
+ output.append(CRLF);
+ output.append("PART1!!");
+ output.append(CRLF);
+
+ output.append("--");
+ output.append(boundry);
+ output.append(CRLF);
+
+ output.append("Content-Disposition: form-data; name=\"");
+ output.append(upload.getName());
+ output.append("\"; filename=\"");
+ output.append(upload.getName());
+ output.append("\"");
+
+ output.append(CRLF);
+ output.append("Content-Type: application/octet-stream; charset=ISO-8859-1");
+ output.append(CRLF);
+ output.append("Content-Transfer-Encoding: binary");
+ output.append(CRLF);
+ output.append(CRLF);
+ output.append(filepartStr);
+ output.append(CRLF);
+
+ output.append("--");
+ output.append(boundry);
+ output.append(CRLF);
+
+ output.append("Content-Disposition: form-data; name=\"stringpart\"");
+ output.append(CRLF);
+ output.append("Content-Type: text/plain; charset=US-ASCII");
+ output.append(CRLF);
+ output.append("Content-Transfer-Encoding: 8bit");
+ output.append(CRLF);
+ output.append(CRLF);
+ output.append("PART2!!");
+ output.append(CRLF);
+
+ output.append("--");
+ output.append(boundry);
+ output.append("--");
+ output.append(CRLF);
+ // System.out.print(output.toString());
+ assertEquals("Multipart content error", output.toString(), os.toString());
+
+ // System.out.print(os.toString());
+ }
+}
diff --git a/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
new file mode 100644
index 0000000..8e3a034
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/os/LoggingPrintStreamTest.java
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.os;
+
+import junit.framework.TestCase;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.io.StringWriter;
+import java.io.PrintWriter;
+
+public class LoggingPrintStreamTest extends TestCase {
+
+ TestPrintStream out = new TestPrintStream();
+
+ public void testPrintException() {
+ @SuppressWarnings("ThrowableInstanceNeverThrown")
+ Throwable t = new Throwable("Ignore me.");
+
+ StringWriter sout = new StringWriter();
+ t.printStackTrace(new PrintWriter(sout));
+
+ t.printStackTrace(out);
+ // t.printStackTrace();
+
+ String[] lines = sout.toString().split("\\n");
+ assertEquals(Arrays.asList(lines), out.lines);
+ }
+
+ public void testPrintObject() {
+ Object o = new Object();
+ out.print(4);
+ out.print(o);
+ out.print(2);
+ out.flush();
+ assertEquals(Arrays.asList("4" + o + "2"), out.lines);
+ }
+
+ public void testPrintlnObject() {
+ Object o = new Object();
+ out.print(4);
+ out.println(o);
+ out.print(2);
+ out.flush();
+ assertEquals(Arrays.asList("4" + o, "2"), out.lines);
+ }
+
+ public void testPrintf() {
+ out.printf("Name: %s\nEmployer: %s", "Bob", "Google");
+ assertEquals(Arrays.asList("Name: Bob"), out.lines);
+ out.flush();
+ assertEquals(Arrays.asList("Name: Bob", "Employer: Google"), out.lines);
+ }
+
+ public void testPrintInt() {
+ out.print(4);
+ out.print(2);
+ assertTrue(out.lines.isEmpty());
+ out.flush();
+ assertEquals(Collections.singletonList("42"), out.lines);
+ }
+
+ public void testPrintlnInt() {
+ out.println(4);
+ out.println(2);
+ assertEquals(Arrays.asList("4", "2"), out.lines);
+ }
+
+ public void testPrintCharArray() {
+ out.print("Foo\nBar\nTee".toCharArray());
+ assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
+ out.flush();
+ assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+ }
+
+ public void testPrintString() {
+ out.print("Foo\nBar\nTee");
+ assertEquals(Arrays.asList("Foo", "Bar"), out.lines);
+ out.flush();
+ assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+ }
+
+ public void testPrintlnCharArray() {
+ out.println("Foo\nBar\nTee".toCharArray());
+ assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+ }
+
+ public void testPrintlnString() {
+ out.println("Foo\nBar\nTee");
+ assertEquals(Arrays.asList("Foo", "Bar", "Tee"), out.lines);
+ }
+
+ public void testPrintlnStringWithBufferedData() {
+ out.print(5);
+ out.println("Foo\nBar\nTee");
+ assertEquals(Arrays.asList("5Foo", "Bar", "Tee"), out.lines);
+ }
+
+ public void testAppend() {
+ out.append("Foo\n")
+ .append('4')
+ .append('\n')
+ .append("Bar", 1, 2)
+ .append('\n');
+ assertEquals(Arrays.asList("Foo", "4", "a"), out.lines);
+ }
+
+ static class TestPrintStream extends LoggingPrintStream {
+
+ final List<String> lines = new ArrayList<String>();
+
+ protected void log(String line) {
+ lines.add(line);
+ }
+ }
+
+}
diff --git a/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
new file mode 100644
index 0000000..0368651
--- /dev/null
+++ b/tests/framework-tests/src/com/android/internal/policy/impl/LockPatternKeyguardViewTest.java
@@ -0,0 +1,372 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.policy.impl;
+
+import android.content.Context;
+
+import com.android.internal.telephony.SimCard;
+import android.test.AndroidTestCase;
+import android.view.View;
+import android.view.KeyEvent;
+import com.android.internal.widget.LockPatternUtils;
+import com.google.android.collect.Lists;
+
+import java.util.List;
+
+/**
+ * Tests for {@link com.android.internal.policy.impl.LockPatternKeyguardView},
+ * which handles the management of screens while the keyguard is showing.
+ */
+public class LockPatternKeyguardViewTest extends AndroidTestCase {
+ private MockUpdateMonitor mUpdateMonitor;
+ private LockPatternUtils mLockPatternUtils;
+ private TestableLockPatternKeyguardView mLPKV;
+ private MockKeyguardCallback mKeyguardViewCallback;
+
+ private static class MockUpdateMonitor extends KeyguardUpdateMonitor {
+
+ public SimCard.State simState = SimCard.State.READY;
+ public boolean inPortrait = false;
+ public boolean keyboardOpen = false;
+
+ private MockUpdateMonitor(Context context) {
+ super(context);
+ }
+
+ @Override
+ public SimCard.State getSimState() {
+ return simState;
+ }
+
+ @Override
+ public boolean isInPortrait() {
+ return inPortrait;
+ }
+
+ @Override
+ public boolean isKeyboardOpen() {
+ return keyboardOpen;
+ }
+
+ @Override
+ boolean queryInPortrait() {
+ return inPortrait;
+ }
+
+ @Override
+ boolean queryKeyboardOpen() {
+ return keyboardOpen;
+ }
+ }
+
+ private static class MockLockPatternUtils extends LockPatternUtils {
+ boolean isLockPatternEnabled = true;
+ public boolean isPermanentlyLocked = false;
+
+ public MockLockPatternUtils() {
+ super(null);
+ }
+
+ @Override
+ public boolean isLockPatternEnabled() {
+ return isLockPatternEnabled;
+ }
+
+ @Override
+ public void setLockPatternEnabled(boolean lockPatternEnabled) {
+ isLockPatternEnabled = lockPatternEnabled;
+ }
+
+ @Override
+ public boolean isPermanentlyLocked() {
+ return isPermanentlyLocked;
+ }
+
+ public void setPermanentlyLocked(boolean permanentlyLocked) {
+ isPermanentlyLocked = permanentlyLocked;
+ }
+ }
+
+ private static class MockKeyguardScreen extends View implements KeyguardScreen {
+
+ private int mOnPauseCount = 0;
+ private int mOnResumeCount = 0;
+ private int mCleanupCount = 0;
+
+ private MockKeyguardScreen(Context context) {
+ super(context);
+ setFocusable(true);
+ }
+
+ /** {@inheritDoc} */
+ public boolean needsInput() {
+ return false;
+ }
+
+ /** {@inheritDoc} */
+ public void onPause() {
+ mOnPauseCount++;
+ }
+
+ /** {@inheritDoc} */
+ public void onResume() {
+ mOnResumeCount++;
+ }
+
+ /** {@inheritDoc} */
+ public void cleanUp() {
+ mCleanupCount++;
+ }
+
+ public int getOnPauseCount() {
+ return mOnPauseCount;
+ }
+
+ public int getOnResumeCount() {
+ return mOnResumeCount;
+ }
+
+ public int getCleanupCount() {
+ return mCleanupCount;
+ }
+ }
+
+ /**
+ * Allows us to inject the lock and unlock views to simulate their behavior
+ * and detect their creation.
+ */
+ private static class TestableLockPatternKeyguardView extends LockPatternKeyguardView {
+ private List<MockKeyguardScreen> mInjectedLockScreens;
+ private List<MockKeyguardScreen> mInjectedUnlockScreens;
+
+
+
+ private TestableLockPatternKeyguardView(Context context, KeyguardUpdateMonitor updateMonitor,
+ LockPatternUtils lockPatternUtils, KeyguardWindowController controller) {
+ super(context, updateMonitor, lockPatternUtils, controller);
+ }
+
+ @Override
+ View createLockScreen() {
+ final MockKeyguardScreen newView = new MockKeyguardScreen(getContext());
+ if (mInjectedLockScreens == null) mInjectedLockScreens = Lists.newArrayList();
+ mInjectedLockScreens.add(newView);
+ return newView;
+ }
+
+ @Override
+ View createUnlockScreenFor(UnlockMode unlockMode) {
+ final MockKeyguardScreen newView = new MockKeyguardScreen(getContext());
+ if (mInjectedUnlockScreens == null) mInjectedUnlockScreens = Lists.newArrayList();
+ mInjectedUnlockScreens.add(newView);
+ return newView;
+ }
+
+ public List<MockKeyguardScreen> getInjectedLockScreens() {
+ return mInjectedLockScreens;
+ }
+
+ public List<MockKeyguardScreen> getInjectedUnlockScreens() {
+ return mInjectedUnlockScreens;
+ }
+ }
+
+ private static class MockKeyguardCallback implements KeyguardViewCallback {
+
+ private int mPokeWakelockCount = 0;
+ private int mKeyguardDoneCount = 0;
+
+ public void pokeWakelock() {
+ mPokeWakelockCount++;
+ }
+
+ public void pokeWakelock(int millis) {
+ mPokeWakelockCount++;
+ }
+
+ public void keyguardDone(boolean authenticated) {
+ mKeyguardDoneCount++;
+ }
+
+ public void keyguardDoneDrawing() {
+
+ }
+
+ public int getPokeWakelockCount() {
+ return mPokeWakelockCount;
+ }
+
+ public int getKeyguardDoneCount() {
+ return mKeyguardDoneCount;
+ }
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mUpdateMonitor = new MockUpdateMonitor(getContext());
+ mLockPatternUtils = new MockLockPatternUtils();
+
+ mLPKV = new TestableLockPatternKeyguardView(getContext(), mUpdateMonitor,
+ mLockPatternUtils, new KeyguardWindowController() {
+ public void setNeedsInput(boolean needsInput) {
+ }
+ });
+ mKeyguardViewCallback = new MockKeyguardCallback();
+ mLPKV.setCallback(mKeyguardViewCallback);
+ }
+
+ public void testStateAfterCreatedWhileScreenOff() {
+
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+ MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+ assertEquals(0, lockScreen.getOnPauseCount());
+ assertEquals(0, lockScreen.getOnResumeCount());
+ assertEquals(0, lockScreen.getCleanupCount());
+
+ assertEquals(0, unlockScreen.getOnPauseCount());
+ assertEquals(0, unlockScreen.getOnResumeCount());
+ assertEquals(0, unlockScreen.getCleanupCount());
+
+ assertEquals(0, mKeyguardViewCallback.getPokeWakelockCount());
+ assertEquals(0, mKeyguardViewCallback.getKeyguardDoneCount());
+ }
+
+ public void testWokenByNonMenuKey() {
+ mLPKV.wakeWhenReadyTq(0);
+
+ // should have poked the wakelock to turn on the screen
+ assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount());
+
+ // shouldn't be any additional views created
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+ MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+ // lock screen should be only visible one
+ assertEquals(View.VISIBLE, lockScreen.getVisibility());
+ assertEquals(View.GONE, unlockScreen.getVisibility());
+
+ // on resume not called until screen turns on
+ assertEquals(0, lockScreen.getOnPauseCount());
+ assertEquals(0, lockScreen.getOnResumeCount());
+ assertEquals(0, lockScreen.getCleanupCount());
+
+ assertEquals(0, unlockScreen.getOnPauseCount());
+ assertEquals(0, unlockScreen.getOnResumeCount());
+ assertEquals(0, unlockScreen.getCleanupCount());
+
+ // simulate screen turning on
+ mLPKV.onScreenTurnedOn();
+
+ assertEquals(0, lockScreen.getOnPauseCount());
+ assertEquals(1, lockScreen.getOnResumeCount());
+ assertEquals(0, lockScreen.getCleanupCount());
+
+ assertEquals(0, unlockScreen.getOnPauseCount());
+ assertEquals(0, unlockScreen.getOnResumeCount());
+ assertEquals(0, unlockScreen.getCleanupCount());
+ }
+
+ public void testWokenByMenuKeyWhenPatternSet() {
+ assertEquals(true, mLockPatternUtils.isLockPatternEnabled());
+
+ mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+ // should have poked the wakelock to turn on the screen
+ assertEquals(1, mKeyguardViewCallback.getPokeWakelockCount());
+
+ // shouldn't be any additional views created
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+ MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+ // unlock screen should be only visible one
+ assertEquals(View.GONE, lockScreen.getVisibility());
+ assertEquals(View.VISIBLE, unlockScreen.getVisibility());
+ }
+
+ public void testScreenRequestsRecreation() {
+ mLPKV.wakeWhenReadyTq(0);
+ mLPKV.onScreenTurnedOn();
+
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+
+ assertEquals(0, lockScreen.getOnPauseCount());
+ assertEquals(1, lockScreen.getOnResumeCount());
+
+ // simulate screen asking to be recreated
+ mLPKV.mKeyguardScreenCallback.recreateMe();
+
+ // should have been recreated
+ assertEquals(2, mLPKV.getInjectedLockScreens().size());
+ assertEquals(2, mLPKV.getInjectedUnlockScreens().size());
+
+ // both old screens should have been cleaned up
+ assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getCleanupCount());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().get(0).getCleanupCount());
+
+ // old lock screen should have been paused
+ assertEquals(1, mLPKV.getInjectedLockScreens().get(0).getOnPauseCount());
+ assertEquals(0, mLPKV.getInjectedUnlockScreens().get(0).getOnPauseCount());
+
+ // new lock screen should have been resumed
+ assertEquals(1, mLPKV.getInjectedLockScreens().get(1).getOnResumeCount());
+ assertEquals(0, mLPKV.getInjectedUnlockScreens().get(1).getOnResumeCount());
+ }
+
+ public void testMenuDoesntGoToUnlockScreenOnWakeWhenPukLocked() {
+ // PUK locked
+ mUpdateMonitor.simState = SimCard.State.PUK_REQUIRED;
+
+ // wake by menu
+ mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+ MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+ // lock screen should be only visible one
+ assertEquals(View.VISIBLE, lockScreen.getVisibility());
+ assertEquals(View.GONE, unlockScreen.getVisibility());
+ }
+
+ public void testMenuGoesToLockScreenWhenDeviceNotSecure() {
+ mLockPatternUtils.setLockPatternEnabled(false);
+
+ // wake by menu
+ mLPKV.wakeWhenReadyTq(KeyEvent.KEYCODE_MENU);
+
+ assertEquals(1, mLPKV.getInjectedLockScreens().size());
+ assertEquals(1, mLPKV.getInjectedUnlockScreens().size());
+ MockKeyguardScreen lockScreen = mLPKV.getInjectedLockScreens().get(0);
+ MockKeyguardScreen unlockScreen = mLPKV.getInjectedUnlockScreens().get(0);
+
+ // lock screen should be only visible one
+ assertEquals(View.VISIBLE, lockScreen.getVisibility());
+ assertEquals(View.GONE, unlockScreen.getVisibility());
+ }
+}
diff --git a/tests/gadgets/GadgetHostTest/Android.mk b/tests/gadgets/GadgetHostTest/Android.mk
new file mode 100644
index 0000000..5e04b81
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GadgetHostTest
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/gadgets/GadgetHostTest/AndroidManifest.xml b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
new file mode 100644
index 0000000..52e314f
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.gadgethost">
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application>
+ <activity android:name="GadgetHostActivity" android:label="_GadgetHost">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <activity android:name="TestGadgetConfigure" android:label="Configure TestGadgetProvider">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
+ <!-- BEGIN_INCLUDE(GadgetProvider) -->
+ <receiver android:name="TestGadgetProvider"
+ android:label="@string/oh_hai"
+ android:icon="@drawable/oh_hai_icon"
+ >
+ <intent-filter>
+ <action android:name="android.gadget.action.GADGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.gadget.provider"
+ android:resource="@xml/gadget_info"
+ />
+ </receiver>
+ <!-- END_INCLUDE(GadgetProvider) -->
+
+ </application>
+</manifest>
diff --git a/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png b/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png
new file mode 100644
index 0000000..30ff267
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/drawable/oh_hai_icon.png
Binary files differ
diff --git a/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml b/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml
new file mode 100644
index 0000000..743f6c6
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/gadget_host.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent" >
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/gadget_view_title"
+ />
+
+ <ScrollView
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ >
+
+ <com.android.tests.gadgethost.GadgetContainerView
+ android:id="@+id/gadget_container"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ />
+
+ </ScrollView>
+
+ <Button
+ android:id="@+id/add_gadget"
+ android:text="@string/add_gadget"
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ />
+
+</LinearLayout>
+
diff --git a/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml b/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml
new file mode 100644
index 0000000..4d483c7
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/test_gadget.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/oh_hai_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/oh_hai"
+/>
+
diff --git a/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml b/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml
new file mode 100644
index 0000000..0d9b983
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/layout/test_gadget_configure.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ >
+
+ <TextView
+ android:id="@+id/oh_hai_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/oh_hai"
+ />
+
+ <EditText
+ android:id="@+id/edit_text"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ />
+
+ <Button
+ android:id="@+id/save_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/save"
+ />
+
+
+</LinearLayout>
diff --git a/tests/gadgets/GadgetHostTest/res/values/strings.xml b/tests/gadgets/GadgetHostTest/res/values/strings.xml
new file mode 100644
index 0000000..ad9916a
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/values/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="gadget_view_title">Gadget Test</string>
+ <string name="add_gadget">Add Gadget</string>
+ <string name="oh_hai">Oh hai.</string>
+ <string name="delete_gadget">Delete</string>
+ <string name="save">Save</string>
+</resources>
+
diff --git a/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
new file mode 100644
index 0000000..e0c4222
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/res/xml/gadget_info.xml
@@ -0,0 +1,10 @@
+<!-- BEGIN_INCLUDE(GadgetProviderInfo) -->
+<gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="40dp"
+ android:minHeight="30dp"
+ android:updatePeriodMillis="86400000"
+ android:initialLayout="@layout/test_gadget"
+ android:configure="com.android.tests.gadgethost.TestGadgetConfigure"
+ >
+</gadget-provider>
+<!-- END_INCLUDE(GadgetProviderInfo) -->
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java
new file mode 100644
index 0000000..3814836
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetContainerView.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gadgethost;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+public class GadgetContainerView extends LinearLayout
+{
+ public GadgetContainerView(Context context) {
+ super(context);
+ }
+
+ public GadgetContainerView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+}
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
new file mode 100644
index 0000000..0bd8926
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/GadgetHostActivity.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gadgethost;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.gadget.GadgetHost;
+import android.gadget.GadgetHostView;
+import android.gadget.GadgetProviderInfo;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.ContextMenu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.LinearLayout;
+
+public class GadgetHostActivity extends Activity
+{
+ static final String TAG = "GadgetHostActivity";
+
+ static final int DISCOVER_GADGET_REQUEST = 1;
+ static final int CONFIGURE_GADGET_REQUEST = 2;
+ static final int HOST_ID = 1234;
+
+ static final String PENDING_GADGET_ID = "pending_gadget";
+
+ GadgetManager mGadgetManager;
+ GadgetContainerView mGadgetContainer;
+
+ public GadgetHostActivity() {
+ mGadgetManager = GadgetManager.getInstance(this);
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.gadget_host);
+
+ findViewById(R.id.add_gadget).setOnClickListener(mOnClickListener);
+ mGadgetContainer = (GadgetContainerView)findViewById(R.id.gadget_container);
+
+ if (false) {
+ if (false) {
+ mHost.deleteHost();
+ } else {
+ GadgetHost.deleteAllHosts();
+ }
+ }
+ }
+
+ View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ discoverGadget(DISCOVER_GADGET_REQUEST);
+ }
+ };
+
+ void discoverGadget(int requestCode) {
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_PICK);
+ intent.putExtra(GadgetManager.EXTRA_GADGET_ID, mHost.allocateGadgetId());
+ startActivityForResult(intent, requestCode);
+ }
+
+ void configureGadget(int requestCode, int gadgetId, ComponentName configure) {
+ Intent intent = new Intent(GadgetManager.ACTION_GADGET_CONFIGURE);
+ intent.setComponent(configure);
+ intent.putExtra(GadgetManager.EXTRA_GADGET_ID, gadgetId);
+ SharedPreferences.Editor prefs = getPreferences(0).edit();
+ prefs.putInt(PENDING_GADGET_ID, gadgetId);
+ prefs.commit();
+ startActivityForResult(intent, requestCode);
+ }
+
+ void handleGadgetPickResult(int resultCode, Intent intent) {
+ // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_ID)
+ Bundle extras = intent.getExtras();
+ int gadgetId = extras.getInt(GadgetManager.EXTRA_GADGET_ID);
+ // END_INCLUDE(getExtra_EXTRA_GADGET_ID)
+ if (resultCode == RESULT_OK) {
+ GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+
+ if (gadget.configure != null) {
+ // configure the gadget if we should
+ configureGadget(CONFIGURE_GADGET_REQUEST, gadgetId, gadget.configure);
+ } else {
+ // just add it as is
+ addGadgetView(gadgetId, gadget);
+ }
+ } else {
+ mHost.deleteGadgetId(gadgetId);
+ }
+ }
+
+ void handleGadgetConfigureResult(int resultCode, Intent data) {
+ int gadgetId = getPreferences(0).getInt(PENDING_GADGET_ID, -1);
+ Log.d(TAG, "resultCode=" + resultCode + " gadgetId=" + gadgetId);
+ if (gadgetId < 0) {
+ Log.w(TAG, "was no preference for PENDING_GADGET_ID");
+ return;
+ }
+ if (resultCode == RESULT_OK) {
+ GadgetProviderInfo gadget = mGadgetManager.getGadgetInfo(gadgetId);
+ addGadgetView(gadgetId, gadget);
+ } else {
+ mHost.deleteGadgetId(gadgetId);
+ }
+ }
+
+ void addGadgetView(int gadgetId, GadgetProviderInfo gadget) {
+ // Inflate the gadget's RemoteViews
+ GadgetHostView view = mHost.createView(this, gadgetId, gadget);
+
+ // Add it to the list
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ LinearLayout.LayoutParams.FILL_PARENT,
+ LinearLayout.LayoutParams.WRAP_CONTENT);
+ mGadgetContainer.addView(view, layoutParams);
+
+ registerForContextMenu(view);
+ }
+
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ switch (requestCode) {
+ case DISCOVER_GADGET_REQUEST:
+ handleGadgetPickResult(resultCode, data);
+ break;
+ case CONFIGURE_GADGET_REQUEST:
+ handleGadgetConfigureResult(resultCode, data);
+ }
+ }
+
+ protected void onStart() {
+ super.onStart();
+ mHost.startListening();
+ }
+
+ protected void onStop() {
+ super.onStop();
+ mHost.stopListening();
+ }
+
+ public void onCreateContextMenu(ContextMenu menu, View v,
+ ContextMenu.ContextMenuInfo menuInfo) {
+ menu.add(ContextMenu.NONE, R.string.delete_gadget, ContextMenu.NONE,
+ R.string.delete_gadget);
+ }
+
+ public boolean onContextItemSelected(MenuItem item) {
+ MyGadgetView view = (MyGadgetView)item.getMenuInfo();
+ switch (item.getItemId()) {
+ case R.string.delete_gadget:
+ Log.d(TAG, "delete! " + view.gadgetId);
+ mGadgetContainer.removeView(view);
+ mHost.deleteGadgetId(view.gadgetId);
+ break;
+ }
+
+ return true;
+ }
+
+ class MyGadgetView extends GadgetHostView implements ContextMenu.ContextMenuInfo {
+ int gadgetId;
+
+ MyGadgetView(int gadgetId) {
+ super(GadgetHostActivity.this);
+ this.gadgetId = gadgetId;
+ }
+
+ public ContextMenu.ContextMenuInfo getContextMenuInfo() {
+ return this;
+ }
+ }
+
+ GadgetHost mHost = new GadgetHost(this, HOST_ID) {
+ protected GadgetHostView onCreateView(Context context, int gadgetId, GadgetProviderInfo gadget) {
+ return new MyGadgetView(gadgetId);
+ }
+ };
+}
+
+
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java
new file mode 100644
index 0000000..897c13c
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetConfigure.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gadgethost;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.EditText;
+
+public class TestGadgetConfigure extends Activity {
+ static final String TAG = "TestGadgetConfigure";
+
+ public TestGadgetConfigure() {
+ super();
+ }
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.test_gadget_configure);
+
+ findViewById(R.id.save_button).setOnClickListener(mOnClickListener);
+ }
+
+ View.OnClickListener mOnClickListener = new View.OnClickListener() {
+ public void onClick(View v) {
+ String text = ((EditText)findViewById(R.id.edit_text)).getText().toString();
+ Log.d(TAG, "text is '" + text + '\'');
+ SharedPreferences.Editor prefs = getSharedPreferences(TestGadgetProvider.PREFS_NAME, 0)
+ .edit();
+ prefs.putString(TestGadgetProvider.PREF_PREFIX_KEY, text);
+ prefs.commit();
+ setResult(RESULT_OK);
+ finish();
+ }
+ };
+
+}
+
+
diff --git a/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
new file mode 100644
index 0000000..370a50b
--- /dev/null
+++ b/tests/gadgets/GadgetHostTest/src/com/android/tests/gadgethost/TestGadgetProvider.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gadgethost;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestGadgetProvider extends BroadcastReceiver {
+ static final String TAG = "TestGadgetProvider";
+
+ static final String PREFS_NAME = "com.android.tests.gadgethost.TestGadgetProvider";
+ static final String PREF_PREFIX_KEY = "prefix";
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "intent=" + intent);
+
+ if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
+ Log.d(TAG, "ENABLED");
+ }
+ else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
+ Log.d(TAG, "DISABLED");
+ }
+ else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
+ Log.d(TAG, "UPDATE");
+ // BEGIN_INCLUDE(getExtra_EXTRA_GADGET_IDS)
+ Bundle extras = intent.getExtras();
+ int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
+ // END_INCLUDE(getExtra_EXTRA_GADGET_IDS)
+
+ SharedPreferences prefs = context.getSharedPreferences(
+ TestGadgetProvider.PREFS_NAME, 0);
+ String prefix = prefs.getString(PREF_PREFIX_KEY, "hai");
+
+ GadgetManager gm = GadgetManager.getInstance(context);
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_gadget);
+ views.setTextViewText(R.id.oh_hai_text, prefix + ": " + SystemClock.elapsedRealtime());
+ if (false) {
+ gm.updateGadget(gadgetIds, views);
+ } else {
+ gm.updateGadget(new ComponentName("com.android.tests.gadgethost",
+ "com.android.tests.gadgethost.TestGadgetProvider"), views);
+ }
+ }
+ }
+}
+
diff --git a/tests/gadgets/GadgetProviderTest/Android.mk b/tests/gadgets/GadgetProviderTest/Android.mk
new file mode 100644
index 0000000..b9bfcdb
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := user
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := GadgetProvider
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/tests/gadgets/GadgetProviderTest/AndroidManifest.xml b/tests/gadgets/GadgetProviderTest/AndroidManifest.xml
new file mode 100644
index 0000000..47a7a2e
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/AndroidManifest.xml
@@ -0,0 +1,13 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.tests.gadgetprovider">
+ <uses-permission android:name="android.permission.VIBRATE" />
+
+ <application>
+ <receiver android:name="TestGadgetProvider">
+ <intent-filter>
+ <action android:name="android.gadget.action.GADGET_UPDATE" />
+ </intent-filter>
+ <meta-data android:name="android.gadget.provider" android:resource="@xml/gadget_info" />
+ </receiver>
+ </application>
+</manifest>
diff --git a/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml b/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml
new file mode 100644
index 0000000..e0a416e
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/layout/test_gadget.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2006 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/oh_hai_text"
+ android:layout_width="150dp"
+ android:layout_height="150dp"
+ android:text="@string/oh_hai"
+ android:background="#8fff"
+ android:textColor="#000"
+ android:textStyle="bold"
+/>
+
diff --git a/tests/gadgets/GadgetProviderTest/res/values/strings.xml b/tests/gadgets/GadgetProviderTest/res/values/strings.xml
new file mode 100644
index 0000000..e07725f
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/values/strings.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2007 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<resources>
+ <string name="gadget_view_title">Gadget Test</string>
+ <string name="add_gadget">Add Gadget</string>
+ <string name="oh_hai">Oh hai.</string>
+ <string name="delete_gadget">Delete</string>
+</resources>
+
diff --git a/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
new file mode 100644
index 0000000..33cc2e3
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/res/xml/gadget_info.xml
@@ -0,0 +1,7 @@
+<gadget-provider xmlns:android="http://schemas.android.com/apk/res/android"
+ android:minWidth="150dp"
+ android:minHeight="150dp"
+ android:updatePeriodMillis="2000"
+ android:initialLayout="@layout/test_gadget"
+ >
+</gadget-provider>
diff --git a/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
new file mode 100644
index 0000000..b81575f
--- /dev/null
+++ b/tests/gadgets/GadgetProviderTest/src/com/android/tests/gadgetprovider/TestGadgetProvider.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tests.gadgetprovider;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.gadget.GadgetManager;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.util.Log;
+import android.widget.RemoteViews;
+
+public class TestGadgetProvider extends BroadcastReceiver {
+
+ static final String TAG = "TestGadgetProvider";
+
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ Log.d(TAG, "intent=" + intent);
+
+ if (GadgetManager.ACTION_GADGET_ENABLED.equals(action)) {
+ Log.d(TAG, "ENABLED");
+ }
+ else if (GadgetManager.ACTION_GADGET_DISABLED.equals(action)) {
+ Log.d(TAG, "DISABLED");
+ }
+ else if (GadgetManager.ACTION_GADGET_UPDATE.equals(action)) {
+ Log.d(TAG, "UPDATE");
+ Bundle extras = intent.getExtras();
+ int[] gadgetIds = extras.getIntArray(GadgetManager.EXTRA_GADGET_IDS);
+
+ GadgetManager gm = GadgetManager.getInstance(context);
+ RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.test_gadget);
+ views.setTextViewText(R.id.oh_hai_text, "hai: " + SystemClock.elapsedRealtime());
+ if (false) {
+ gm.updateGadget(gadgetIds, views);
+ } else {
+ gm.updateGadget(new ComponentName("com.android.tests.gadgetprovider",
+ "com.android.tests.gadgetprovider.TestGadgetProvider"), views);
+ }
+ }
+ }
+}
+