Merge "Deflake WebViewTest#testPageScroll"
diff --git a/CtsTestCaseList.mk b/CtsTestCaseList.mk
index d149d70..c54832f 100644
--- a/CtsTestCaseList.mk
+++ b/CtsTestCaseList.mk
@@ -85,6 +85,7 @@
CtsDeviceInfo \
CtsDeviceOsTestApp \
CtsDeviceOwnerApp \
+ CtsServicesTestApp \
CtsDeviceTaskSwitchingAppA \
CtsDeviceTaskSwitchingAppB \
CtsDeviceTaskSwitchingControl \
@@ -93,7 +94,7 @@
CtsIntentSenderApp \
CtsLauncherAppsTests \
CtsLauncherAppsTestsSupport \
- CtsLeanbackJank \
+ CtsLeanbackJankApp \
CtsManagedProfileApp \
CtsMonkeyApp \
CtsMonkeyApp2 \
@@ -141,6 +142,7 @@
CtsBrowserTestCases \
CtsCalendarcommon2TestCases \
CtsCallLogTestCases \
+ CtsCameraTestCases \
CtsContentTestCases \
CtsDatabaseTestCases \
CtsDisplayTestCases \
@@ -218,7 +220,7 @@
# Host side only tests
cts_host_libraries := \
CtsAadbHostTestCases \
- CtsAppSecurityTests \
+ CtsAppSecurityHostTestCases \
CtsAppUsageHostTestCases \
CtsAtraceHostTestCases \
CtsDevicePolicyManagerTestCases \
@@ -229,6 +231,7 @@
CtsMonkeyTestCases \
CtsOsHostTestCases \
CtsSecurityHostTestCases \
+ CtsServicesHostTestCases \
CtsThemeHostTestCases \
CtsUiHostTestCases \
CtsUsbTests
diff --git a/apps/CameraITS/tests/scene0/test_metadata.py b/apps/CameraITS/tests/scene0/test_metadata.py
index 375a6af..44663bb 100644
--- a/apps/CameraITS/tests/scene0/test_metadata.py
+++ b/apps/CameraITS/tests/scene0/test_metadata.py
@@ -72,8 +72,6 @@
check('props.has_key("android.scaler.croppingType")')
check('props["android.scaler.croppingType"] is not None')
check('props["android.scaler.croppingType"] in [0,1]')
- if full:
- check('props["android.scaler.croppingType"] == 1')
assert(not failed)
diff --git a/apps/CameraITS/tests/scene1/test_exposure.py b/apps/CameraITS/tests/scene1/test_exposure.py
index 89bc724..dc4a790 100644
--- a/apps/CameraITS/tests/scene1/test_exposure.py
+++ b/apps/CameraITS/tests/scene1/test_exposure.py
@@ -61,8 +61,8 @@
mults.append(m)
s_test = round(s*m)
e_test = s_e_product / s_test
- print "Testsing s:", s_test, "e:", e_test
- req = its.objects.manual_capture_request(s_test, e_test)
+ print "Testing s:", s_test, "e:", e_test
+ req = its.objects.manual_capture_request(s_test, e_test, True, props)
cap = cam.do_capture(req)
s_res = cap["metadata"]["android.sensor.sensitivity"]
e_res = cap["metadata"]["android.sensor.exposureTime"]
@@ -112,4 +112,3 @@
if __name__ == '__main__':
main()
-
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index f1e5774..2d8f6a9 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -41,9 +41,7 @@
LOCAL_PACKAGE_NAME := CtsVerifier
-LOCAL_AAPT_FLAGS += --version-name "5.0_r1.91 $(BUILD_NUMBER)"
-
-LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni libaudioloopback_jni
+LOCAL_JNI_SHARED_LIBRARIES := libctsverifier_jni
LOCAL_PROGUARD_FLAG_FILES := proguard.flags
@@ -53,6 +51,32 @@
include $(BUILD_PACKAGE)
+# Build CTS verifier framework as a libary.
+
+include $(CLEAR_VARS)
+
+define java-files-in
+$(sort $(patsubst ./%,%, \
+ $(shell cd $(LOCAL_PATH) ; \
+ find -L $(1) -maxdepth 1 -name *.java -and -not -name ".*") \
+ ))
+endef
+
+LOCAL_MODULE := cts-verifier-framework
+LOCAL_AAPT_FLAGS := --auto-add-overlay --extra-packages android.support.v4
+LOCAL_SDK_VERSION := current
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SRC_FILES := \
+ $(call java-files-in, src/com/android/cts/verifier) \
+ $(call java-files-in, src/com/android/cts/verifier/backup) \
+ $(call all-java-files-under, src/android) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 \
+ compatibility-common-util-devicesidelib \
+ compatibility-device-util \
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
# opencv library
include $(CLEAR_VARS)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 8220649..e2a4772 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -17,7 +17,8 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.verifier"
- android:versionCode="5">
+ android:versionCode="5"
+ android:versionName="6.0_r2">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
@@ -57,6 +58,7 @@
<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" />
<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
+ <uses-permission android:name="android.permission.ACCESS_NOTIFICATION_POLICY" />
<!-- Needed by the Audio Quality Verifier to store the sound samples that will be mailed. -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
@@ -109,6 +111,26 @@
<!-- A generic activity for intent based tests -->
<activity android:name=".IntentDrivenTestActivity"/>
+ <activity android:name=".admin.DeviceAdminKeyguardDisabledFeaturesActivity"
+ android:label="@string/da_kg_disabled_features_test"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
+ </activity>
+
+ <activity android:name=".admin.RedactedNotificationKeyguardDisabledFeaturesActivity"
+ android:label="@string/rn_kg_disabled_features_test"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_device_admin" />
+ </activity>
+
<activity android:name=".admin.ScreenLockTestActivity"
android:label="@string/da_screen_lock_test"
android:configChanges="keyboardHidden|orientation|screenSize">
@@ -121,15 +143,6 @@
android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
</activity>
- <receiver android:name=".admin.TestDeviceAdminReceiver"
- android:permission="android.permission.BIND_DEVICE_ADMIN">
- <meta-data android:name="android.app.device_admin"
- android:resource="@xml/device_admin" />
- <intent-filter>
- <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
- </intent-filter>
- </receiver>
-
<activity android:name=".backup.BackupTestActivity" android:label="@string/backup_test">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@@ -1053,6 +1066,15 @@
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
</activity>
+ <activity android:name=".notifications.ConditionProviderVerifierActivity"
+ android:label="@string/cp_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+ </activity>
+
<activity android:name=".notifications.AttentionManagementVerifierActivity"
android:label="@string/attention_test">
<intent-filter>
@@ -1084,6 +1106,15 @@
</intent-filter>
</service>
+ <service android:name=".notifications.MockConditionProvider"
+ android:exported="true"
+ android:label="@string/cp_service_name"
+ android:permission="android.permission.BIND_CONDITION_PROVIDER_SERVICE">
+ <intent-filter>
+ <action android:name="android.service.notification.ConditionProviderService" />
+ </intent-filter>
+ </service>
+
<service android:name=".notifications.InteractiveVerifierActivity$DismissService"/>
<activity android:name=".security.CAInstallNotificationVerifierActivity"
@@ -1379,6 +1410,21 @@
android:label="@string/device_owner_wifi_lockdown_test">
</activity>
+ <activity android:name=".managedprovisioning.VpnTestActivity"
+ android:label="@string/device_owner_vpn_test">
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.VPN" />
+ <category android:name="android.intent.category.DEFAULT"></category>
+ </intent-filter>
+ </activity>
+
+ <service android:name=".managedprovisioning.VpnTestActivity$MyTestVpnService"
+ android:permission="android.permission.BIND_VPN_SERVICE">
+ <intent-filter>
+ <action android:name="android.net.VpnService"/>
+ </intent-filter>
+ </service>
+
<activity android:name=".managedprovisioning.PermissionLockdownTestActivity"
android:label="@string/device_profile_owner_permission_lockdown_test">
<intent-filter>
@@ -1432,6 +1478,10 @@
<action android:name="com.android.cts.verifier.managedprovisioning.TEST_NFC_BEAM" />
<action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_CROSS_PROFILE_INTENTS_DIALOG" />
<action android:name="com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.BYOD_SET_LOCATION_AND_CHECK" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.NOTIFICATION" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.CLEAR_NOTIFICATION" />
<category android:name="android.intent.category.DEFAULT"></category>
</intent-filter>
</activity>
@@ -1457,10 +1507,9 @@
</intent-filter>
</activity>
- <activity android:name=".managedprovisioning.CrossProfileTestActivity">
+ <activity android:name=".managedprovisioning.HandleIntentActivity"
+ android:enabled="false">
<intent-filter>
- <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL" />
- <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK" />
<!-- We need to have at least one activity listening to these intents on the device
to test if these are forwarded from the managed profile to the parent or
the other way around. -->
@@ -1543,6 +1592,14 @@
</intent-filter>
</activity>
+ <activity android:name=".managedprovisioning.CrossProfileTestActivity">
+ <intent-filter>
+ <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_PERSONAL" />
+ <action android:name="com.android.cts.verifier.managedprovisioning.CROSS_PROFILE_TO_WORK" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
<activity android:name=".managedprovisioning.WorkStatusTestActivity">
<intent-filter>
<action android:name="com.android.cts.verifier.managedprovisioning.WORK_STATUS_ICON" />
@@ -1551,15 +1608,6 @@
</intent-filter>
</activity>
- <activity android:name=".managedprovisioning.WorkNotificationTestActivity">
- <intent-filter>
- <action android:name="com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION" />
- <action android:name="com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION" />
- <action android:name="com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION" />
- <category android:name="android.intent.category.DEFAULT"></category>
- </intent-filter>
- </activity>
-
<receiver android:name=".managedprovisioning.DeviceAdminTestReceiver"
android:label="@string/afw_device_admin"
android:permission="android.permission.BIND_DEVICE_ADMIN">
diff --git a/apps/CtsVerifier/res/layout-land/sensor_test.xml b/apps/CtsVerifier/res/layout-land/sensor_test.xml
index f547978..ee96d41 100644
--- a/apps/CtsVerifier/res/layout-land/sensor_test.xml
+++ b/apps/CtsVerifier/res/layout-land/sensor_test.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/apps/CtsVerifier/res/layout-port/sensor_test.xml b/apps/CtsVerifier/res/layout-port/sensor_test.xml
index b4eca4d..4f5332e 100644
--- a/apps/CtsVerifier/res/layout-port/sensor_test.xml
+++ b/apps/CtsVerifier/res/layout-port/sensor_test.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/apps/CtsVerifier/res/layout-small/sensor_test.xml b/apps/CtsVerifier/res/layout-small/sensor_test.xml
index eefa5fa..7895596 100644
--- a/apps/CtsVerifier/res/layout-small/sensor_test.xml
+++ b/apps/CtsVerifier/res/layout-small/sensor_test.xml
@@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView android:id="@+id/log_scroll_view"
- app:layout_box="all"
+ app:ctsv_layout_box="all"
android:fillViewport="true"
android:layout_height="match_parent"
android:layout_width="match_parent">
diff --git a/apps/CtsVerifier/res/layout/ca_boot_notify.xml b/apps/CtsVerifier/res/layout/ca_boot_notify.xml
index 0ceece1..31edd27 100644
--- a/apps/CtsVerifier/res/layout/ca_boot_notify.xml
+++ b/apps/CtsVerifier/res/layout/ca_boot_notify.xml
@@ -18,7 +18,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:orientation="vertical" android:layout_width="fill_parent"
android:layout_height="fill_parent">
diff --git a/apps/CtsVerifier/res/layout/car_dock_test_main.xml b/apps/CtsVerifier/res/layout/car_dock_test_main.xml
index c568b54..afefa52 100644
--- a/apps/CtsVerifier/res/layout/car_dock_test_main.xml
+++ b/apps/CtsVerifier/res/layout/car_dock_test_main.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
diff --git a/apps/CtsVerifier/res/layout/fs_main.xml b/apps/CtsVerifier/res/layout/fs_main.xml
index 8a78c81..8f6029b 100644
--- a/apps/CtsVerifier/res/layout/fs_main.xml
+++ b/apps/CtsVerifier/res/layout/fs_main.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
diff --git a/apps/CtsVerifier/res/layout/intent_driven_test.xml b/apps/CtsVerifier/res/layout/intent_driven_test.xml
index bd9e4ca..75580b9 100644
--- a/apps/CtsVerifier/res/layout/intent_driven_test.xml
+++ b/apps/CtsVerifier/res/layout/intent_driven_test.xml
@@ -4,7 +4,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
diff --git a/apps/CtsVerifier/res/layout/js_charging.xml b/apps/CtsVerifier/res/layout/js_charging.xml
index 8d9ed1d..f2b20a0 100644
--- a/apps/CtsVerifier/res/layout/js_charging.xml
+++ b/apps/CtsVerifier/res/layout/js_charging.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView app:layout_box="all"
+ <ScrollView app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
@@ -29,30 +29,29 @@
android:text="@string/js_start_test_text"
android:onClick="startTest"
android:enabled="false"/>
-
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/js_padding"
- android:layout_marginBottom="@dimen/js_padding">
- <ImageView
- android:id="@+id/charging_off_test_image"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:src="@drawable/fs_indeterminate"
- android:layout_marginRight="@dimen/js_padding"/>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/js_charging_off_test"
- android:textSize="16dp"/>
- </LinearLayout>
<TextView
+ android:id="@+id/js_waiting_for_charging_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/js_padding"
- android:text="@string/js_charging_description_2"
- android:textStyle="bold"/>
+ android:text="@string/js_charging_description_3"
+ android:textStyle="bold"
+ android:visibility="gone"/>
+ <com.android.cts.verifier.TimerProgressBar
+ android:id="@+id/js_waiting_for_charging_progress_bar"
+ style="?android:attr/progressBarStyleHorizontal"
+ android:layout_width="fill_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/js_padding"
+ android:visibility="gone"/>
+ <TextView
+ android:id="@+id/js_problem_with_charger_text_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/js_padding"
+ android:text="@string/js_charging_description_4"
+ android:textStyle="bold"
+ android:visibility="gone"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
@@ -70,6 +69,29 @@
android:text="@string/js_charging_on_test"
android:textSize="16dp"/>
</LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_margin="@dimen/js_padding"
+ android:text="@string/js_charging_description_2"
+ android:textStyle="bold"/>
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="@dimen/js_padding"
+ android:layout_marginBottom="@dimen/js_padding">
+ <ImageView
+ android:id="@+id/charging_off_test_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/js_charging_off_test"
+ android:textSize="16dp"/>
+ </LinearLayout>
<include layout="@layout/pass_fail_buttons" />
</LinearLayout>
</ScrollView>
diff --git a/apps/CtsVerifier/res/layout/js_connectivity.xml b/apps/CtsVerifier/res/layout/js_connectivity.xml
index b0e2824..ae0725d 100644
--- a/apps/CtsVerifier/res/layout/js_connectivity.xml
+++ b/apps/CtsVerifier/res/layout/js_connectivity.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView app:layout_box="all"
+ <ScrollView app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
diff --git a/apps/CtsVerifier/res/layout/js_idle.xml b/apps/CtsVerifier/res/layout/js_idle.xml
index 4277173..200e66f 100644
--- a/apps/CtsVerifier/res/layout/js_idle.xml
+++ b/apps/CtsVerifier/res/layout/js_idle.xml
@@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <ScrollView app:layout_box="all"
+ <ScrollView app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
@@ -15,13 +15,6 @@
android:layout_height="wrap_content"
android:text="@string/js_test_description"
android:layout_margin="@dimen/js_padding"/>
- <TextView
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/js_idle_description_1"
- android:layout_margin="@dimen/js_padding"
- android:textStyle="bold"/>
-
<Button
android:id="@+id/js_idle_start_test_button"
android:layout_width="wrap_content"
@@ -30,6 +23,14 @@
android:text="@string/js_start_test_text"
android:onClick="startTest"
android:enabled="false"/>
+ <TextView
+ android:id="@+id/js_idle_continue_instruction_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/js_idle_continue_instruction"
+ android:layout_margin="@dimen/js_padding"
+ android:textStyle="bold"
+ android:visibility="gone"/>
<LinearLayout
android:layout_width="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/list_content.xml b/apps/CtsVerifier/res/layout/list_content.xml
index 8670283..b0e5354 100644
--- a/apps/CtsVerifier/res/layout/list_content.xml
+++ b/apps/CtsVerifier/res/layout/list_content.xml
@@ -22,7 +22,7 @@
<ListView
android:id="@android:id/list"
- app:layout_box="all"
+ app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.wearable.view.BoxInsetLayout>
diff --git a/apps/CtsVerifier/res/layout/location_mode_main.xml b/apps/CtsVerifier/res/layout/location_mode_main.xml
index 1768434..3ce532a 100644
--- a/apps/CtsVerifier/res/layout/location_mode_main.xml
+++ b/apps/CtsVerifier/res/layout/location_mode_main.xml
@@ -18,7 +18,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
diff --git a/apps/CtsVerifier/res/layout/pa_main.xml b/apps/CtsVerifier/res/layout/pa_main.xml
index 832af71..8cc9d3a 100644
--- a/apps/CtsVerifier/res/layout/pa_main.xml
+++ b/apps/CtsVerifier/res/layout/pa_main.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <RelativeLayout app:layout_box="all"
+ <RelativeLayout app:ctsv_layout_box="all"
android:layout_width="match_parent"
android:layout_height="match_parent" >
diff --git a/apps/CtsVerifier/res/layout/pass_fail_list.xml b/apps/CtsVerifier/res/layout/pass_fail_list.xml
index cdd40e1..7be427c 100644
--- a/apps/CtsVerifier/res/layout/pass_fail_list.xml
+++ b/apps/CtsVerifier/res/layout/pass_fail_list.xml
@@ -18,7 +18,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
diff --git a/apps/CtsVerifier/res/layout/poa_main.xml b/apps/CtsVerifier/res/layout/poa_main.xml
index 41bade0..1100d7f 100644
--- a/apps/CtsVerifier/res/layout/poa_main.xml
+++ b/apps/CtsVerifier/res/layout/poa_main.xml
@@ -17,7 +17,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <LinearLayout app:layout_box="all"
+ <LinearLayout app:ctsv_layout_box="all"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
diff --git a/apps/CtsVerifier/res/layout/pwa_widgets.xml b/apps/CtsVerifier/res/layout/pwa_widgets.xml
index 6204d3e..380b8f0 100644
--- a/apps/CtsVerifier/res/layout/pwa_widgets.xml
+++ b/apps/CtsVerifier/res/layout/pwa_widgets.xml
@@ -19,13 +19,13 @@
android:layout_height="match_parent">
<TextureView
- app:layout_box="all"
+ app:ctsv_layout_box="all"
android:id="@+id/texture_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
- app:layout_box="all"
+ app:ctsv_layout_box="all"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
diff --git a/apps/CtsVerifier/res/layout/vpn_test.xml b/apps/CtsVerifier/res/layout/vpn_test.xml
new file mode 100644
index 0000000..83c0c1b
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/vpn_test.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+ android:layout_height="match_parent">
+
+ <ScrollView
+ android:layout_width="match_parent"
+ android:layout_height="320dp"
+ android:layout_weight="2">
+ <TextView
+ android:id="@+id/device_owner_vpn_info"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"
+ android:text="@string/device_owner_vpn_info_default"
+ android:textSize="18dip" />
+ </ScrollView>
+
+ <include layout="@layout/pass_fail_buttons" />
+
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/wifi_lockdown.xml b/apps/CtsVerifier/res/layout/wifi_lockdown.xml
index ae6ea0c..2ac337e 100644
--- a/apps/CtsVerifier/res/layout/wifi_lockdown.xml
+++ b/apps/CtsVerifier/res/layout/wifi_lockdown.xml
@@ -16,8 +16,7 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- >
+ android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
@@ -74,4 +73,4 @@
<include layout="@layout/pass_fail_buttons" />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/attrs.xml b/apps/CtsVerifier/res/values/attrs.xml
index 71a1ba6..9490c87 100644
--- a/apps/CtsVerifier/res/values/attrs.xml
+++ b/apps/CtsVerifier/res/values/attrs.xml
@@ -15,7 +15,7 @@
-->
<resources>
<declare-styleable name="BoxInsetLayout_Layout">
- <attr name="layout_box">
+ <attr name="ctsv_layout_box">
<flag name="left" value="0x01" />
<flag name="top" value="0x02" />
<flag name="right" value="0x04" />
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index d8a96eb..c2e0e4f 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -124,6 +124,8 @@
settings that may specify a timeout.\n\nClick the \"Force Lock\" button to lock the screen.
Your screen should be locked and require the password to be entered.
</string>
+ <string name="da_kg_disabled_features_test">Keyguard Disabled Features Test</string>
+ <string name="rn_kg_disabled_features_test">Redacted Notifications Keyguard Disabled Features Test</string>
<string name="da_force_lock">Force Lock</string>
<string name="da_lock_success">It appears the screen was locked successfully!</string>
<string name="da_lock_error">It does not look like the screen was locked...</string>
@@ -339,8 +341,7 @@
<string name="hifi_ultrasound_test_default_false_string">false</string>
<string name="hifi_ultrasound_test_mic_no_support">
Device does not support near-ultrasound recording.\n
- All new phones and tablets MUST support near-ultrasound recording.\n
- Report FAIL if this is a new device, report PASS if this is an updating device.\n</string>
+ Please report PASS.\n</string>
<string name="hifi_ultrasound_test_spkr_no_support">
Device does not support near-ultrasound playback.\n
If this is your reference device, please use a different reference device.\n</string>
@@ -360,8 +361,7 @@
If this is your reference device, please use a different reference device.\n</string>
<string name="hifi_ultrasound_speaker_test_spkr_no_support">
Device does not support near-ultrasound playback.\n
- All new phones and tablets MUST support near-ultrasound playback.\n
- Report FAIL if this is a new device, report PASS if this is an updating device.\n</string>
+ Please report PASS.\n</string>
<string name="hifi_ultrasound_speaker_test_test_side">
Please wait for the result on the reference device then report here.</string>
<string name="hifi_ultrasound_speaker_test_reference_side">
@@ -1135,6 +1135,23 @@
<string name="nls_clear_all">Check that service can clear all notifications.</string>
<string name="nls_service_stopped">Service should stop once disabled.</string>
<string name="nls_note_missed">Check that notification was not received.</string>
+ <string name="cp_test">Condition Provider test</string>
+ <string name="cp_service_name">Condition Provider for CTS Verifier</string>
+ <string name="cp_info">This test checks that a ConditionProviderService can be enabled
+ and disabled, and that once enabled the service is able to create, query, edit, and delete
+ automatic zen rules.
+ </string>
+ <string name="cp_enable_service">Please enable \"CTS Verifier\" under Do Not Disturb access and return here.</string>
+ <string name="cp_disable_service">Please disable \"CTS Verifier\" under Do Not Disturb access and return here.</string>
+ <string name="cp_start_settings">Launch Settings</string>
+ <string name="cp_create_rule">Creating Automatic Zen Rule</string>
+ <string name="cp_subscribe_rule">Subscribing to Automatic Zen Rule</string>
+ <string name="cp_service_started">Service should start once enabled.</string>
+ <string name="cp_service_stopped">Service should stop once disabled.</string>
+ <string name="cp_unsubscribe_rule">Unsubscribing to Automatic Zen Rule</string>
+ <string name="cp_delete_rule">Deleting Automatic Zen Rule</string>
+ <string name="cp_get_rules">Retrieving Automatic Zen Rules</string>
+ <string name="cp_get_rule">Retrieving Automatic Zen Rule</string>
<string name="location_mode_high_accuracy_test">High Accuracy Mode Test</string>
<string name="location_mode_high_accuracy_info">
@@ -1296,6 +1313,7 @@
<string name="provisioning_byod_auth_bound_key_set_up">Set up</string>
<string name="provisioning_byod_lockscreen_bound_key">Lockscreen-bound key test</string>
<string name="provisioning_byod_fingerprint_bound_key">Fingerprint-bound key test</string>
+ <string name="provisioning_byod_vpn">Vpn test</string>
<!-- Strings for DeskClock -->
<string name="deskclock_tests">Alarms and Timers Tests</string>
<string name="deskclock_tests_info">
@@ -1341,8 +1359,8 @@
1. Press the "Create Alarm" button.\n
2. Verify that you see one alarm with the following information:\n
Name of alarm: Create Alarm Test. \n
- Vibrate: on.\n
- Ringtone: silent.\n
+ Vibrate: on. (if the device supports vibrate).\n
+ Ringtone: silent. (if the device has a speaker).\n
Time: 01:23. \n
Repeating on: Monday and Wednesday. \n
</string>
@@ -1424,8 +1442,29 @@
<string name="snsr_rotation_vector_set_final">Place the device back to the reference position.</string>
<string name="snsr_rotation_vector_verification">Angular deviation [%1$4.1f %2$4.1f %3$4.1f]. Current: %4$f deg. Max tolerated: %5$f.</string>
+ <!-- Strings for device admin tests -->
+ <string name="device_admin_notification">This is device admin notification</string>
+ <string name="device_admin_keyguard_disable_camera">Disable camera</string>
+ <string name="device_admin_keyguard_disable_camera_instruction">
+ Please press the Go button to lock the screen. Then try to open the camera
+ from the lower right corner of the screen. Expected result is you cannot
+ open the camera from lock screen and it will ask for password instead.
+ </string>
+ <string name="device_admin_disable_notifications">Disable notifications</string>
+ <string name="device_admin_disable_notifications_instruction">
+ Please press the Go button to lock the screen. Wait a few seconds to see
+ if a notification appears. Expected result is no notifications appear.
+ You should be able to see one after unlocking.
+ </string>
+ <string name="device_admin_disable_unredacted_notifications">Disable unredacted notifications</string>
+ <string name="device_admin_disable_unredacted_notifications_instruction">
+ Please press the Go button to lock the screen. Wait a few seconds to see
+ if a notification appears. Expected result is a notification appear with
+ its content hidden. You should be able to see the content after unlocking.
+ </string>
+
<!-- Strings common for BYOD and DO managed provisioning tests. -->
- <string name="afw_device_admin">CTS Verifier - AfW Admin</string>
+ <string name="afw_device_admin">CTS Verifier</string>
<!-- Strings for BYOD managed provisioning tests (ByodFlowTestActivity) -->
<string name="test_category_managed_provisioning">Managed Provisioning</string>
@@ -1493,7 +1532,7 @@
</string>
<string name="provisioning_byod_keyguard_disabled_features_instruction">
Please go to Settings > Security > Device administrators and set
- \"CTS Verifier - AfW Admin\" as active admin.\n
+ \"CTS Verifier\" as active admin.\n
After that please press the \"Prepare test\" button to disable trust agents.\n
Then please press through the following verification steps.\n
Note: Device password will be set to \"testpassword\". After leaving the screen device
@@ -1510,8 +1549,9 @@
<string name="provisioning_byod_fingerprint_disabled_in_settings">Fingerprint is disabled in Settings</string>
<string name="provisioning_byod_fingerprint_disabled_in_settings_instruction">
Please press the Go button to go to Settings > Security. Then go to Fingerprint and\n
- check if the screen is shown as disabled by the administrator.
- Then please press Back and mark the test as \"Pass\" or \"Fail\".
+ check if the disclaimer at the bottom of screen is altered to warn the users for\n
+ fingerprint being disabled in lock screen. Then please press Back and mark the \n
+ test as \"Pass\" or \"Fail\".
</string>
<string name="provisioning_byod_disable_fingerprint">Fingerprint disabled on keyguard</string>
<string name="provisioning_byod_disable_fingerprint_instruction">
@@ -1519,12 +1559,12 @@
Expected result is you cannot log in using your fingerprint.\n
After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
</string>
- <string name="provisioning_byod_disable_notifications">Notifications disabled on keyguard</string>
- <string name="provisioning_byod_disable_notifications_instruction">
+ <string name="provisioning_byod_disable_unredacted_notifications">Unredacted notifications disabled on keyguard</string>
+ <string name="provisioning_byod_disable_unredacted_notifications_instruction">
Please press the Go button to lock the screen. Wait a couple of seconds and look out for a
notification from CtsVerifier.\n
Expected result is the notification is shown as \"Contents hidden\", you can not see the contents
- (Which would read \"This is a work notification\").\n
+ (Which would read \"This is a notification\"). You should be seeing a work badge.\n
After you log back in, please navigate back to CtsVerifier and mark the test as \"Pass\" or \"Fail\".
</string>
<string name="provisioning_byod_work_notification">Work notification is badged</string>
@@ -1533,7 +1573,7 @@
\n
Verify that the notification is badged (see sample badge below). Then mark this test accordingly.
</string>
- <string name="provisioning_byod_work_notification_title">This is a work notification</string>
+ <string name="provisioning_byod_notification_title">This is a notification</string>
<string name="provisioning_byod_work_status_icon">Work status icon is displayed</string>
<string name="provisioning_byod_work_status_icon_instruction">
Verify that the current status bar does not have a work status icon (see sample icon below).
@@ -1578,7 +1618,7 @@
Navigate to Device administrators and confirm that:\n
\n
- Both Personal and Work categories exist.\n
- - \"CTS Verifier - AfW Admin\" exists under the Work category, and is activated.\n
+ - \"CTS Verifier\" exists under the Work category, and is activated.\n
\n
Use the Back button to return to this page.
</string>
@@ -1686,6 +1726,27 @@
<string name="provisioning_button_finish">Finish</string>
<string name="provisioning_cross_profile_chooser">Choose an app to complete action</string>
+ <string name="provisioning_byod_no_gps_location_feature">No GPS feature present. Skip test.</string>
+ <string name="provisioning_byod_location_mode_enable">Enable location</string>
+ <string name="provisioning_byod_location_mode_enable_toast_location_change">Location changed</string>
+ <string name="provisioning_byod_location_mode_enable_instruction">
+ This test verifies that the location updates can be enabled for the managed profile apps.\n
+ 1. Press the go button to go to the location settings page, set the location switch enabled.\n
+ 2. Move your position a little bit, verify that location updates toast comes up.\n
+ Please wait until the location updates or timeout toast message shows up before going back to the cts-verifier tests.\n
+ 3. Go back to the cts-verifier tests using the back button, then mark the test accordingly.\n
+ </string>
+
+ <string name="provisioning_byod_location_mode_disable">Disable location</string>
+ <string name="provisioning_byod_location_mode_time_out_toast">Timeout waiting for gps location change</string>
+ <string name="provisioning_byod_location_mode_disable_instruction">
+ This test verifies that the location updates can be disabled for the managed profile apps.\n
+ 1. Press the go button to go to the location settings page, set the location switch disabled.\n
+ 2. Move your position a little bit, verify that no location updates toast come up and that the timeout message show up after around 15 seconds.
+ Please wait until the timeout or location updates toast message shows up before going back to the cts-verifier tests.\n
+ 3. Go back to the cts-verifier tests using the back button, then mark the test accordingly.\n
+ </string>
+
<!-- Strings for DeviceOwnerProvisioningTest -->
<string name="provisioning_device_owner">Device Owner Provisioning</string>
<string name="device_owner_provisioning_tests">Device Owner provisioning tests</string>
@@ -1732,7 +1793,7 @@
<string name="device_owner_wifi_lockdown_info">
Please enter the SSID and auth method of an available WiFi Access Point and press the button to create a
WiFi configuration. This configuration can be seen on Settings > WiFi. The test cases
- are going use this config. Please go through test cases in order (from top to bottom).
+ are going to use this config. Please go through test cases in order (from top to bottom).
</string>
<string name="switch_wifi_lockdown_off_button">WiFi config lockdown off</string>
<string name="switch_wifi_lockdown_on_button">WiFi config lockdown on</string>
@@ -1824,8 +1885,8 @@
Please press the Go button to open the Security page in Settings.
Navigate to Device administrators and confirm that:\n
\n
- - \"CTS Verifier - AfW Admin\" exists and is activated.\n
- - \"CTS Verifier - AfW Admin\" cannot be disabled.\n
+ - \"CTS Verifier\" exists and is activated.\n
+ - \"CTS Verifier\" cannot be disabled.\n
\n
Use the Back button to return to this page.
</string>
@@ -1854,6 +1915,42 @@
<string name="device_owner_user_restriction_set">Set restriction</string>
<string name="device_owner_settings_go">Go</string>
+ <string name="device_owner_vpn_connection">
+ Vpn connection has been established.\n
+ This is not as expected.\n
+ Mark this test as failed.\n
+ </string>
+ <string name="device_owner_vpn_connection_close_failed">
+ Established vpn connection cannot be closed.\n
+ This is not as expected.\n
+ Mark this test as failed.\n
+ </string>
+ <string name="device_owner_no_vpn_connection">
+ Cannot establish a VPN connection.\n
+ This was expected.\n
+ Mark this test as passed.\n
+ </string>
+ <string name="device_owner_vpn_connection_canceled">
+ Cannot establish a VPN connection.\n
+ Connection canceled by user.\n
+ </string>
+ <string name="device_owner_vpn_test">Check VPN</string>
+ <string name="device_owner_vpn_info_default">Vpn test message</string>
+
+ <string name="device_owner_disallow_config_vpn">Disallow configuring VPN</string>
+ <string name="device_owner_disallow_config_vpn_info">
+ Please press the Set VPN restriction button to set the VPN restriction.
+ Perform tests in order. Mark test as passed if both test cases pass\n\n
+ 1. Press Go to open the Vpn settings page.\n
+ Confirm that:\n
+ - You cannot add a new VPN network.\n
+ - You cannot edit, add or remove any existing VPNs.\n\n
+ 2. Press Check VPN to check programmatic Vpn test.\n
+ - Check Vpn setup\n\n
+ Use the Back button to return to this page.
+ </string>
+ <string name="device_owner_user_vpn_restriction_set">Set VPN restriction</string>
+
<!-- Strings for JobScheduler Tests -->
<string name="js_test_description">This test is mostly automated, but requires some user interaction. You can pass this test once the list items below are checked.</string>
@@ -1861,15 +1958,20 @@
<string name="js_start_test_text">Start test</string>
<string name="js_idle_instructions">Verify the behaviour of the JobScheduler API for when the device is in idle mode. Simply follow the on-screen instructions.</string>
<string name="js_idle_description_1">Turn the screen off and then back on in order to begin.</string>
+ <string name="js_idle_continue_instruction">
+ Switch off screen and wait for it to turn on to continue.
+ </string>
<string name="js_idle_item_idle_off">Idle job does not execute when device is not idle.</string>
<string name="js_idle_item_idle_on">Idle job does execute when device is forced into idle.</string>
<string name="js_charging_test">Charging Constraints</string>
<string name="js_charging_instructions">Verify the behaviour of the JobScheduler API for when the device is on power and unplugged from power. Simply follow the on-screen instructions.</string>
- <string name="js_charging_description_1">Unplug the device in order to begin.</string>
+ <string name="js_charging_description_1">Plug in the charger if it isn\'t already plugged in.</string>
<string name="js_charging_off_test">Device not charging will not execute a job with a charging constraint.</string>
<string name="js_charging_on_test">Device when charging will execute a job with a charging constraint.</string>
- <string name="js_charging_description_2">After the above test has passed, plug the device back in to continue. If the above failed, you can simply fail this test.</string>
+ <string name="js_charging_description_2">After the above test has passed, remove the charger to continue. If the above failed, you can simply fail this test.</string>
+ <string name="js_charging_description_3">Device is plugged in. Please wait while it get\s into stable charging state.</string>
+ <string name="js_charging_description_4">There seems to be a problem with your charger. Pleasy try again.</string>
<string name="js_connectivity_test">Connectivity Constraints</string>
<string name="js_connectivity_instructions">Verify the behaviour of the JobScheduler API for when the device has no access to data connectivity. Simply follow the on-screen instructions.</string>
@@ -2082,6 +2184,10 @@
<string name="audio_general_headset_port_exists">Does this device have a headset port?</string>
<string name="audio_general_headset_no">No</string>
<string name="audio_general_headset_yes">Yes</string>
+ <string name="audio_general_deficiency_found">WARNING: Some results show potential deficiencies on the system.
+ Please consider addressing them for a future release.</string>
+ <string name="audio_general_test_passed">Test Successful</string>
+ <string name="audio_general_test_failed">Test Failed</string>
<!-- Audio Loopback Latency Test -->
<string name="audio_loopback_test">Audio Loopback Latency Test</string>
diff --git a/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java b/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java
index 77d6a21..7718bd1 100644
--- a/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java
+++ b/apps/CtsVerifier/src/android/support/wearable/view/BoxInsetLayout.java
@@ -34,10 +34,10 @@
/**
* BoxInsetLayout is a screen shape-aware FrameLayout that can box its children
* in the center square of a round screen by using the
- * {@code layout_box} attribute. The values for this attribute specify the
+ * {@code ctsv_layout_box} attribute. The values for this attribute specify the
* child's edges to be boxed in:
* {@code left|top|right|bottom} or {@code all}.
- * The {@code layout_box} attribute is ignored on a device with a rectangular
+ * The {@code ctsv_layout_box} attribute is ignored on a device with a rectangular
* screen.
*/
@TargetApi(Build.VERSION_CODES.KITKAT_WATCH)
@@ -383,7 +383,7 @@
}
/**
- * adds {@code layout_box} attribute to layout parameters
+ * adds {@code ctsv_layout_box} attribute to layout parameters
*/
public static class LayoutParams extends FrameLayout.LayoutParams {
@@ -399,7 +399,7 @@
public LayoutParams(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BoxInsetLayout_Layout, 0, 0);
- boxedEdges = a.getInt(R.styleable.BoxInsetLayout_Layout_layout_box, BOX_NONE);
+ boxedEdges = a.getInt(R.styleable.BoxInsetLayout_Layout_ctsv_layout_box, BOX_NONE);
a.recycle();
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
index 91b8d93..167fd84 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/DialogTestListActivity.java
@@ -98,11 +98,6 @@
*/
protected abstract void setupTests(ArrayTestListAdapter adapter);
- // Enable Pass Button when all tests passed.
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
public class DefaultTestCallback implements DialogTestListItem.TestCallback {
final private DialogTestListItem mTest;
@@ -193,6 +188,7 @@
try {
startActivity(intent);
} catch (ActivityNotFoundException e) {
+ Log.w(TAG, "Cannot start activity.", e);
Toast.makeText(this, "Cannot start " + intent, Toast.LENGTH_LONG).show();
setTestResult(test, TestResult.TEST_RESULT_FAILED);
return false;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
index 6b9316f..44e2e0f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/ManifestTestListAdapter.java
@@ -154,6 +154,7 @@
List<ResolveInfo> getResolveInfosForParent() {
Intent mainIntent = new Intent(Intent.ACTION_MAIN);
mainIntent.addCategory(CATEGORY_MANUAL_TEST);
+ mainIntent.setPackage(mContext.getPackageName());
PackageManager packageManager = mContext.getPackageManager();
List<ResolveInfo> list = packageManager.queryIntentActivities(mainIntent,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
index 5a08558..8e4e63c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/PassFailButtons.java
@@ -262,6 +262,10 @@
@Override
public ReportLog getReportLog() { return reportLog; }
+
+ public void updatePassButton() {
+ getPassButton().setEnabled(mAdapter.allTestsPassed());
+ }
}
private static <T extends android.app.Activity & PassFailActivity>
@@ -324,8 +328,7 @@
ContentResolver resolver = activity.getContentResolver();
Cursor cursor = null;
try {
- cursor = resolver.query(
- TestResultsProvider.getTestNameUri(activity.getClass().getName()),
+ cursor = resolver.query(TestResultsProvider.getTestNameUri(activity),
new String[] {TestResultsProvider.COLUMN_TEST_INFO_SEEN}, null, null, null);
return cursor.moveToFirst() && cursor.getInt(0) > 0;
} finally {
@@ -388,10 +391,9 @@
values.put(TestResultsProvider.COLUMN_TEST_NAME, activity.getClass().getName());
values.put(TestResultsProvider.COLUMN_TEST_INFO_SEEN, 1);
int numUpdated = resolver.update(
- TestResultsProvider.getTestNameUri(activity.getClass().getName()),
- values, null, null);
+ TestResultsProvider.getTestNameUri(activity), values, null, null);
if (numUpdated == 0) {
- resolver.insert(TestResultsProvider.RESULTS_CONTENT_URI, values);
+ resolver.insert(TestResultsProvider.getResultContentUri(activity), values);
}
}
@@ -399,16 +401,14 @@
private static void setTestResultAndFinish(android.app.Activity activity, String testId,
String testDetails, ReportLog reportLog, View target) {
boolean passed;
- switch (target.getId()) {
- case R.id.pass_button:
- passed = true;
- break;
- case R.id.fail_button:
- passed = false;
- break;
- default:
- throw new IllegalArgumentException("Unknown id: " + target.getId());
+ if (target.getId() == R.id.pass_button) {
+ passed = true;
+ } else if (target.getId() == R.id.fail_button) {
+ passed = false;
+ } else {
+ throw new IllegalArgumentException("Unknown id: " + target.getId());
}
+
setTestResultAndFinishHelper(activity, testId, testDetails, passed, reportLog);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index 976ff32..6a96961 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -19,7 +19,9 @@
import android.Manifest;
import android.app.ListActivity;
import android.content.Intent;
+import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
@@ -33,19 +35,6 @@
/** Top-level {@link ListActivity} for launching tests and managing results. */
public class TestListActivity extends AbstractTestListActivity implements View.OnClickListener {
-
- private static final String [] RUNTIME_PERMISSIONS = {
- Manifest.permission.ACCESS_FINE_LOCATION,
- Manifest.permission.BODY_SENSORS,
- Manifest.permission.READ_EXTERNAL_STORAGE,
- Manifest.permission.READ_PHONE_STATE,
- Manifest.permission.CALL_PHONE,
- Manifest.permission.WRITE_CONTACTS,
- Manifest.permission.CAMERA,
- Manifest.permission.WRITE_EXTERNAL_STORAGE,
- Manifest.permission.RECORD_AUDIO,
- Manifest.permission.READ_CONTACTS
- };
private static final int CTS_VERIFIER_PERMISSION_REQUEST = 1;
private static final String TAG = TestListActivity.class.getSimpleName();
@@ -59,15 +48,25 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- for (String runtimePermission : RUNTIME_PERMISSIONS) {
- Log.v(TAG, "Checking permissions for: " + runtimePermission);
- if (checkSelfPermission(runtimePermission) != PackageManager.PERMISSION_GRANTED) {
- requestPermissions(RUNTIME_PERMISSIONS, CTS_VERIFIER_PERMISSION_REQUEST);
- return;
- }
+ try {
+ PackageInfo packageInfo = getPackageManager().getPackageInfo(
+ getApplicationInfo().packageName, PackageManager.GET_PERMISSIONS);
+ if (packageInfo.requestedPermissions != null) {
+ for (String permission : packageInfo.requestedPermissions) {
+ Log.v(TAG, "Checking permissions for: " + permission);
+ if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(packageInfo.requestedPermissions,
+ CTS_VERIFIER_PERMISSION_REQUEST);
+ return;
+ }
+ }
+ }
+ createContinue();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Unable to load package's permissions", e);
+ Toast.makeText(this, R.string.runtime_permissions_error, Toast.LENGTH_SHORT).show();
}
- createContinue();
}
private void createContinue() {
@@ -137,21 +136,16 @@
}
private boolean handleMenuItemSelected(int id) {
- switch (id) {
- case R.id.clear:
- handleClearItemSelected();
- return true;
-
- case R.id.view:
- handleViewItemSelected();
- return true;
-
- case R.id.export:
- handleExportItemSelected();
- return true;
-
- default:
- return false;
+ if (id == R.id.clear) {
+ handleClearItemSelected();
+ } else if (id == R.id.view) {
+ handleViewItemSelected();
+ } else if (id == R.id.export) {
+ handleExportItemSelected();
+ } else {
+ return false;
}
+
+ return true;
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
index ce092cc..642b951 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListAdapter.java
@@ -163,7 +163,7 @@
TestResultContentObserver observer = new TestResultContentObserver();
ContentResolver resolver = context.getContentResolver();
- resolver.registerContentObserver(TestResultsProvider.RESULTS_CONTENT_URI, true, observer);
+ resolver.registerContentObserver(TestResultsProvider.getResultContentUri(context), true, observer);
}
public void loadTestResults() {
@@ -236,7 +236,7 @@
ContentResolver resolver = mContext.getContentResolver();
Cursor cursor = null;
try {
- cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI, REFRESH_PROJECTION,
+ cursor = resolver.query(TestResultsProvider.getResultContentUri(mContext), REFRESH_PROJECTION,
null, null, null);
if (cursor.moveToFirst()) {
do {
@@ -262,7 +262,7 @@
@Override
protected Void doInBackground(Void... params) {
ContentResolver resolver = mContext.getContentResolver();
- resolver.delete(TestResultsProvider.RESULTS_CONTENT_URI, "1", null);
+ resolver.delete(TestResultsProvider.getResultContentUri(mContext), "1", null);
return null;
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
index 45e528f..2527d57 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsBackupHelper.java
@@ -53,7 +53,7 @@
ContentResolver resolver = mContext.getContentResolver();
Cursor cursor = null;
try {
- cursor = resolver.query(TestResultsProvider.RESULTS_CONTENT_URI,
+ cursor = resolver.query(TestResultsProvider.getResultContentUri(mContext),
null, null, null, null);
int nameIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_NAME);
int resultIndex = cursor.getColumnIndex(TestResultsProvider.COLUMN_TEST_RESULT);
@@ -128,7 +128,7 @@
}
ContentResolver resolver = mContext.getContentResolver();
- resolver.bulkInsert(TestResultsProvider.RESULTS_CONTENT_URI, values);
+ resolver.bulkInsert(TestResultsProvider.getResultContentUri(mContext), values);
} else {
Log.e(TAG, "Skipping key: " + data.getKey());
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
index a9f672e..64c04eb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsProvider.java
@@ -39,13 +39,26 @@
private static final String RESULTS_PATH = "results";
- public static final String AUTHORITY = "com.android.cts.verifier.testresultsprovider";
- public static final Uri CONTENT_URI = Uri.parse("content://" + AUTHORITY);
- public static final Uri RESULTS_CONTENT_URI =
- Uri.withAppendedPath(CONTENT_URI, RESULTS_PATH);
+ /**
+ * Get the URI from the result content.
+ * @param context
+ * @return Uri
+ */
+ public static Uri getResultContentUri(Context context) {
+ final String packageName = context.getPackageName();
+ final Uri contentUri = Uri.parse("content://" + packageName + ".testresultsprovider");
+ return Uri.withAppendedPath(contentUri, RESULTS_PATH);
+ }
- public static Uri getTestNameUri(String testName) {
- return Uri.withAppendedPath(RESULTS_CONTENT_URI, testName);
+ /**
+ * Get the URI from the test name.
+ * @param context
+ * @param testName
+ * @return Uri
+ */
+ public static Uri getTestNameUri(Context context) {
+ final String testName = context.getClass().getName();
+ return Uri.withAppendedPath(getResultContentUri(context), testName);
}
static final String _ID = "_id";
@@ -69,11 +82,6 @@
private static final int RESULTS_ALL = 1;
private static final int RESULTS_ID = 2;
private static final int RESULTS_TEST_NAME = 3;
- static {
- URI_MATCHER.addURI(AUTHORITY, RESULTS_PATH, RESULTS_ALL);
- URI_MATCHER.addURI(AUTHORITY, RESULTS_PATH + "/#", RESULTS_ID);
- URI_MATCHER.addURI(AUTHORITY, RESULTS_PATH + "/*", RESULTS_TEST_NAME);
- }
private static final String TABLE_NAME = "results";
@@ -83,6 +91,12 @@
@Override
public boolean onCreate() {
+ final String authority = getContext().getPackageName() + ".testresultsprovider";
+
+ URI_MATCHER.addURI(authority, RESULTS_PATH, RESULTS_ALL);
+ URI_MATCHER.addURI(authority, RESULTS_PATH + "/#", RESULTS_ID);
+ URI_MATCHER.addURI(authority, RESULTS_PATH + "/*", RESULTS_TEST_NAME);
+
mOpenHelper = new TestResultsOpenHelper(getContext());
mBackupManager = new BackupManager(getContext());
return false;
@@ -153,7 +167,7 @@
long id = db.insert(TABLE_NAME, null, values);
getContext().getContentResolver().notifyChange(uri, null);
mBackupManager.dataChanged();
- return Uri.withAppendedPath(RESULTS_CONTENT_URI, "" + id);
+ return Uri.withAppendedPath(getResultContentUri(getContext()), "" + id);
}
@Override
@@ -219,13 +233,14 @@
values.put(TestResultsProvider.COLUMN_TEST_DETAILS, testDetails);
values.put(TestResultsProvider.COLUMN_TEST_METRICS, serialize(reportLog));
+ final Uri uri = getResultContentUri(context);
ContentResolver resolver = context.getContentResolver();
- int numUpdated = resolver.update(TestResultsProvider.RESULTS_CONTENT_URI, values,
+ int numUpdated = resolver.update(uri, values,
TestResultsProvider.COLUMN_TEST_NAME + " = ?",
new String[] {testName});
if (numUpdated == 0) {
- resolver.insert(TestResultsProvider.RESULTS_CONTENT_URI, values);
+ resolver.insert(uri, values);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
index ff6bc76..76eb8a1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestResultsReport.java
@@ -96,7 +96,6 @@
xml.startTag(null, VERIFIER_INFO_TAG);
xml.attribute(null, "version-name", Version.getVersionName(mContext));
xml.attribute(null, "version-code", Integer.toString(Version.getVersionCode(mContext)));
- xml.attribute(null, "build", Version.getBuildNumber(mContext));
xml.endTag(null, VERIFIER_INFO_TAG);
xml.startTag(null, DEVICE_INFO_TAG);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TimerProgressBar.java b/apps/CtsVerifier/src/com/android/cts/verifier/TimerProgressBar.java
new file mode 100644
index 0000000..4e0f61e
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TimerProgressBar.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier;
+
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.widget.ProgressBar;
+
+/**
+ * Can be used to show time outs for events. A progress bar will be displayed to the user.
+ * On calling start, it will start filling up.
+ */
+public class TimerProgressBar extends ProgressBar {
+ public TimerProgressBar(Context context) {
+ super(context);
+ setHandler(context);
+ }
+
+ public TimerProgressBar(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setHandler(context);
+ }
+
+ public TimerProgressBar(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ setHandler(context);
+ }
+
+ @TargetApi(21)
+ public TimerProgressBar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+ super(context, attrs, defStyleAttr, defStyleRes);
+ setHandler(context);
+ }
+
+ private void setHandler(Context context) {
+ mHandler = new Handler(context.getMainLooper());
+ }
+
+ private Handler mHandler;
+ private TimerExpiredCallback mTimerExpiredCallback;
+ private long mStartTime;
+ private long mDuration;
+ private long mStepSize;
+ private boolean mForceComplete;
+
+ private Runnable mProgressCallback = new Runnable() {
+ @Override
+ public void run() {
+ if (mForceComplete) {
+ TimerProgressBar.this.setProgress(TimerProgressBar.this.getMax());
+ return;
+ }
+
+ long currentTime = SystemClock.elapsedRealtime();
+ int progress = (int) ((currentTime - mStartTime) / mStepSize);
+ progress = Math.min(progress, TimerProgressBar.this.getMax());
+ TimerProgressBar.this.setProgress(progress);
+
+ if (mStartTime + mDuration > currentTime) {
+ mHandler.postDelayed(this, mStepSize);
+ } else {
+ if (mTimerExpiredCallback != null) {
+ mTimerExpiredCallback.onTimerExpired();
+ }
+ }
+ }
+ };
+
+ public void start(long duration, long stepSize) {
+ start(duration, stepSize, null);
+ }
+
+ /**
+ * Start filling up the progress bar.
+ *
+ * @param duration Time in milliseconds the progress bar takes to fill up completely
+ * @param stepSize Time in milliseconds between consecutive updates to progress bar's progress
+ * @param callback Callback that should be executed after the progress bar is filled completely (i.e. timer expires)
+ */
+ public void start(long duration, long stepSize, TimerExpiredCallback callback) {
+ mDuration = duration;
+ mStepSize = stepSize;
+ mStartTime = SystemClock.elapsedRealtime();
+ mForceComplete = false;
+ mTimerExpiredCallback = callback;
+ this.setMax((int) (duration / stepSize));
+ this.setProgress(0);
+ mHandler.post(mProgressCallback);
+ }
+
+ /**
+ * Fill the progress bar completely. Timer expired callback won't be executed.
+ */
+ public void forceComplete() {
+ mForceComplete = true;
+ }
+
+ public interface TimerExpiredCallback {
+ void onTimerExpired();
+ }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/Version.java b/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
index dfe9508..e7b6121 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/Version.java
@@ -24,21 +24,13 @@
class Version {
static String getVersionName(Context context) {
- return getVersionNameStrings(context)[0];
+ return getPackageInfo(context).versionName;
}
static int getVersionCode(Context context) {
return getPackageInfo(context).versionCode;
}
- static String getBuildNumber(Context context) {
- return getVersionNameStrings(context)[1];
- }
-
- static private String[] getVersionNameStrings(Context context) {
- return getPackageInfo(context).versionName.split(" ");
- }
-
static PackageInfo getPackageInfo(Context context) {
try {
PackageManager packageManager = context.getPackageManager();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/DeviceAdminKeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/DeviceAdminKeyguardDisabledFeaturesActivity.java
new file mode 100644
index 0000000..2ad77f6
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/DeviceAdminKeyguardDisabledFeaturesActivity.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.admin;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.fingerprint.FingerprintManager;
+import android.provider.Settings;
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
+import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
+import com.android.cts.verifier.managedprovisioning.KeyguardDisabledFeaturesActivity;
+
+
+/**
+ * Tests for Device Admin keyguard disabled features.
+ */
+public class DeviceAdminKeyguardDisabledFeaturesActivity extends KeyguardDisabledFeaturesActivity {
+ @Override
+ protected int getKeyguardDisabledFeatures() {
+ return DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_ALL;
+ }
+
+ @Override
+ protected void setKeyguardDisabledFeatures() {
+ int flags = getKeyguardDisabledFeatures();
+ mDpm.setKeyguardDisabledFeatures(getAdminComponent(), flags);
+ }
+
+ @Override
+ protected String getTestIdPrefix() {
+ return "DeviceAdmin_";
+ }
+
+ @Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ setupFingerprintTests(adapter);
+ setupDisableTrustAgentsTest(adapter);
+ adapter.add(new DialogTestListItem(this, R.string.device_admin_keyguard_disable_camera,
+ getTestIdPrefix()+"KeyguardDisableCamera",
+ R.string.device_admin_keyguard_disable_camera_instruction,
+ new Intent(ByodHelperActivity.ACTION_LOCKNOW)));
+
+ adapter.add(new DialogTestListItem(this, R.string.device_admin_disable_notifications,
+ "DeviceAdmin_DisableNotifications",
+ R.string.device_admin_disable_notifications_instruction,
+ new Intent(ByodHelperActivity.ACTION_NOTIFICATION_ON_LOCKSCREEN)));
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
index 1591df3..ee24868 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/PolicySerializationTestActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.admin;
+import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -73,7 +74,7 @@
setPassFailButtonClickListeners();
mDevicePolicyManager = (DevicePolicyManager) getSystemService(DEVICE_POLICY_SERVICE);
- mAdmin = TestDeviceAdminReceiver.getComponent(this);
+ mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
mGeneratePolicyButton = findViewById(R.id.generate_policy_button);
mGeneratePolicyButton.setOnClickListener(new OnClickListener() {
@@ -136,7 +137,7 @@
private void applyPolicy() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
- TestDeviceAdminReceiver.getComponent(this));
+ DeviceAdminTestReceiver.getReceiverComponentName());
startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
}
@@ -152,7 +153,7 @@
private void handleAddDeviceAdminResult(int resultCode, Intent data) {
if (resultCode == RESULT_OK) {
- ComponentName admin = TestDeviceAdminReceiver.getComponent(this);
+ ComponentName admin = DeviceAdminTestReceiver.getReceiverComponentName();
for (PolicyItem<?> item : mPolicyItems) {
item.applyExpectedValue(mDevicePolicyManager, admin);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/RedactedNotificationKeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/RedactedNotificationKeyguardDisabledFeaturesActivity.java
new file mode 100644
index 0000000..711fd8c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/RedactedNotificationKeyguardDisabledFeaturesActivity.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.admin;
+
+import android.app.admin.DevicePolicyManager;
+
+import android.content.Intent;
+
+
+import com.android.cts.verifier.ArrayTestListAdapter;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.DialogTestListActivity;
+import com.android.cts.verifier.managedprovisioning.ByodHelperActivity;
+
+/**
+ * Tests for Device Admin keyguard redacted notification feature. This test is taken out from
+ * DeviceAdminKeyguardDisabledFeaturesActivity class, because KEYGUARD_DISABLE_SECURE_NOTIFICATIONS
+ * would mask KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS.
+ * */
+
+public class RedactedNotificationKeyguardDisabledFeaturesActivity
+ extends DeviceAdminKeyguardDisabledFeaturesActivity {
+ @Override
+ protected int getKeyguardDisabledFeatures() {
+ return DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+ }
+
+ @Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ adapter.add(new DialogTestListItem(this, R.string.device_admin_disable_unredacted_notifications,
+ "DeviceAdmin_DisableUnredactedNotifications",
+ R.string.device_admin_disable_unredacted_notifications_instruction,
+ new Intent(ByodHelperActivity.ACTION_NOTIFICATION_ON_LOCKSCREEN)));
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/ScreenLockTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/admin/ScreenLockTestActivity.java
index 5520bb7..41217a6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/ScreenLockTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/admin/ScreenLockTestActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.admin;
+import com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver;
import com.android.cts.verifier.PassFailButtons;
import com.android.cts.verifier.R;
@@ -72,7 +73,7 @@
private void sendAddDeviceAdminIntent() {
Intent intent = new Intent(DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN);
intent.putExtra(DevicePolicyManager.EXTRA_DEVICE_ADMIN,
- TestDeviceAdminReceiver.getComponent(this));
+ DeviceAdminTestReceiver.getReceiverComponentName());
startActivityForResult(intent, ADD_DEVICE_ADMIN_REQUEST_CODE);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
index 508fae0..edb3bf0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyLineActivity.java
@@ -22,8 +22,8 @@
import com.android.compatibility.common.util.ReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
-import android.content.Context;
+import android.content.Context;
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
@@ -31,17 +31,13 @@
import android.media.AudioTrack;
import android.media.AudioRecord;
import android.media.MediaRecorder;
-
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.os.SystemClock;
-
import android.util.Log;
-
import android.view.View;
import android.view.View.OnClickListener;
-
import android.widget.Button;
import android.widget.TextView;
import android.widget.SeekBar;
@@ -391,9 +387,15 @@
Results resultsRight = new Results("Right");
computeResultsForVector(mFreqAverage1, resultsRight);
if (resultsLeft.testAll() && resultsRight.testAll()) {
- //enable button
- getPassButton().setEnabled(true);
+ String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+ appendResultsToScreen(strSuccess);
+ } else {
+ String strFailed = getResources().getString(R.string.audio_general_test_failed);
+ appendResultsToScreen(strFailed + "\n");
+ String strWarning = getResources().getString(R.string.audio_general_deficiency_found);
+ appendResultsToScreen(strWarning);
}
+ getPassButton().setEnabled(true); //Everybody passes! (for now...)
}
private void computeResultsForVector(VectorAverage freqAverage,Results results) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
index f9334b3..ba7b86d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencySpeakerActivity.java
@@ -416,8 +416,15 @@
computeResultsForVector(mFreqAverageRight, resultsRight, false, bandSpecsArray);
if (resultsLeft.testAll() && resultsRight.testAll() && resultsBase.testAll()) {
//enable button
- getPassButton().setEnabled(true);
+ String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+ appendResultsToScreen(strSuccess);
+ } else {
+ String strFailed = getResources().getString(R.string.audio_general_test_failed);
+ appendResultsToScreen(strFailed + "\n");
+ String strWarning = getResources().getString(R.string.audio_general_deficiency_found);
+ appendResultsToScreen(strWarning);
}
+ getPassButton().setEnabled(true); //Everybody passes! (for now...)
}
private void computeResultsForVector(VectorAverage freqAverage,Results results, boolean isBase,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java
index 75b04eb..98d1365 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/Correlation.java
@@ -30,6 +30,8 @@
public double mEstimatedLatencyMs = 0;
public double mEstimatedLatencyConfidence = 0.0;
+ private double mAmplitudeThreshold = 0.001; // 0.001 = -60 dB noise
+
public void init(int blockSize, int samplingRate) {
mBlockSize = blockSize;
mSamplingRate = samplingRate;
@@ -40,7 +42,7 @@
log("Started Auto Correlation for data with " + data.length + " points");
mSamplingRate = samplingRate;
- downsampleData(data, mDataDownsampled);
+ downsampleData(data, mDataDownsampled, mAmplitudeThreshold);
//correlation vector
autocorrelation(mDataDownsampled, mDataAutocorrelated);
@@ -95,7 +97,7 @@
return status;
}
- private boolean downsampleData(double [] data, double [] dataDownsampled) {
+ private boolean downsampleData(double [] data, double [] dataDownsampled, double threshold) {
boolean status = false;
// mDataDownsampled = new double[mBlockSize];
@@ -106,6 +108,8 @@
int N = data.length; //all samples available
double groupSize = (double) N / mBlockSize;
+ int ignored = 0;
+
int currentIndex = 0;
double nextGroup = groupSize;
for (int i = 0; i<N && currentIndex<mBlockSize; i++) {
@@ -118,9 +122,18 @@
if (currentIndex>=mBlockSize) {
break;
}
- dataDownsampled[currentIndex] += Math.abs(data[i]);
+
+ double value = Math.abs(data[i]);
+ if (value >= threshold) {
+ dataDownsampled[currentIndex] += value;
+ } else {
+ ignored++;
+ }
}
+ log(String.format(" Threshold: %.3f, ignored:%d/%d (%%.2f)", threshold, ignored, N,
+ (double) ignored/(double)N));
+
status = true;
return status;
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
index fcd88d1..aaea279 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/deskclock/DeskClockTestsActivity.java
@@ -165,13 +165,6 @@
}
}
- /**
- * Enable Pass Button when the all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
public static class DeskClockIntentFactory implements IntentFactory {
@Override
public Intent[] createIntents(String testId, int buttonText) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index 3c108da..1b8396d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -233,6 +233,7 @@
public static final Feature[] ALL_MNC_FEATURES = {
new Feature(PackageManager.FEATURE_MIDI, false),
new Feature(PackageManager.FEATURE_AUDIO_PRO, false),
+ new Feature(PackageManager.FEATURE_FINGERPRINT, false),
};
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
index 2a94ace..4b70b89 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ChargingConstraintTestActivity.java
@@ -9,17 +9,21 @@
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.BatteryManager;
import android.widget.Button;
import android.widget.ImageView;
+import android.widget.TextView;
+import android.view.View;
import com.android.cts.verifier.R;
+import com.android.cts.verifier.TimerProgressBar;
/**
* This activity runs the following tests:
- * - Ask the tester to unplug the phone, and verify that jobs with charging constraints will
- * not run.
* - Ask the tester to ensure the phone is plugged in, and verify that jobs with charging
* constraints are run.
+ * - Ask the tester to unplug the phone, and verify that jobs with charging constraints will
+ * not run.
*/
@TargetApi(21)
public class ChargingConstraintTestActivity extends ConstraintTestActivity {
@@ -29,6 +33,19 @@
private static final int OFF_CHARGING_JOB_ID =
ChargingConstraintTestActivity.class.hashCode() + 1;
+ // Time in milliseconds to wait after power is connected for the phone
+ // to get into charging mode.
+ private static final long WAIT_FOR_CHARGING_DURATION = 3 * 60 * 1000;
+
+ private static final int STATE_NOT_RUNNING = 0;
+ private static final int STATE_WAITING_TO_START_ON_CHARGING_TEST = 1;
+ private static final int STATE_ON_CHARGING_TEST_PASSED = 2;
+
+ private int mTestState;
+ TimerProgressBar mWaitingForChargingProgressBar;
+ TextView mWaitingForChargingTextView;
+ TextView mProblemWithChargerTextView;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -38,6 +55,20 @@
setPassFailButtonClickListeners();
setInfoResources(R.string.js_charging_test, R.string.js_charging_instructions, -1);
mStartButton = (Button) findViewById(R.id.js_charging_start_test_button);
+ mWaitingForChargingProgressBar = (TimerProgressBar) findViewById(
+ R.id.js_waiting_for_charging_progress_bar);
+ mWaitingForChargingTextView = (TextView) findViewById(
+ R.id.js_waiting_for_charging_text_view);
+ mProblemWithChargerTextView = (TextView) findViewById(
+ R.id.js_problem_with_charger_text_view);
+
+ if (isDevicePluggedIn()){
+ mStartButton.setEnabled(true);
+ }
+
+ hideWaitingForStableChargingViews();
+
+ mTestState = STATE_NOT_RUNNING;
mJobScheduler = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
@@ -45,6 +76,8 @@
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_POWER_CONNECTED);
intentFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
+ intentFilter.addAction(BatteryManager.ACTION_CHARGING);
+ intentFilter.addAction(BatteryManager.ACTION_DISCHARGING);
registerReceiver(mChargingChangedReceiver, intentFilter);
}
@@ -55,22 +88,47 @@
unregisterReceiver(mChargingChangedReceiver);
}
+ private boolean isDevicePluggedIn() {
+ IntentFilter ifilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ Intent batteryStatus = registerReceiver(null, ifilter);
+ int status = batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
+ // 0 indicates device is on battery power
+ return status != 0;
+ }
+
@Override
public void startTestImpl() {
- new TestDeviceUnpluggedConstraint().execute();
+ BatteryManager bm = (BatteryManager) getSystemService(BATTERY_SERVICE);
+ if (bm.isCharging()) {
+ new TestDevicePluggedInConstraint().execute();
+ } else if (isDevicePluggedIn()) {
+ mTestState = STATE_WAITING_TO_START_ON_CHARGING_TEST;
+ showWaitingForStableChargingViews();
+ }
}
private BroadcastReceiver mChargingChangedReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
- mDeviceUnpluggedTestPassed = false;
- mStartButton.setEnabled(true);
- } else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
- mStartButton.setEnabled(false);
- if (mDeviceUnpluggedTestPassed) {
- continueTest();
+ if (BatteryManager.ACTION_CHARGING.equals(intent.getAction())) {
+ if (mTestState == STATE_WAITING_TO_START_ON_CHARGING_TEST) {
+ mWaitingForChargingProgressBar.forceComplete();
+ hideWaitingForStableChargingViews();
+ new TestDevicePluggedInConstraint().execute();
}
+ } else if (BatteryManager.ACTION_DISCHARGING.equals(intent.getAction())) {
+ if (mTestState == STATE_ON_CHARGING_TEST_PASSED) {
+ new TestDeviceUnpluggedConstraint().execute();
+ }
+ } else if (Intent.ACTION_POWER_CONNECTED.equals(intent.getAction())) {
+ if (mTestState == STATE_WAITING_TO_START_ON_CHARGING_TEST) {
+ showWaitingForStableChargingViews();
+ } else if (mTestState == STATE_NOT_RUNNING) {
+ mStartButton.setEnabled(true);
+ }
+ mStartButton.setEnabled(true);
+ } else if (Intent.ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
+ hideWaitingForStableChargingViews();
}
}
};
@@ -79,15 +137,6 @@
private boolean mDeviceUnpluggedTestPassed = false;
/**
- * After the first test has passed, and preconditions are met, this will kick off the second
- * test.
- * See {@link #startTest(android.view.View)}.
- */
- private void continueTest() {
- new TestDevicePluggedInConstraint().execute();
- }
-
- /**
* Test blocks and can't be run on the main thread.
*/
private void testChargingConstraintFails_notCharging() {
@@ -99,17 +148,12 @@
.build();
mJobScheduler.schedule(runOnCharge);
- // Send intent to kick off any jobs. This will be a no-op as the device is not plugged in;
- // the JobScheduler tracks charging state independently.
- sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
-
boolean testPassed;
try {
testPassed = mTestEnvironment.awaitTimeout();
} catch (InterruptedException e) {
testPassed = false;
}
- mDeviceUnpluggedTestPassed = testPassed;
runOnUiThread(new ChargingConstraintTestResultRunner(OFF_CHARGING_JOB_ID, testPassed));
}
@@ -127,15 +171,14 @@
mTestEnvironment.setExpectedExecutions(1);
mJobScheduler.schedule(delayConstraintAndUnexpiredDeadline);
- // Force the JobScheduler to consider any jobs that have charging constraints.
- sendBroadcast(EXPEDITE_STABLE_CHARGING);
-
boolean testPassed;
try {
testPassed = mTestEnvironment.awaitExecution();
} catch (InterruptedException e) {
testPassed = false;
}
+
+ mTestState = testPassed ? STATE_ON_CHARGING_TEST_PASSED : STATE_NOT_RUNNING;
runOnUiThread(new ChargingConstraintTestResultRunner(ON_CHARGING_JOB_ID, testPassed));
}
@@ -144,11 +187,15 @@
@Override
protected Void doInBackground(Void... voids) {
testChargingConstraintFails_notCharging();
-
- // Do not call notifyTestCompleted here, as we're still waiting for the user to put
- // the device back on charge to continue with TestDevicePluggedInConstraint.
+ notifyTestCompleted();
return null;
}
+
+ @Override
+ protected void onPostExecute(Void res) {
+ mTestState = STATE_NOT_RUNNING;
+ mStartButton.setEnabled(true);
+ }
}
/** Run test for when the <bold>device is connected to power.</bold> */
@@ -156,8 +203,6 @@
@Override
protected Void doInBackground(Void... voids) {
testChargingConstraintExecutes_onCharging();
-
- notifyTestCompleted();
return null;
}
}
@@ -181,4 +226,25 @@
view.setImageResource(mTestPassed ? R.drawable.fs_good : R.drawable.fs_error);
}
}
+
+ private void showWaitingForStableChargingViews() {
+ mWaitingForChargingProgressBar.start(WAIT_FOR_CHARGING_DURATION, 1000,
+ new TimerProgressBar.TimerExpiredCallback(){
+ @Override
+ public void onTimerExpired() {
+ mProblemWithChargerTextView.setVisibility(View.VISIBLE);
+ }
+ }
+ );
+ mWaitingForChargingProgressBar.setVisibility(View.VISIBLE);
+ mWaitingForChargingTextView.setVisibility(View.VISIBLE);
+ mProblemWithChargerTextView.setVisibility(View.GONE);
+ }
+
+ private void hideWaitingForStableChargingViews() {
+ mWaitingForChargingProgressBar.forceComplete();
+ mWaitingForChargingProgressBar.setVisibility(View.GONE);
+ mWaitingForChargingTextView.setVisibility(View.GONE);
+ mProblemWithChargerTextView.setVisibility(View.GONE);
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
index 8d10bda..aaf68e6 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConnectivityConstraintTestActivity.java
@@ -106,11 +106,6 @@
mJobScheduler.schedule(testJob1);
mJobScheduler.schedule(testJob2);
- /*
- // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
- sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
- */
-
boolean testPassed;
try {
testPassed = mTestEnvironment.awaitExecution();
@@ -132,9 +127,6 @@
mJobScheduler.schedule(testJob);
- // Send intent to kick off ready jobs that the JobScheduler might be lazily holding on to.
- sendBroadcastAndBlockForResult(EXPEDITE_STABLE_CHARGING);
-
boolean testPassed;
try {
testPassed = mTestEnvironment.awaitTimeout();
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
index da0862a..0d8d13f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/ConstraintTestActivity.java
@@ -18,13 +18,7 @@
@TargetApi(21)
public abstract class ConstraintTestActivity extends PassFailButtons.Activity {
- /**
- * Intent we use to force the job scheduler to consider any ready jobs that otherwise it may
- * have decided to be lazy about.
- */
- protected static final Intent EXPEDITE_STABLE_CHARGING =
- new Intent("com.android.server.task.controllers.BatteryController.ACTION_CHARGING_STABLE");
-
+
protected ComponentName mMockComponent;
protected MockJobService.TestEnvironment mTestEnvironment;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
index a8bd993..05c1a2e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/jobscheduler/IdleConstraintTestActivity.java
@@ -26,15 +26,17 @@
import android.content.IntentFilter;
import android.os.AsyncTask;
import android.os.Bundle;
+import android.os.PowerManager;
import android.util.Log;
+import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
+import android.widget.TextView;
/**
* Idle constraints:
- * The framework doesn't support turning idle mode off. Use the manual tester to ensure that
- * the device is not in idle mode (by turning the screen off and then back on) before running
- * the tests.
+ * The framework doesn't support turning the screen off. Use the manual tester to
+ * turn off the screen to run to run tests that require idle mode to be on.
*/
@TargetApi(21)
public class IdleConstraintTestActivity extends ConstraintTestActivity {
@@ -57,22 +59,35 @@
*/
private static final int IDLE_ON_JOB_ID = IdleConstraintTestActivity.class.hashCode() + 1;
+ private static final int IDLE_ON_TEST_STATE_NOT_IN_PROGRESS = 0;
+ private static final int IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF = 1;
+
/**
- * Listens for idle mode off/on events, namely {@link #ACTION_EXPEDITE_IDLE_MODE} and
- * {@link Intent#ACTION_SCREEN_ON}.
- * On ACTION_EXPEDITE_IDLE_MODE, we will disable the {@link #mStartButton}, and on
- * ACTION_SCREEN_ON we enable it. This is to avoid the start button being clicked when the
- * device is in idle mode.
+ * mTestState stores the state of the tests. It is used to ensure that we only run
+ * the 'idle on' test if screen is turned off after the user has started tests.
*/
- private BroadcastReceiver mIdleChangedReceiver = new BroadcastReceiver() {
+ private int mTestState = IDLE_ON_TEST_STATE_NOT_IN_PROGRESS;
+
+ private PowerManager mPowerManager;
+ private TextView mContinueInstructionTextView;
+
+ /**
+ * Listens for screen off event. Starts an async task to force device into
+ * idle mode and run the 'idle on' test.
+ */
+ private BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (Intent.ACTION_SCREEN_ON.equals(intent.getAction())) {
- mStartButton.setEnabled(true);
- } else if (ACTION_EXPEDITE_IDLE_MODE.equals(intent.getAction())) {
- mStartButton.setEnabled(false);
+ if (Intent.ACTION_SCREEN_OFF.equals(intent.getAction())) {
+ if (mTestState == IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF) {
+ mContinueInstructionTextView.setVisibility(View.GONE);
+ PowerManager.WakeLock wl = mPowerManager.newWakeLock(
+ PowerManager.PARTIAL_WAKE_LOCK, TAG);
+ wl.acquire();
+ new TestIdleModeTaskIdle().execute(wl);
+ }
} else {
- Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_ON");
+ Log.e(TAG, "Invalid broadcast received, was expecting SCREEN_OFF");
}
}
};
@@ -86,47 +101,88 @@
setPassFailButtonClickListeners();
setInfoResources(R.string.js_idle_test, R.string.js_idle_instructions, -1);
mStartButton = (Button) findViewById(R.id.js_idle_start_test_button);
+ mContinueInstructionTextView = (TextView) findViewById(
+ R.id.js_idle_continue_instruction_view);
- // Register receiver for idle off/on events.
+ // Register receiver for screen off event.
IntentFilter intentFilter = new IntentFilter();
- intentFilter.addAction(Intent.ACTION_SCREEN_ON);
- intentFilter.addAction(ACTION_EXPEDITE_IDLE_MODE);
+ intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
- registerReceiver(mIdleChangedReceiver, intentFilter);
+ mPowerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
+
+ registerReceiver(mScreenOffReceiver, intentFilter);
+
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ // Enable start button only if tests are not in progress.
+ if (mTestState == IDLE_ON_TEST_STATE_NOT_IN_PROGRESS) {
+ mStartButton.setEnabled(true);
+ mContinueInstructionTextView.setVisibility(View.GONE);
+ }
}
@Override
protected void onDestroy() {
super.onDestroy();
- unregisterReceiver(mIdleChangedReceiver);
+ unregisterReceiver(mScreenOffReceiver);
}
@Override
protected void startTestImpl() {
- new TestIdleModeTask().execute();
+ mStartButton.setEnabled(false);
+ new TestIdleModeTaskNotIdle().execute();
}
- /** Background task that will run the actual test. */
- private class TestIdleModeTask extends AsyncTask<Void, Void, Void> {
-
+ /** Background task that will run the 'not idle' test. */
+ private class TestIdleModeTaskNotIdle extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... voids) {
testIdleConstraintFails_notIdle();
+ return null;
+ }
+ @Override
+ protected void onPostExecute(Void result) {
+ mTestState = IDLE_ON_TEST_STATE_WAITING_FOR_SCREEN_OFF;
+ mContinueInstructionTextView.setVisibility(View.VISIBLE);
+ }
+ }
- // Send the {@link #ACTION_EXPEDITE_IDLE_MODE} broadcast as an ordered broadcast, this
- // function will block until all receivers have processed the broadcast.
+ /** Background task that will run the 'idle' test. */
+ private class TestIdleModeTaskIdle extends AsyncTask<PowerManager.WakeLock, Void, Void> {
+
+ private PowerManager.WakeLock mPartialWakeLock;
+
+ @Override
+ protected Void doInBackground(PowerManager.WakeLock... wakeLocks) {
+ mPartialWakeLock = wakeLocks[0];
+
if (!sendBroadcastAndBlockForResult(new Intent(ACTION_EXPEDITE_IDLE_MODE))) {
- // Fail the test if the broadcast wasn't processed.
runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, false));
+ } else {
+ testIdleConstraintExecutes_onIdle();
}
-
- testIdleConstraintExecutes_onIdle();
-
notifyTestCompleted();
return null;
}
+ @Override
+ protected void onPostExecute(Void result) {
+ // Reset test state
+ mTestState = IDLE_ON_TEST_STATE_NOT_IN_PROGRESS;
+
+ PowerManager.WakeLock fullWakeLock = mPowerManager.newWakeLock(
+ PowerManager.FULL_WAKE_LOCK
+ | PowerManager.ACQUIRE_CAUSES_WAKEUP
+ | PowerManager.ON_AFTER_RELEASE, TAG);
+ // Turn on screen and release both locks
+ fullWakeLock.acquire();
+ fullWakeLock.release();
+ mPartialWakeLock.release();
+ }
}
/**
@@ -154,6 +210,10 @@
runOnUiThread(new IdleTestResultRunner(IDLE_OFF_JOB_ID, testPassed));
}
+ /**
+ * Called after screen is switched off and device is forced into idle mode.
+ * Schedule a job with an idle constraint and verify that it executes.
+ */
private void testIdleConstraintExecutes_onIdle() {
mTestEnvironment.setUp();
mJobScheduler.cancelAll();
@@ -172,6 +232,7 @@
// We'll just indicate that it failed, not why.
testPassed = false;
}
+
runOnUiThread(new IdleTestResultRunner(IDLE_ON_JOB_ID, testPassed));
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index b129665..9e3b2aa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -82,6 +82,9 @@
private TestListItem mKeyguardDisabledFeaturesTest;
private DialogTestListItem mDisableNfcBeamTest;
private TestListItem mAuthenticationBoundKeyTest;
+ private DialogTestListItem mEnableLocationModeTest;
+ private DialogTestListItem mDisableLocationModeTest;
+ private TestListItem mVpnTest;
public ByodFlowTestActivity() {
super(R.layout.provisioning_byod,
@@ -94,7 +97,7 @@
super.onCreate(savedInstanceState);
mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
- disableComponent();
+ enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
mPrepareTestButton.setText(R.string.provisioning_byod_start);
mPrepareTestButton.setOnClickListener(new OnClickListener() {
@Override
@@ -157,6 +160,7 @@
// Pass and fail buttons are known to call finish() when clicked, and this is when we want to
// clean up the provisioned profile.
requestDeleteProfileOwner();
+ enableComponent(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
super.finish();
}
@@ -186,7 +190,7 @@
R.string.provisioning_byod_work_notification,
"BYOD_WorkNotificationBadgedTest",
R.string.provisioning_byod_work_notification_instruction,
- new Intent(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION),
+ new Intent(ByodHelperActivity.ACTION_NOTIFICATION),
R.drawable.ic_corp_icon);
Intent workStatusIcon = new Intent(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
@@ -301,6 +305,12 @@
new Intent(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST),
null);
+ mVpnTest = TestListItem.newTest(this,
+ R.string.provisioning_byod_vpn,
+ VpnTestActivity.class.getName(),
+ new Intent(VpnTestActivity.ACTION_VPN),
+ null);
+
// Test for checking if the required intent filters are set during managed provisioning.
mIntentFiltersTest = new DialogTestListItem(this,
R.string.provisioning_byod_cross_profile_intent_filters,
@@ -346,7 +356,11 @@
adapter.add(mPermissionLockdownTest);
adapter.add(mKeyguardDisabledFeaturesTest);
adapter.add(mAuthenticationBoundKeyTest);
+ adapter.add(mVpnTest);
+ /* If there is an application that handles ACTION_IMAGE_CAPTURE, test that it handles it
+ * well.
+ */
if (canResolveIntent(ByodHelperActivity.getCaptureImageIntent())) {
// Capture image intent can be resolved in primary profile, so test.
mCrossProfileImageCaptureSupportTest = new DialogTestListItem(this,
@@ -362,6 +376,9 @@
.show();
}
+ /* If there is an application that handles ACTION_VIDEO_CAPTURE, test that it handles it
+ * well.
+ */
if (canResolveIntent(ByodHelperActivity.getCaptureVideoIntent())) {
// Capture video intent can be resolved in primary profile, so test.
mCrossProfileVideoCaptureSupportTest = new DialogTestListItem(this,
@@ -409,7 +426,9 @@
adapter.add(mDisableNfcBeamTest);
}
- /* TODO: reinstate when bug b/20131958 is fixed
+ /* If there is an application that handles RECORD_SOUND_ACTION, test that it handles it
+ * well.
+ */
if (canResolveIntent(ByodHelperActivity.getCaptureAudioIntent())) {
// Capture audio intent can be resolved in primary profile, so test.
mCrossProfileAudioCaptureSupportTest = new DialogTestListItem(this,
@@ -424,7 +443,27 @@
R.string.provisioning_byod_no_audio_capture_resolver, Toast.LENGTH_SHORT)
.show();
}
- */
+
+ if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION_GPS)) {
+ mEnableLocationModeTest = new DialogTestListItem(this,
+ R.string.provisioning_byod_location_mode_enable,
+ "BYOD_LocationModeEnableTest",
+ R.string.provisioning_byod_location_mode_enable_instruction,
+ new Intent(ByodHelperActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES));
+ mDisableLocationModeTest = new DialogTestListItem(this,
+ R.string.provisioning_byod_location_mode_disable,
+ "BYOD_LocationModeDisableTest",
+ R.string.provisioning_byod_location_mode_disable_instruction,
+ new Intent(ByodHelperActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES));
+
+ adapter.add(mEnableLocationModeTest);
+ adapter.add(mDisableLocationModeTest);
+ } else {
+ // The system does not support GPS feature, so skip test.
+ Toast.makeText(ByodFlowTestActivity.this,
+ R.string.provisioning_byod_no_gps_location_feature, Toast.LENGTH_SHORT)
+ .show();
+ }
}
// Return whether the intent can be resolved in the current profile
@@ -435,11 +474,11 @@
@Override
protected void clearRemainingState(final DialogTestListItem test) {
super.clearRemainingState(test);
- if (WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION.equals(
+ if (ByodHelperActivity.ACTION_NOTIFICATION.equals(
test.getManualTestIntent().getAction())) {
try {
startActivity(new Intent(
- WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION));
+ ByodHelperActivity.ACTION_CLEAR_NOTIFICATION));
} catch (ActivityNotFoundException e) {
// User shouldn't run this test before work profile is set up.
}
@@ -487,11 +526,15 @@
private void checkIntentFilters() {
try {
+ // Enable component HandleIntentActivity before intent filters are checked.
+ setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
// We disable the ByodHelperActivity in the primary profile. So, this intent
// will be handled by the ByodHelperActivity in the managed profile.
Intent intent = new Intent(ByodHelperActivity.ACTION_CHECK_INTENT_FILTERS);
startActivityForResult(intent, REQUEST_INTENT_FILTERS_STATUS);
} catch (ActivityNotFoundException e) {
+ // Disable component HandleIntentActivity if intent filters check fails.
+ setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
Log.d(TAG, "checkIntentFilters: ActivityNotFoundException", e);
setTestResult(mIntentFiltersTest, TestResult.TEST_RESULT_FAILED);
showToast(R.string.provisioning_byod_no_activity);
@@ -499,6 +542,8 @@
}
private void handleIntentFiltersStatus(int resultCode) {
+ // Disable component HandleIntentActivity after intent filters are checked.
+ setHandleIntentActivityEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
// we use the resultCode from ByodHelperActivity in the managed profile to know if certain
// intents fired from the managed profile are forwarded.
final boolean intentFiltersSetForManagedIntents = (resultCode == RESULT_OK);
@@ -514,21 +559,30 @@
intentFiltersSet ? TestResult.TEST_RESULT_PASSED : TestResult.TEST_RESULT_FAILED);
}
- private void disableComponent() {
- // Disable app components in the current profile, so only the counterpart in the other profile
- // can respond (via cross-profile intent filter)
+ /**
+ * Disable or enable app components in the current profile. When they are disabled only the
+ * counterpart in the other profile can respond (via cross-profile intent filter).
+ * @param enabledState {@link PackageManager#COMPONENT_ENABLED_STATE_DISABLED} or
+ * {@link PackageManager#COMPONENT_ENABLED_STATE_DEFAULT}
+ */
+ private void enableComponent(final int enabledState) {
final String[] components = {
ByodHelperActivity.class.getName(),
- WorkNotificationTestActivity.class.getName(),
WorkStatusTestActivity.class.getName(),
PermissionLockdownTestActivity.ACTIVITY_ALIAS,
- AuthenticationBoundKeyTestActivity.class.getName()
+ AuthenticationBoundKeyTestActivity.class.getName(),
+ VpnTestActivity.class.getName()
};
for (String component : components) {
getPackageManager().setComponentEnabledSetting(new ComponentName(this, component),
- PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
- PackageManager.DONT_KILL_APP);
+ enabledState, PackageManager.DONT_KILL_APP);
}
}
+ private void setHandleIntentActivityEnabledSetting(final int enableState) {
+ getPackageManager().setComponentEnabledSetting(
+ new ComponentName(ByodFlowTestActivity.this, HandleIntentActivity.class.getName()),
+ enableState, PackageManager.DONT_KILL_APP);
+ }
+
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
index 9ea5061..ef7c952 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodHelperActivity.java
@@ -19,14 +19,21 @@
import android.app.Activity;
import android.app.admin.DevicePolicyManager;
import android.app.Dialog;
+import android.app.Notification;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.location.Location;
+import android.location.LocationListener;
+import android.location.LocationManager;
import android.net.Uri;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
import android.os.UserManager;
import android.provider.MediaStore;
import android.provider.Settings;
@@ -51,7 +58,7 @@
*
* Note: We have to use a dummy activity because cross-profile intents only work for activities.
*/
-public class ByodHelperActivity extends Activity implements DialogCallback {
+public class ByodHelperActivity extends Activity implements DialogCallback, Handler.Callback {
static final String TAG = "ByodHelperActivity";
// Primary -> managed intent: query if the profile owner has been set up.
@@ -97,24 +104,57 @@
public static final String ACTION_TEST_APP_LINKING_DIALOG =
"com.android.cts.verifier.managedprovisioning.action.TEST_APP_LINKING_DIALOG";
+ // Primary -> managed intent: request to goto the location settings page and listen to updates.
+ public static final String ACTION_SET_LOCATION_AND_CHECK_UPDATES =
+ "com.android.cts.verifier.managedprovisioning.BYOD_SET_LOCATION_AND_CHECK";
+ public static final String ACTION_NOTIFICATION =
+ "com.android.cts.verifier.managedprovisioning.NOTIFICATION";
+ public static final String ACTION_NOTIFICATION_ON_LOCKSCREEN =
+ "com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION";
+ public static final String ACTION_CLEAR_NOTIFICATION =
+ "com.android.cts.verifier.managedprovisioning.CLEAR_NOTIFICATION";
+
public static final int RESULT_FAILED = RESULT_FIRST_USER;
private static final int REQUEST_INSTALL_PACKAGE = 1;
private static final int REQUEST_IMAGE_CAPTURE = 2;
private static final int REQUEST_VIDEO_CAPTURE = 3;
private static final int REQUEST_AUDIO_CAPTURE = 4;
+ private static final int REQUEST_LOCATION_UPDATE = 5;
private static final String ORIGINAL_SETTINGS_NAME = "original settings";
+
+ private static final int NOTIFICATION_ID = 7;
+
+ private NotificationManager mNotificationManager;
private Bundle mOriginalSettings;
+ private static final int MSG_TIMEOUT = 1;
+
+ private static final long MSG_TIMEOUT_MILLISEC = 15 * 1000;
+
private ComponentName mAdminReceiverComponent;
private DevicePolicyManager mDevicePolicyManager;
+ private LocationManager mLocationManager;
+ private Handler mHandler;
+ private boolean mIsLocationUpdated;
private Uri mImageUri;
private Uri mVideoUri;
private ArrayList<File> mTempFiles = new ArrayList<File>();
+ private void showNotification(int visibility) {
+ final Notification notification = new Notification.Builder(this)
+ .setSmallIcon(R.drawable.icon)
+ .setContentTitle(getString(R.string.provisioning_byod_notification_title))
+ .setVisibility(visibility)
+ .setAutoCancel(true)
+ .build();
+ mNotificationManager.notify(NOTIFICATION_ID, notification);
+ }
+
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -128,6 +168,10 @@
mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
mDevicePolicyManager = (DevicePolicyManager) getSystemService(
Context.DEVICE_POLICY_SERVICE);
+ mLocationManager = (LocationManager) getSystemService(LOCATION_SERVICE);
+ mHandler = new Handler(this);
+ mIsLocationUpdated = false;
+ mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
Intent intent = getIntent();
String action = intent.getAction();
Log.d(TAG, "ByodHelperActivity.onCreate: " + action);
@@ -146,6 +190,8 @@
// Request to delete work profile.
} else if (action.equals(ACTION_REMOVE_PROFILE_OWNER)) {
if (isProfileOwner()) {
+ Log.d(TAG, "Clearing cross profile intents");
+ mDevicePolicyManager.clearCrossProfileIntentFilters(mAdminReceiverComponent);
mDevicePolicyManager.wipeData(0);
showToast(R.string.provisioning_byod_profile_deleted);
}
@@ -234,6 +280,31 @@
Intent toSend = new Intent(Intent.ACTION_VIEW);
toSend.setData(Uri.parse("http://com.android.cts.verifier"));
sendIntentInsideChooser(toSend);
+ } else if (action.equals(ACTION_SET_LOCATION_AND_CHECK_UPDATES)) {
+ // Grant the locaiton permission to the provile owner on cts-verifier.
+ // The permission state does not have to be reverted at the end since the profile onwer
+ // is going to be deleted when BYOD tests ends.
+ grantLocationPermissionToSelf();
+ Intent locationSettingsIntent = getLocationSettingsIntent();
+ if (locationSettingsIntent.resolveActivity(getPackageManager()) != null) {
+ startActivityForResult(locationSettingsIntent, REQUEST_LOCATION_UPDATE);
+ scheduleTimeout();
+ } else {
+ Log.e(TAG, "BYOD settings could not be resolved in managed profile");
+ finish();
+ }
+ mLocationManager.requestLocationUpdates(
+ LocationManager.GPS_PROVIDER, 0, 0, mLocationListener);
+ return;
+ } else if (action.equals(ACTION_NOTIFICATION)) {
+ showNotification(Notification.VISIBILITY_PUBLIC);
+ } else if (ACTION_NOTIFICATION_ON_LOCKSCREEN.equals(action)) {
+ DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ dpm.lockNow();
+ showNotification(Notification.VISIBILITY_PRIVATE);
+ } else if (ACTION_CLEAR_NOTIFICATION.equals(action)) {
+ mNotificationManager.cancel(NOTIFICATION_ID);
}
// This activity has no UI and is only used to respond to CtsVerifier in the primary side.
finish();
@@ -289,6 +360,13 @@
}
break;
}
+ case REQUEST_LOCATION_UPDATE: {
+ Log.d(TAG, "BYOD exit location settings:OK");
+ mLocationManager.removeUpdates(mLocationListener);
+ mHandler.removeMessages(MSG_TIMEOUT);
+ finish();
+ break;
+ }
default: {
Log.wtf(TAG, "Unknown requestCode " + requestCode + "; data = " + data);
break;
@@ -314,6 +392,10 @@
return new Intent(MediaStore.Audio.Media.RECORD_SOUND_ACTION);
}
+ public static Intent getLocationSettingsIntent() {
+ return new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
+ }
+
public static Intent createLockIntent() {
return new Intent(ACTION_LOCKNOW);
}
@@ -376,8 +458,49 @@
startActivity(chooser);
}
+ private void grantLocationPermissionToSelf() {
+ mDevicePolicyManager.setPermissionGrantState(mAdminReceiverComponent, getPackageName(),
+ android.Manifest.permission.ACCESS_FINE_LOCATION,
+ DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED);
+ }
+
+ private final LocationListener mLocationListener = new LocationListener() {
+ @Override
+ public void onLocationChanged(Location location) {
+ if (mIsLocationUpdated) return;
+ showToast(R.string.provisioning_byod_location_mode_enable_toast_location_change);
+ mIsLocationUpdated = true;
+ }
+
+ @Override
+ public void onProviderDisabled(String provider) {
+ }
+
+ @Override
+ public void onProviderEnabled(String provider) {
+ }
+
+ @Override
+ public void onStatusChanged(String provider, int status, Bundle extras) {
+ }
+ };
+
+ private void scheduleTimeout() {
+ mHandler.removeMessages(MSG_TIMEOUT);
+ mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_TIMEOUT), MSG_TIMEOUT_MILLISEC);
+ }
+
@Override
public void onDialogClose() {
finish();
}
+
+ @Override
+ public boolean handleMessage(Message msg) {
+ if (msg.what == MSG_TIMEOUT) {
+ if (mIsLocationUpdated) return true;
+ showToast(R.string.provisioning_byod_location_mode_time_out_toast);
+ }
+ return true;
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
index ed6b5eb..039cc09 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceAdminTestReceiver.java
@@ -22,6 +22,7 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.provider.Settings;
import android.util.Log;
/**
@@ -66,15 +67,17 @@
filter.addAction(ByodHelperActivity.ACTION_TEST_NFC_BEAM);
filter.addAction(ByodHelperActivity.ACTION_TEST_CROSS_PROFILE_INTENTS_DIALOG);
filter.addAction(ByodHelperActivity.ACTION_TEST_APP_LINKING_DIALOG);
+ filter.addAction(ByodHelperActivity.ACTION_NOTIFICATION);
+ filter.addAction(ByodHelperActivity.ACTION_NOTIFICATION_ON_LOCKSCREEN);
+ filter.addAction(ByodHelperActivity.ACTION_CLEAR_NOTIFICATION);
filter.addAction(CrossProfileTestActivity.ACTION_CROSS_PROFILE_TO_WORK);
- filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION);
- filter.addAction(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN);
- filter.addAction(WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION);
filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_TOAST);
filter.addAction(WorkStatusTestActivity.ACTION_WORK_STATUS_ICON);
filter.addAction(
PermissionLockdownTestActivity.ACTION_MANAGED_PROFILE_CHECK_PERMISSION_LOCKDOWN);
filter.addAction(AuthenticationBoundKeyTestActivity.ACTION_AUTH_BOUND_KEY_TEST);
+ filter.addAction(ByodHelperActivity.ACTION_SET_LOCATION_AND_CHECK_UPDATES);
+ filter.addAction(VpnTestActivity.ACTION_VPN);
dpm.addCrossProfileIntentFilter(getWho(context), filter,
DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
index c7e785c..5dac13b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerNegativeTestActivity.java
@@ -16,6 +16,7 @@
package com.android.cts.verifier.managedprovisioning;
+import android.app.admin.DevicePolicyManager;
import android.content.Intent;
import android.database.DataSetObserver;
import android.os.Bundle;
@@ -33,10 +34,8 @@
*/
public class DeviceOwnerNegativeTestActivity extends PassFailButtons.TestListActivity {
- private static final String ACTION_PROVISION_MANAGED_DEVICE
- = "com.android.managedprovisioning.ACTION_PROVISION_MANAGED_DEVICE";
private static final Intent PROVISION_DEVICE_INTENT =
- new Intent(ACTION_PROVISION_MANAGED_DEVICE);
+ new Intent(DevicePolicyManager.ACTION_PROVISION_MANAGED_DEVICE);
private static final String DEVICE_OWNER_NEGATIVE_TEST = "DEVICE_OWNER_PROVISIONING_NEGATIVE";
private static final TestInfo DEVICE_OWNER_NEGATIVE_TEST_INFO = new TestInfo(
@@ -81,12 +80,5 @@
setTestListAdapter(adapter);
}
-
- /**
- * Enable Pass Button when the all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index a6a5e5a..72361c1 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -75,6 +75,9 @@
PermissionLockdownTestActivity.class.getName();
private static final String DISALLOW_CONFIG_BT_ID = "DISALLOW_CONFIG_BT";
private static final String DISALLOW_CONFIG_WIFI_ID = "DISALLOW_CONFIG_WIFI";
+ private static final String DISALLOW_CONFIG_VPN_ID = "DISALLOW_CONFIG_VPN";
+ //TODO(rgl): This symbol should be available in android.provider.settings
+ private static final String ACTION_VPN_SETTINGS = "android.net.vpn.SETTINGS";
private static final String REMOVE_DEVICE_OWNER_TEST_ID = "REMOVE_DEVICE_OWNER";
@Override
@@ -123,13 +126,6 @@
super.finish();
}
- /**
- * Enable Pass Button when all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
adapter.add(createTestItem(this, CHECK_DEVICE_OWNER_TEST_ID,
R.string.device_owner_check_device_owner_test,
@@ -166,6 +162,22 @@
new Intent(Settings.ACTION_WIFI_SETTINGS))}));
}
+ // DISALLOW_CONFIG_VPN
+ adapter.add(createInteractiveTestItem(this, DISALLOW_CONFIG_VPN_ID,
+ R.string.device_owner_disallow_config_vpn,
+ R.string.device_owner_disallow_config_vpn_info,
+ new ButtonInfo[] {
+ new ButtonInfo(
+ R.string.device_owner_user_vpn_restriction_set,
+ createSetUserRestrictionIntent(
+ UserManager.DISALLOW_CONFIG_VPN)),
+ new ButtonInfo(
+ R.string.device_owner_settings_go,
+ new Intent(ACTION_VPN_SETTINGS)),
+ new ButtonInfo(
+ R.string.device_owner_vpn_test,
+ new Intent(this, VpnTestActivity.class))}));
+
// DISALLOW_CONFIG_BLUETOOTH
if (packageManager.hasSystemFeature(PackageManager.FEATURE_BLUETOOTH)) {
adapter.add(createInteractiveTestItem(this, DISALLOW_CONFIG_BT_ID,
@@ -326,6 +338,7 @@
dpm.setKeyguardDisabled(admin, false);
dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_BLUETOOTH);
dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_WIFI);
+ dpm.clearUserRestriction(admin, UserManager.DISALLOW_CONFIG_VPN);
dpm.clearDeviceOwnerApp(getPackageName());
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/HandleIntentActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/HandleIntentActivity.java
new file mode 100644
index 0000000..88cf105
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/HandleIntentActivity.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.Activity;
+
+public class HandleIntentActivity extends Activity { }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
index eef6299..58a1fef 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/IntentFiltersTestHelper.java
@@ -84,9 +84,7 @@
new Intent("android.settings.USER_SETTINGS"),
new Intent("android.settings.ZEN_MODE_SETTINGS"),
new Intent("com.android.settings.ACCESSIBILITY_COLOR_SPACE_SETTINGS"),
- new Intent("com.android.settings.STORAGE_USB_SETTINGS"),
new Intent("com.android.settings.TTS_SETTINGS"),
- new Intent("com.android.settings.USER_DICTIONARY_EDIT"),
new Intent(Settings.ACTION_INTERNAL_STORAGE_SETTINGS),
new Intent(Settings.ACTION_SYNC_SETTINGS),
new Intent(Settings.ACTION_ADD_ACCOUNT),
@@ -150,7 +148,6 @@
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
forwardedIntentsFromManaged.addAll(Arrays.asList(
new Intent(Intent.ACTION_DIAL).setData(Uri.parse("tel:123")),
- new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")),
new Intent("android.intent.action.CALL_EMERGENCY").setData(
Uri.parse("tel:123")),
new Intent("android.intent.action.CALL_PRIVILEGED").setData(
@@ -176,6 +173,8 @@
Uri.parse("mmsto:07700900100?body=Hello%20world")).addCategory(
Intent.CATEGORY_BROWSABLE),
new Intent(Settings.ACTION_APN_SETTINGS)));
+ notForwardedIntentsFromManaged
+ .add(new Intent(Intent.ACTION_CALL).setData(Uri.parse("tel:123")));
}
if (pm.hasSystemFeature(PackageManager.FEATURE_NFC)) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
index 1a158f8..1b4edcf 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
@@ -34,7 +34,7 @@
public class KeyguardDisabledFeaturesActivity extends DialogTestListActivity {
- private DevicePolicyManager mDpm;
+ protected DevicePolicyManager mDpm;
public KeyguardDisabledFeaturesActivity() {
super(R.layout.provisioning_byod,
@@ -43,6 +43,12 @@
R.string.provisioning_byod_keyguard_disabled_features_instruction);
}
+ protected int getKeyguardDisabledFeatures() {
+ return DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS
+ | DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT
+ | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
+ }
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -54,25 +60,31 @@
mPrepareTestButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
- if (!mDpm.isAdminActive(DeviceAdminTestReceiver.getReceiverComponentName())) {
+ if (!mDpm.isAdminActive(getAdminComponent())) {
Toast.makeText(KeyguardDisabledFeaturesActivity.this,
R.string.provisioning_byod_keyguard_disabled_features_not_admin,
Toast.LENGTH_SHORT).show();
return;
}
+ setKeyguardDisabledFeatures();
mDpm.resetPassword("testpassword", 0);
- setKeyguardDisabledFeatures(DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS |
- DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT |
- DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
}
});
}
+
+ protected ComponentName getAdminComponent() {
+ return DeviceAdminTestReceiver.getReceiverComponentName();
+ }
+
+ protected String getTestIdPrefix() {
+ return "BYOD_";
+ }
@Override
public void finish() {
// Pass and fail buttons are known to call finish() when clicked, and this is when we want to
// clear the password.
- final ComponentName adminComponent = DeviceAdminTestReceiver.getReceiverComponentName();
+ final ComponentName adminComponent = getAdminComponent();
if (mDpm.isAdminActive(adminComponent)) {
mDpm.resetPassword(null, 0);
mDpm.removeActiveAdmin(adminComponent);
@@ -80,47 +92,61 @@
super.finish();
}
- private void setKeyguardDisabledFeatures(final int flags) {
- Intent setKeyguardDisabledFeaturesIntent =
- new Intent(ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES)
- .putExtra(ByodHelperActivity.EXTRA_PARAMETER_1, flags);
+ protected void setKeyguardDisabledFeatures() {
+ int flags = getKeyguardDisabledFeatures();
+ Intent setKeyguardDisabledFeaturesIntent = new Intent(
+ ByodHelperActivity.ACTION_KEYGUARD_DISABLED_FEATURES)
+ .putExtra(ByodHelperActivity.EXTRA_PARAMETER_1, flags);
startActivity(setKeyguardDisabledFeaturesIntent);
}
-
- @Override
- protected void setupTests(ArrayTestListAdapter adapter) {
+
+ protected void setupDisableTrustAgentsTest(ArrayTestListAdapter adapter) {
adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_trust_agents,
- "BYOD_DisableTrustAgentsTest",
+ getTestIdPrefix() + "DisableTrustAgentsTest",
R.string.provisioning_byod_disable_trust_agents_instruction,
new Intent(Settings.ACTION_SECURITY_SETTINGS)));
+ }
+
+ protected void setupDisableUnredactedWorkNotification(ArrayTestListAdapter adapter) {
adapter.add(new DialogTestListItemWithIcon(this,
- R.string.provisioning_byod_disable_notifications,
- "BYOD_DisableUnredactedNotifications",
- R.string.provisioning_byod_disable_notifications_instruction,
- new Intent(WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN),
+ R.string.provisioning_byod_disable_unredacted_notifications,
+ getTestIdPrefix() + "DisableUnredactedNotifications",
+ R.string.provisioning_byod_disable_unredacted_notifications_instruction,
+ new Intent(ByodHelperActivity.ACTION_NOTIFICATION_ON_LOCKSCREEN),
R.drawable.ic_corp_icon));
+ }
+
+ protected void setupFingerprintTests(ArrayTestListAdapter adapter) {
FingerprintManager fpm = (FingerprintManager) getSystemService(Context.FINGERPRINT_SERVICE);
if (fpm.isHardwareDetected()) {
adapter.add(new DialogTestListItem(this,
R.string.provisioning_byod_fingerprint_disabled_in_settings,
- "BYOD_FingerprintDisabledInSettings",
+ getTestIdPrefix() + "FingerprintDisabledInSettings",
R.string.provisioning_byod_fingerprint_disabled_in_settings_instruction,
new Intent(Settings.ACTION_SECURITY_SETTINGS)));
adapter.add(new DialogTestListItem(this, R.string.provisioning_byod_disable_fingerprint,
- "BYOD_DisableFingerprint",
+ getTestIdPrefix() + "DisableFingerprint",
R.string.provisioning_byod_disable_fingerprint_instruction,
ByodHelperActivity.createLockIntent()));
}
}
@Override
+ protected void setupTests(ArrayTestListAdapter adapter) {
+ setupDisableTrustAgentsTest(adapter);
+ setupDisableUnredactedWorkNotification(adapter);
+ setupFingerprintTests(adapter);
+
+ }
+
+ @Override
protected void clearRemainingState(final DialogTestListItem test) {
super.clearRemainingState(test);
- if (WorkNotificationTestActivity.ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(
+ if (ByodHelperActivity.ACTION_NOTIFICATION_ON_LOCKSCREEN.equals(
test.getManualTestIntent().getAction())) {
try {
startActivity(new Intent(
- WorkNotificationTestActivity.ACTION_CLEAR_WORK_NOTIFICATION));
+ ByodHelperActivity.ACTION_CLEAR_NOTIFICATION));
} catch (ActivityNotFoundException e) {
// User shouldn't run this test before work profile is set up.
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
new file mode 100644
index 0000000..49c0c20
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.managedprovisioning;
+
+import android.app.AlertDialog;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.VpnService;
+import android.net.VpnService.Builder;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.UserManager;
+import android.provider.Settings;
+import android.util.Log;
+import android.widget.TextView;
+import android.net.VpnService;
+import android.os.ParcelFileDescriptor;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.io.IOException;
+
+/**
+ * Activity to test Vpn configuration
+ */
+public class VpnTestActivity extends PassFailButtons.Activity {
+
+ public static final String ACTION_VPN = "com.android.cts.verifier.managedprovisioning.VPN";
+
+ public static class MyTestVpnService extends VpnService {
+ /*
+ * MyVpnTestService is just a stub. This class exists because the framework needs a class
+ * inside the app to refer back to, just using VpnService itself won't work.
+ */
+ }
+
+ private ParcelFileDescriptor descriptor = null;
+ private ComponentName mAdminReceiverComponent;
+ private DevicePolicyManager mDevicePolicyManager;
+ private UserManager mUserManager;
+ private static final String TAG = "DeviceOwnerPositiveTestActivity";
+ private static final int REQUEST_VPN_CODE = 1;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.vpn_test);
+ setPassFailButtonClickListeners();
+ mAdminReceiverComponent = new ComponentName(this, DeviceAdminTestReceiver.class.getName());
+ mDevicePolicyManager = (DevicePolicyManager) getSystemService(
+ Context.DEVICE_POLICY_SERVICE);
+ mDevicePolicyManager.addUserRestriction(mAdminReceiverComponent,
+ UserManager.DISALLOW_CONFIG_VPN);
+ mUserManager = (UserManager) getSystemService(Context.USER_SERVICE);
+ testVpnEstablishFails();
+ }
+
+ @Override
+ public void finish() {
+ mDevicePolicyManager.clearUserRestriction(mAdminReceiverComponent,
+ UserManager.DISALLOW_CONFIG_VPN);
+ super.finish();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int result, Intent data) {
+ if (requestCode == REQUEST_VPN_CODE && result == RESULT_OK) {
+ establishVpn();
+ } else {
+ // vpn connection canceled by user
+ Log.w(TAG, "Test failed, canceled by user");
+ populateInfo(R.string.device_owner_vpn_connection_canceled);
+ }
+ }
+
+ public void testVpnEstablishFails() {
+ Intent newIntent = VpnService.prepare(this);
+ if (newIntent != null) {
+ startActivityForResult(newIntent, REQUEST_VPN_CODE);
+ } else {
+ establishVpn();
+ }
+ }
+
+ public void establishVpn() {
+ MyTestVpnService service = new MyTestVpnService();
+ descriptor = service.new Builder().addAddress("8.8.8.8", 30).establish();
+ if (descriptor == null) {
+ // vpn connection not established, as expected, test case succeeds
+ Log.i(TAG, "Test succeeded: descriptor is null");
+ populateInfo(R.string.device_owner_no_vpn_connection);
+ return;
+ }
+ // vpn connection established, not expected, test case fails
+ Log.w(TAG, "vpn connection established, not expected, test case fails");
+ try {
+ descriptor.close();
+ populateInfo(R.string.device_owner_vpn_connection);
+ } catch (IOException e) {
+ Log.i(TAG, "Closing vpn connection failed. Caught exception: ", e);
+ populateInfo(R.string.device_owner_vpn_connection_close_failed);
+ }
+ }
+
+ private void populateInfo(int messageId) {
+ TextView vpnInfoTextView = (TextView) findViewById(R.id.device_owner_vpn_info);
+ vpnInfoTextView.setText(getString(messageId));
+ }
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java
index 4a292eb..3babb8f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WifiLockdownTestActivity.java
@@ -126,13 +126,6 @@
});
}
- /**
- * Enable Pass Button when all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
adapter.add(DeviceOwnerPositiveTestActivity.createInteractiveTestItem(this,
CONFIG_MODIFIABLE_WHEN_UNLOCKED_TEST_ID,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
deleted file mode 100644
index a912d2c..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/WorkNotificationTestActivity.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.managedprovisioning;
-
-import android.app.Activity;
-import android.app.Notification;
-import android.app.NotificationManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-
-import com.android.cts.verifier.R;
-
-/**
- * Test activity used to generate a notification.
- */
-public class WorkNotificationTestActivity extends Activity {
- public static final String ACTION_WORK_NOTIFICATION =
- "com.android.cts.verifier.managedprovisioning.WORK_NOTIFICATION";
- public static final String ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN =
- "com.android.cts.verifier.managedprovisioning.LOCKSCREEN_NOTIFICATION";
- public static final String ACTION_CLEAR_WORK_NOTIFICATION =
- "com.android.cts.verifier.managedprovisioning.CLEAR_WORK_NOTIFICATION";
- private static final int NOTIFICATION_ID = 7;
- private NotificationManager mNotificationManager;
-
- private void showWorkNotification(int visibility) {
- final Notification notification = new Notification.Builder(this)
- .setSmallIcon(R.drawable.icon)
- .setContentTitle(getString(R.string.provisioning_byod_work_notification_title))
- .setVisibility(visibility)
- .setAutoCancel(true)
- .build();
- mNotificationManager.notify(NOTIFICATION_ID, notification);
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- final String action = getIntent().getAction();
- mNotificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
- if (ACTION_WORK_NOTIFICATION.equals(action)) {
- showWorkNotification(Notification.VISIBILITY_PUBLIC);
- } else if (ACTION_WORK_NOTIFICATION_ON_LOCKSCREEN.equals(action)) {
- DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
- Context.DEVICE_POLICY_SERVICE);
- dpm.lockNow();
- showWorkNotification(Notification.VISIBILITY_PRIVATE);
- } else if (ACTION_CLEAR_WORK_NOTIFICATION.equals(action)) {
- mNotificationManager.cancel(NOTIFICATION_ID);
- }
- finish();
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
new file mode 100644
index 0000000..47a928c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -0,0 +1,554 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.notifications;
+
+import com.android.cts.verifier.R;
+
+import android.app.AutomaticZenRule;
+import android.app.NotificationManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Parcelable;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
+import android.text.TextUtils;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ConditionProviderVerifierActivity extends InteractiveVerifierActivity
+ implements Runnable {
+ protected static final String CP_PACKAGE = "com.android.cts.verifier";
+ protected static final String CP_PATH = CP_PACKAGE +
+ "/com.android.cts.verifier.notifications.MockConditionProvider";
+
+ @Override
+ int getTitleResource() {
+ return R.string.cp_test;
+ }
+
+ @Override
+ int getInstructionsResource() {
+ return R.string.cp_info;
+ }
+
+ // Test Setup
+
+ @Override
+ protected List<InteractiveTestCase> createTestItems() {
+ List<InteractiveTestCase> tests = new ArrayList<>(9);
+ tests.add(new IsEnabledTest());
+ tests.add(new ServiceStartedTest());
+ tests.add(new CreateAutomaticZenRuleTest());
+ tests.add(new GetAutomaticZenRuleTest());
+ tests.add(new GetAutomaticZenRulesTest());
+ tests.add(new SubscribeAutomaticZenRuleTest());
+ tests.add(new DeleteAutomaticZenRuleTest());
+ tests.add(new UnsubscribeAutomaticZenRuleTest());
+ tests.add(new IsDisabledTest());
+ tests.add(new ServiceStoppedTest());
+ return tests;
+ }
+
+ protected class IsEnabledTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createSettingsItem(parent, R.string.cp_enable_service);
+ }
+
+ @Override
+ boolean autoStart() {
+ return true;
+ }
+
+ @Override
+ void test() {
+ Intent settings = new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS);
+ if (settings.resolveActivity(mPackageManager) == null) {
+ logFail("no settings activity");
+ status = FAIL;
+ } else {
+ String cpPackages = Secure.getString(getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+ if (cpPackages != null && cpPackages.contains(CP_PACKAGE)) {
+ status = PASS;
+ } else {
+ status = WAIT_FOR_USER;
+ }
+ next();
+ }
+ }
+
+ void tearDown() {
+ // wait for the service to start
+ delay();
+ }
+ }
+
+ protected class ServiceStartedTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_service_started);
+ }
+
+ @Override
+ void test() {
+ MockConditionProvider.probeConnected(mContext,
+ new MockConditionProvider.BooleanResultCatcher() {
+ @Override
+ public void accept(boolean result) {
+ if (result) {
+ status = PASS;
+ } else {
+ logFail();
+ status = RETEST;
+ delay();
+ }
+ next();
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class CreateAutomaticZenRuleTest extends InteractiveTestCase {
+ private String id = null;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_create_rule);
+ }
+
+ @Override
+ void test() {
+ long now = System.currentTimeMillis();
+ AutomaticZenRule ruleToCreate =
+ createRule("Rule", "value", NotificationManager.INTERRUPTION_FILTER_ALARMS);
+ AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+
+ if (createdRule != null
+ && ruleToCreate.getName().equals(createdRule.getName())
+ && ruleToCreate.getOwner().equals(createdRule.getOwner())
+ && ruleToCreate.getConditionId().equals(createdRule.getConditionId())
+ && ruleToCreate.isEnabled() == createdRule.isEnabled()
+ && !TextUtils.isEmpty(createdRule.getId())
+ && createdRule.getCreationTime() > now) {
+ id = createdRule.getId();
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ if (id != null) {
+ mNm.removeAutomaticZenRule(id);
+ }
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class SubscribeAutomaticZenRuleTest extends InteractiveTestCase {
+ private String id = null;
+ private AutomaticZenRule ruleToCreate;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_subscribe_rule);
+ }
+
+ @Override
+ void setUp() {
+ ruleToCreate = createRule("RuleSubscribe", "Subscribevalue",
+ NotificationManager.INTERRUPTION_FILTER_ALARMS);
+ AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+ id = createdRule == null ? null : createdRule.getId();
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+
+ MockConditionProvider.probeSubscribe(mContext,
+ new MockConditionProvider.ParcelableListResultCatcher() {
+ @Override
+ public void accept(List<Parcelable> result) {
+ boolean foundMatch = false;
+ for (Parcelable p : result) {
+ Uri uri = (Uri) p;
+ if (ruleToCreate.getConditionId().equals(uri)) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (foundMatch) {
+ status = PASS;
+ } else {
+ logFail();
+ status = RETEST;
+ }
+ next();
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ if (id != null) {
+ mNm.removeAutomaticZenRule(id);
+ }
+ MockConditionProvider.resetData(mContext);
+ // wait for intent to move through the system
+ delay();
+ }
+ }
+
+ private class GetAutomaticZenRuleTest extends InteractiveTestCase {
+ private String id = null;
+ private AutomaticZenRule ruleToCreate;
+ private AutomaticZenRule createdRule;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_get_rule);
+ }
+
+ @Override
+ void setUp() {
+ ruleToCreate = createRule("RuleGet", "valueGet",
+ NotificationManager.INTERRUPTION_FILTER_ALARMS);
+ createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+ id = createdRule == null ? null : createdRule.getId();
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (createdRule != null) {
+ id = createdRule.getId();
+ AutomaticZenRule queriedRule = mNm.getAutomaticZenRule(id);
+ if (queriedRule != null
+ && ruleToCreate.getName().equals(queriedRule.getName())
+ && ruleToCreate.getOwner().equals(queriedRule.getOwner())
+ && ruleToCreate.getConditionId().equals(queriedRule.getConditionId())
+ && ruleToCreate.isEnabled() == queriedRule.isEnabled()
+ && queriedRule.getId().equals(id)
+ && createdRule.getCreationTime() == queriedRule.getCreationTime()) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ if (id != null) {
+ mNm.removeAutomaticZenRule(id);
+ }
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class GetAutomaticZenRulesTest extends InteractiveTestCase {
+ private List<String> ids = new ArrayList<>();
+ AutomaticZenRule createdRule1;
+ AutomaticZenRule createdRule2;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_get_rules);
+ }
+
+ @Override
+ void setUp() {
+ AutomaticZenRule rule1 =
+ createRule("Rule1", "value1", NotificationManager.INTERRUPTION_FILTER_ALARMS);
+ AutomaticZenRule rule2 =
+ createRule("Rule2", "value2", NotificationManager.INTERRUPTION_FILTER_NONE);
+ createdRule1 = mNm.addAutomaticZenRule(rule1);
+ createdRule2 = mNm.addAutomaticZenRule(rule2);
+ ids.add(createdRule1.getId());
+ ids.add(createdRule2.getId());
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ List<AutomaticZenRule> rules = mNm.getAutomaticZenRules();
+
+ if (rules == null || rules.size() < 2) {
+ logFail();
+ status = FAIL;
+ next();
+ return;
+ }
+
+ if (rules.contains(createdRule1) && rules.contains(createdRule2)) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ for (String id : ids) {
+ mNm.removeAutomaticZenRule(id);
+ }
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class DeleteAutomaticZenRuleTest extends InteractiveTestCase {
+ private String id = null;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_delete_rule);
+ }
+
+ @Override
+ void test() {
+ AutomaticZenRule ruleToCreate = createRule("RuleDelete", "Deletevalue",
+ NotificationManager.INTERRUPTION_FILTER_ALARMS);
+ AutomaticZenRule createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+
+ if (createdRule != null) {
+ id = createdRule.getId();
+ if (mNm.removeAutomaticZenRule(id)) {
+ if (mNm.getAutomaticZenRule(id) == null) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ } else {
+ logFail("Couldn't test rule deletion; creation failed.");
+ status = FAIL;
+ }
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class UnsubscribeAutomaticZenRuleTest extends InteractiveTestCase {
+ private String id = null;
+ private AutomaticZenRule ruleToCreate;
+ private AutomaticZenRule createdRule;
+
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_unsubscribe_rule);
+ }
+
+ @Override
+ void setUp() {
+ ruleToCreate = createRule("RuleUnsubscribe", "valueUnsubscribe",
+ NotificationManager.INTERRUPTION_FILTER_PRIORITY);
+ createdRule = mNm.addAutomaticZenRule(ruleToCreate);
+ id = createdRule == null ? null : createdRule.getId();
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ MockConditionProvider.probeSubscribe(mContext,
+ new MockConditionProvider.ParcelableListResultCatcher() {
+ @Override
+ public void accept(List<Parcelable> result) {
+ boolean foundMatch = false;
+ for (Parcelable p : result) {
+ Uri uri = (Uri) p;
+ if (ruleToCreate.getConditionId().equals(uri)) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (foundMatch) {
+ // Now that it's subscribed, remove the rule and verify that it
+ // unsubscribes.
+ mNm.removeAutomaticZenRule(id);
+ MockConditionProvider.probeSubscribe(mContext,
+ new MockConditionProvider.ParcelableListResultCatcher() {
+ @Override
+ public void accept(List<Parcelable> result) {
+ boolean foundMatch = false;
+ for (Parcelable p : result) {
+ Uri uri = (Uri) p;
+ if (ruleToCreate.getConditionId().equals(uri)) {
+ foundMatch = true;
+ break;
+ }
+ }
+ if (foundMatch) {
+ logFail();
+ status = RETEST;
+ } else {
+ status = PASS;
+ }
+ next();
+ }
+ });
+ } else {
+ logFail("Couldn't test unsubscribe; subscribe failed.");
+ status = RETEST;
+ next();
+ }
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ mNm.removeAutomaticZenRule(id);
+ MockConditionProvider.resetData(mContext);
+ // wait for intent to move through the system
+ delay();
+ }
+ }
+
+ private class IsDisabledTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createSettingsItem(parent, R.string.cp_disable_service);
+ }
+
+ @Override
+ boolean autoStart() {
+ return true;
+ }
+
+ @Override
+ void test() {
+ String cpPackages = Secure.getString(getContentResolver(),
+ Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+ if (cpPackages == null || !cpPackages.contains(CP_PACKAGE)) {
+ status = PASS;
+ } else {
+ status = WAIT_FOR_USER;
+ }
+ next();
+ }
+
+ @Override
+ void tearDown() {
+ MockConditionProvider.resetData(mContext);
+ delay();
+ }
+ }
+
+ private class ServiceStoppedTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.cp_service_stopped);
+ }
+
+ @Override
+ void test() {
+ MockConditionProvider.probeConnected(mContext,
+ new MockConditionProvider.BooleanResultCatcher() {
+ @Override
+ public void accept(boolean result) {
+ if (result) {
+ logFail();
+ status = RETEST;
+ delay();
+ } else {
+ status = PASS;
+ }
+ next();
+ }
+ });
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ MockConditionProvider.resetData(mContext);
+ // wait for intent to move through the system
+ delay();
+ }
+ }
+
+ private AutomaticZenRule createRule(String name, String queryValue, int status) {
+ return new AutomaticZenRule(name,
+ ComponentName.unflattenFromString(CP_PATH),
+ MockConditionProvider.toConditionId(queryValue),
+ status,
+ true);
+ }
+
+ protected View createSettingsItem(ViewGroup parent, int messageId) {
+ return createUserItem(parent, R.string.cp_start_settings, messageId);
+ }
+
+ public void launchSettings() {
+ startActivity(new Intent(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS));
+ }
+
+ public void actionPressed(View v) {
+ Object tag = v.getTag();
+ if (tag instanceof Integer) {
+ int id = ((Integer) tag).intValue();
+ if (id == R.string.cp_start_settings) {
+ launchSettings();
+ } else if (id == R.string.attention_ready) {
+ mCurrentTest.status = READY;
+ next();
+ }
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java
new file mode 100644
index 0000000..4b90d9a
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockConditionProvider.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.cts.verifier.notifications;
+
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Parcelable;
+import android.service.notification.Condition;
+import android.service.notification.ConditionProviderService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class MockConditionProvider extends ConditionProviderService {
+ static final String TAG = "MockConditionProvider";
+
+ static final String PACKAGE_NAME = "com.android.cts.verifier.notifications";
+ static final String PATH = "mock_cp";
+ static final String QUERY = "query_item";
+
+ static final String SERVICE_BASE = "android.service.notification.cts.MockConditionProvider.";
+ static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
+ static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
+ static final String SERVICE_SUBSCRIBE = SERVICE_BASE + "SERVICE_SUBSCRIBE";
+
+ static final String EXTRA_PAYLOAD = "PAYLOAD";
+ static final String EXTRA_INT = "INT";
+ static final String EXTRA_BOOLEAN = "BOOLEAN";
+ static final String EXTRA_TAG = "TAG";
+ static final String EXTRA_CODE = "CODE";
+
+ static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
+
+
+ private ArrayList<Uri> mSubscriptions = new ArrayList<>();
+ private boolean mConnected = false;
+ private BroadcastReceiver mReceiver;
+
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ Log.d(TAG, "created");
+
+ mSubscriptions = new ArrayList<Uri>();
+
+ mReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (SERVICE_CHECK.equals(action)) {
+ Log.d(TAG, "SERVICE_CHECK");
+ Bundle bundle = new Bundle();
+ bundle.putBoolean(EXTRA_BOOLEAN, mConnected);
+ setResultExtras(bundle);
+ setResultCode(Activity.RESULT_OK);
+ } else if (SERVICE_SUBSCRIBE.equals(action)) {
+ Log.d(TAG, "SERVICE_SUBSCRIBE");
+ Bundle bundle = new Bundle();
+ bundle.putParcelableArrayList(EXTRA_PAYLOAD, mSubscriptions);
+ setResultExtras(bundle);
+ setResultCode(Activity.RESULT_OK);
+ } else if (SERVICE_RESET.equals(action)) {
+ Log.d(TAG, "SERVICE_RESET");
+ resetData();
+ } else {
+ Log.w(TAG, "unknown action");
+ setResultCode(Activity.RESULT_CANCELED);
+ }
+ }
+ };
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(SERVICE_CHECK);
+ filter.addAction(SERVICE_SUBSCRIBE);
+ filter.addAction(SERVICE_RESET);
+ registerReceiver(mReceiver, filter);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ mConnected = false;
+ unregisterReceiver(mReceiver);
+ mReceiver = null;
+ Log.d(TAG, "destroyed");
+ }
+
+ public void resetData() {
+ mSubscriptions.clear();
+ }
+
+ public static void resetData(Context context) {
+ sendCommand(context, SERVICE_RESET, null, 0);
+ }
+
+ public static void probeConnected(Context context, BooleanResultCatcher catcher) {
+ requestConnected(context, SERVICE_CHECK, catcher);
+ }
+
+ public static void probeSubscribe(Context context, ParcelableListResultCatcher catcher) {
+ requestParcelableListResult(context, SERVICE_SUBSCRIBE, catcher);
+ }
+
+ private static void sendCommand(Context context, String action, String tag, int code) {
+ Intent broadcast = new Intent(action);
+ if (tag != null) {
+ broadcast.putExtra(EXTRA_TAG, tag);
+ broadcast.putExtra(EXTRA_CODE, code);
+ }
+ context.sendBroadcast(broadcast);
+ }
+
+ public static Uri toConditionId(String queryValue) {
+ return new Uri.Builder().scheme(Condition.SCHEME)
+ .authority(PACKAGE_NAME)
+ .appendPath(PATH)
+ .appendQueryParameter(QUERY, queryValue)
+ .build();
+ }
+
+ @Override
+ public void onConnected() {
+ Log.d(TAG, "connected");
+ mConnected = true;
+ }
+
+ @Override
+ public void onRequestConditions(int relevance) {
+
+ }
+
+ @Override
+ public void onSubscribe(Uri conditionId) {
+ Log.d(TAG, "subscribed to " + conditionId);
+ mSubscriptions.add(conditionId);
+ }
+
+ @Override
+ public void onUnsubscribe(Uri conditionId) {
+ Log.d(TAG, "unsubscribed from " + conditionId);
+ mSubscriptions.remove(conditionId);
+ }
+
+ public abstract static class BooleanResultCatcher extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ accept(getResultExtras(true).getBoolean(EXTRA_BOOLEAN, false));
+ }
+
+ abstract public void accept(boolean result);
+ }
+
+ private static void requestConnected(Context context, String action,
+ BooleanResultCatcher catcher) {
+ Intent broadcast = new Intent(action);
+ context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+ }
+
+ public abstract static class ParcelableListResultCatcher extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ accept(getResultExtras(true).getParcelableArrayList(EXTRA_PAYLOAD));
+ }
+
+ abstract public void accept(List<Parcelable> result);
+ }
+
+ private static void requestParcelableListResult(Context context, String action,
+ ParcelableListResultCatcher catcher) {
+ Intent broadcast = new Intent(action);
+ context.sendOrderedBroadcast(broadcast, null, catcher, null, RESULT_NO_SERVER, null, null);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
index 920c9ae..5985be6 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/P2pTestListActivity.java
@@ -153,13 +153,6 @@
}
/**
- * Enable Pass Button when the all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
- /**
* Receive the WIFI_P2P_STATE_CHANGED_ACTION action.
*/
class P2pBroadcastReceiver extends BroadcastReceiver {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java
index e6f94af..dd53d33 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/p2p/RequesterTestListActivity.java
@@ -103,11 +103,4 @@
adapter.add(TestListItem.newTest(testcase.getTestName(), testcase.getTestId(),
intent, null));
}
-
- /**
- * Enable Pass Button when the all tests passed.
- */
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
index 83e3054..ab8546b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/DeviceSuspendTestActivity.java
@@ -186,37 +186,35 @@
}
public String runAPWakeUpWhenReportLatencyExpires(Sensor sensor) throws Throwable {
+
+ verifyBatchingSupport(sensor);
+
int fifoMaxEventCount = sensor.getFifoMaxEventCount();
- if (fifoMaxEventCount == 0) {
- throw new SensorTestStateNotSupportedException("Batching not supported.");
- }
- int maximumExpectedSamplingPeriodUs = sensor.getMaxDelay();
- if (maximumExpectedSamplingPeriodUs == 0) {
+ int samplingPeriodUs = sensor.getMaxDelay();
+ if (samplingPeriodUs == 0) {
// If maxDelay is not defined, set the value for 5 Hz.
- maximumExpectedSamplingPeriodUs = 200000;
- }
- int fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
-
- // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
- // seconds of time to allow the device to be in suspend state.
- if (fifoBasedReportLatencyUs < 20000000L) {
- throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
+ samplingPeriodUs = 200000;
}
- final int MAX_REPORT_LATENCY_US = 15000000; // 15 seconds
+ long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
+ verifyBatchingPeriod(fifoBasedReportLatencyUs);
+
+ final long MAX_REPORT_LATENCY_US = TimeUnit.SECONDS.toMicros(15); // 15 seconds
TestSensorEnvironment environment = new TestSensorEnvironment(
this,
sensor,
false,
- maximumExpectedSamplingPeriodUs,
- MAX_REPORT_LATENCY_US,
+ samplingPeriodUs,
+ (int) MAX_REPORT_LATENCY_US,
true /*isDeviceSuspendTest*/);
TestSensorOperation op = TestSensorOperation.createOperation(environment,
mDeviceSuspendLock,
false);
- final int ALARM_WAKE_UP_DELAY_MS = MAX_REPORT_LATENCY_US/1000 +
- (int)TimeUnit.SECONDS.toMillis(10);
+ final long ALARM_WAKE_UP_DELAY_MS =
+ TimeUnit.MICROSECONDS.toMillis(MAX_REPORT_LATENCY_US) +
+ TimeUnit.SECONDS.toMillis(10);
+
op.addVerification(BatchArrivalVerification.getDefault(environment));
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
SystemClock.elapsedRealtime() + ALARM_WAKE_UP_DELAY_MS,
@@ -231,35 +229,37 @@
}
public String runAPWakeUpWhenFIFOFull(Sensor sensor) throws Throwable {
- int fifoMaxEventCount = sensor.getFifoMaxEventCount();
- if (fifoMaxEventCount == 0) {
- throw new SensorTestStateNotSupportedException("Batching not supported.");
- }
+ verifyBatchingSupport(sensor);
+
// Try to fill the FIFO at the fastest rate and check if the time is enough to run
// the manual test.
- int maximumExpectedSamplingPeriodUs = sensor.getMinDelay();
- int fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+ int samplingPeriodUs = sensor.getMinDelay();
- final int MIN_LATENCY_US = (int)TimeUnit.SECONDS.toMicros(20);
+ long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
+
+ final long MIN_LATENCY_US = TimeUnit.SECONDS.toMicros(20);
// Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
// seconds of time to allow the device to be in suspend state.
if (fifoBasedReportLatencyUs < MIN_LATENCY_US) {
- maximumExpectedSamplingPeriodUs = MIN_LATENCY_US/fifoMaxEventCount;
+ int fifoMaxEventCount = sensor.getFifoMaxEventCount();
+ samplingPeriodUs = (int) MIN_LATENCY_US/fifoMaxEventCount;
fifoBasedReportLatencyUs = MIN_LATENCY_US;
}
final int MAX_REPORT_LATENCY_US = Integer.MAX_VALUE;
- final int ALARM_WAKE_UP_DELAY_MS = fifoBasedReportLatencyUs/1000 +
- (int)TimeUnit.SECONDS.toMillis(10);
+ final long ALARM_WAKE_UP_DELAY_MS =
+ TimeUnit.MICROSECONDS.toMillis(fifoBasedReportLatencyUs) +
+ TimeUnit.SECONDS.toMillis(10);
+
TestSensorEnvironment environment = new TestSensorEnvironment(
this,
sensor,
false,
- maximumExpectedSamplingPeriodUs,
- MAX_REPORT_LATENCY_US,
+ (int) samplingPeriodUs,
+ (int) MAX_REPORT_LATENCY_US,
true /*isDeviceSuspendTest*/);
- TestSensorOperation op = TestSensorOperation.createOperation(environment,
+ TestSensorOperation op = TestSensorOperation.createOperation(environment,
mDeviceSuspendLock,
true);
mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,
@@ -277,33 +277,26 @@
public String runAPWakeUpByAlarmNonWakeSensor(Sensor sensor, int maxReportLatencyUs)
throws Throwable {
- int fifoMaxEventCount = sensor.getFifoMaxEventCount();
- if (fifoMaxEventCount == 0) {
- throw new SensorTestStateNotSupportedException("Batching not supported.");
- }
- int maximumExpectedSamplingPeriodUs = sensor.getMaxDelay();
- if (maximumExpectedSamplingPeriodUs == 0 ||
- maximumExpectedSamplingPeriodUs > 200000) {
- // If maxDelay is not defined, set the value for 5 Hz.
- maximumExpectedSamplingPeriodUs = 200000;
- }
- int fifoBasedReportLatencyUs = fifoMaxEventCount * maximumExpectedSamplingPeriodUs;
+ verifyBatchingSupport(sensor);
- // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
- // seconds of time to allow the device to be in suspend state.
- if (fifoBasedReportLatencyUs < 20000000L) {
- throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
+ int samplingPeriodUs = sensor.getMaxDelay();
+ if (samplingPeriodUs == 0 || samplingPeriodUs > 200000) {
+ // If maxDelay is not defined, set the value for 5 Hz.
+ samplingPeriodUs = 200000;
}
+ long fifoBasedReportLatencyUs = maxBatchingPeriod(sensor, samplingPeriodUs);
+ verifyBatchingPeriod(fifoBasedReportLatencyUs);
+
TestSensorEnvironment environment = new TestSensorEnvironment(
this,
sensor,
false,
- maximumExpectedSamplingPeriodUs,
+ (int) samplingPeriodUs,
maxReportLatencyUs,
true /*isDeviceSuspendTest*/);
- final int ALARM_WAKE_UP_DELAY_MS = 20000;
+ final long ALARM_WAKE_UP_DELAY_MS = 20000;
TestSensorOperation op = TestSensorOperation.createOperation(environment,
mDeviceSuspendLock,
true);
@@ -318,4 +311,27 @@
}
return null;
}
+
+ private void verifyBatchingSupport(Sensor sensor)
+ throws SensorTestStateNotSupportedException {
+ int fifoMaxEventCount = sensor.getFifoMaxEventCount();
+ if (fifoMaxEventCount == 0) {
+ throw new SensorTestStateNotSupportedException("Batching not supported.");
+ }
+ }
+
+ private void verifyBatchingPeriod(long periodUs)
+ throws SensorTestStateNotSupportedException {
+ // Ensure that FIFO based report latency is at least 20 seconds, we need at least 10
+ // seconds of time to allow the device to be in suspend state.
+ if (periodUs < TimeUnit.SECONDS.toMicros(20)) {
+ throw new SensorTestStateNotSupportedException("FIFO too small to test reliably");
+ }
+ }
+
+ private long maxBatchingPeriod (Sensor sensor, long samplePeriod) {
+ long fifoMaxEventCount = sensor.getFifoMaxEventCount();
+ return fifoMaxEventCount * samplePeriod;
+ }
+
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
index 9684d97..00a52ae 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/streamquality/StreamingVideoActivity.java
@@ -117,7 +117,7 @@
private static final Stream[] HTTP_STREAMS = {
new Stream("H263 Video, AMR Audio", "http_h263_amr",
- "http://redirector.c.play.google.com/"
+ "http://redirector.gvt1.com/"
+ "videoplayback?id=271de9756065677e"
+ "&itag=13&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&sparams=ip,ipbits,expire,id,itag"
@@ -126,7 +126,7 @@
+ "&source=youtube"
+ "&key=ik0&user=android-device-test"),
new Stream("MPEG4 SP Video, AAC Audio", "http_mpeg4_aac",
- "http://redirector.c.play.google.com/"
+ "http://redirector.gvt1.com/"
+ "videoplayback?id=271de9756065677e"
+ "&itag=17&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&sparams=ip,ipbits,expire,id,itag"
@@ -135,7 +135,7 @@
+ "&source=youtube"
+ "&key=ik0&user=android-device-test"),
new Stream("H264 Base Video, AAC Audio", "http_h264_aac",
- "http://redirector.c.play.google.com/"
+ "http://redirector.gvt1.com/"
+ "videoplayback?id=271de9756065677e"
+ "&itag=18&ip=0.0.0.0&ipbits=0&expire=19000000000"
+ "&sparams=ip,ipbits,expire,id,itag"
@@ -220,10 +220,6 @@
i, null));
}
- private void updatePassButton() {
- getPassButton().setEnabled(mAdapter.allTestsPassed());
- }
-
/** @returns the appropriate RTSP url, or null in case of failure */
private String lookupRtspUrl(int itag, String signature) {
String rtspLookupUri = String.format(RTSP_LOOKUP_URI_TEMPLATE, itag, signature);
diff --git a/build/device_info_package.mk b/build/device_info_package.mk
index f46b5ed..036218a 100644
--- a/build/device_info_package.mk
+++ b/build/device_info_package.mk
@@ -19,7 +19,22 @@
DEVICE_INFO_PACKAGE := com.android.compatibility.common.deviceinfo
DEVICE_INFO_INSTRUMENT := android.support.test.runner.AndroidJUnitRunner
DEVICE_INFO_PERMISSIONS += android.permission.WRITE_EXTERNAL_STORAGE
-DEVICE_INFO_ACTIVITIES += $(DEVICE_INFO_PACKAGE).GenericDeviceInfo $(DEVICE_INFO_PACKAGE).PackageDeviceInfo
+DEVICE_INFO_ACTIVITIES += \
+ $(DEVICE_INFO_PACKAGE).CameraDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).ConfigurationDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).CpuDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).FeatureDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).GenericDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).GraphicsDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).LibraryDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).LocaleDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).MediaDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).MemoryDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).PackageDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).PropertyDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).ScreenDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).StorageDeviceInfo \
+ $(DEVICE_INFO_PACKAGE).UserDeviceInfo
ifeq ($(DEVICE_INFO_MIN_SDK),)
DEVICE_INFO_MIN_SDK := 8
diff --git a/build/test_deqp_package.mk b/build/test_deqp_package.mk
index cbcf224..f98f342 100644
--- a/build/test_deqp_package.mk
+++ b/build/test_deqp_package.mk
@@ -19,25 +19,23 @@
CTS_DEQP_CONFIG_PATH := $(call my-dir)
cts_library_xml := $(CTS_TESTCASES_OUT)/com.drawelements.deqp.$(DEQP_API).xml
-$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/mnc/com.drawelements.deqp.$(DEQP_API).xml
+$(cts_library_xml): MUSTPASS_XML_FILE := external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml
$(cts_library_xml): PRIVATE_TEST_NAME := $(DEQP_TEST_NAME)
$(cts_library_xml): PRIVATE_TEST_PACKAGE := com.drawelements.deqp.$(DEQP_API)
$(cts_library_xml): PRIVATE_DUMMY_CASELIST := $(CTS_DEQP_CONFIG_PATH)/deqp_dummy_test_list
-$(cts_library_xml): external/deqp/android/cts/mnc/com.drawelements.deqp.$(DEQP_API).xml $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
+$(cts_library_xml): external/deqp/android/cts/master/com.drawelements.deqp.$(DEQP_API).xml external/deqp/android/cts/mnc/$(DEQP_API)-master.txt $(CTS_EXPECTATIONS) $(CTS_UNSUPPORTED_ABIS) $(CTS_XML_GENERATOR)
$(hide) echo Generating test description for $(PRIVATE_TEST_NAME)
$(hide) mkdir -p $(CTS_TESTCASES_OUT)
-# Query build ABIs by routing a dummy test list through xml generator and parse result
- $(hide) $(eval supported_abi_attr := $(shell $(CTS_XML_GENERATOR) -t dummyTest \
- -n dummyName \
- -p invalid.dummy \
- -e $(CTS_EXPECTATIONS) \
- -b $(CTS_UNSUPPORTED_ABIS) \
- -a $(CTS_TARGET_ARCH) \
- < $(PRIVATE_DUMMY_CASELIST) \
- | grep --only-matching -e " abis=\"[^\"]*\""))
-
-# Patch xml caselist with supported abi
- $(hide) $(SED_EXTENDED) -e 's:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $(supported_abi_attr)\4>:' \
+# Query build ABIs by routing a dummy test list through xml generator and parse result. Use sed to insert the ABI string into the XML files.
+ $(hide) SUPPORTED_ABI_ATTR=`$(CTS_XML_GENERATOR) -t dummyTest \
+ -n dummyName \
+ -p invalid.dummy \
+ -e $(CTS_EXPECTATIONS) \
+ -b $(CTS_UNSUPPORTED_ABIS) \
+ -a $(CTS_TARGET_ARCH) \
+ < $(PRIVATE_DUMMY_CASELIST) \
+ | grep --only-matching -e " abis=\"[^\"]*\""` && \
+ $(SED_EXTENDED) -e "s:^(\s*)<Test ((.[^/]|[^/])*)(/?)>$$:\1<Test \2 $${SUPPORTED_ABI_ATTR}\4>:" \
< $(MUSTPASS_XML_FILE) \
> $@
diff --git a/build/test_target_java_library.mk b/build/test_target_java_library.mk
index fe1000a..525abb5 100644
--- a/build/test_target_java_library.mk
+++ b/build/test_target_java_library.mk
@@ -50,4 +50,4 @@
-o $@
# Have the module name depend on the cts files; so the cts files get generated when you run mm/mmm/mma/mmma.
-$(my_register_name) : $(cts_library_jar) $(cts_library_xml $(cts_module_test_config))
+$(my_register_name) : $(cts_library_jar) $(cts_library_xml) $(cts_module_test_config)
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
new file mode 100644
index 0000000..4e379dc
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CameraDeviceInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.media.CamcorderProfile;
+
+/**
+ * Camera information collector.
+ */
+public final class CameraDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ addResult("profile_480p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_480P));
+ addResult("profile_720p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_720P));
+ addResult("profile_1080p", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_1080P));
+ addResult("profile_cif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_CIF));
+ addResult("profile_qcif", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QCIF));
+ addResult("profile_qvga", CamcorderProfile.hasProfile(CamcorderProfile.QUALITY_QVGA));
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java
new file mode 100644
index 0000000..4ce905e
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ConfigurationDeviceInfo.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.res.Configuration;
+
+/**
+ * Configuration device info collector.
+ */
+public final class ConfigurationDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ Configuration con = getInstrumentation().getContext().getResources().getConfiguration();
+ addResult("touchscreen", con.touchscreen);
+ addResult("navigation", con.navigation);
+ addResult("keyboard", con.keyboard);
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java
new file mode 100644
index 0000000..45d8e47
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/CpuDeviceInfo.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+/**
+ * CPU device info collector.
+ */
+public final class CpuDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ addResult("available_processors", Runtime.getRuntime().availableProcessors());
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java
new file mode 100644
index 0000000..dff2313
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/FeatureDeviceInfo.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Feature device info collector.
+ */
+public final class FeatureDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ PackageManager packageManager = getInstrumentation().getContext().getPackageManager();
+ startArray("feature");
+
+ Set<String> checkedFeatures = new HashSet<String>();
+ for (String featureName : getPackageManagerFeatures()) {
+ checkedFeatures.add(featureName);
+ boolean hasFeature = packageManager.hasSystemFeature(featureName);
+ addFeature(featureName, "sdk", hasFeature);
+ }
+
+ FeatureInfo[] featureInfos = packageManager.getSystemAvailableFeatures();
+ if (featureInfos != null) {
+ for (FeatureInfo featureInfo : featureInfos) {
+ if (featureInfo.name != null && !checkedFeatures.contains(featureInfo.name)) {
+ addFeature(featureInfo.name, "other", true);
+ }
+ }
+ }
+
+ endArray();
+ }
+
+ /**
+ * Use reflection to get the features defined by the SDK. If there are features that do not fit
+ * the convention of starting with "FEATURE_" then they will still be shown under the
+ * "Other Features" section.
+ *
+ * @return list of feature names from sdk
+ */
+ private List<String> getPackageManagerFeatures() {
+ try {
+ List<String> features = new ArrayList<String>();
+ Field[] fields = PackageManager.class.getFields();
+ for (Field field : fields) {
+ if (field.getName().startsWith("FEATURE_")) {
+ String feature = (String) field.get(null);
+ features.add(feature);
+ }
+ }
+ return features;
+ } catch (IllegalAccessException illegalAccess) {
+ throw new RuntimeException(illegalAccess);
+ }
+ }
+
+ private void addFeature(String name, String type, boolean available) {
+ startGroup();
+ addResult("name", name);
+ addResult("type", type);
+ addResult("available", available);
+ endGroup();
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java
new file mode 100644
index 0000000..1f93aaa
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GlesStubActivity.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.content.res.Configuration;
+import android.os.Bundle;
+import android.view.Window;
+import android.view.WindowManager;
+import android.opengl.GLES20;
+import android.opengl.GLES30;
+import android.opengl.GLSurfaceView;
+import android.util.Log;
+
+import java.util.Locale;
+import java.util.HashSet;
+import java.util.Scanner;
+import java.util.Set;
+import java.util.concurrent.CountDownLatch;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/** Stub activity to collect data from the GlesView */
+public final class GlesStubActivity extends Activity {
+
+ private static final String LOG_TAG = "GlesStubActivity";
+ private int mVersion = -1;
+ private GraphicsDeviceInfo mGraphicsDeviceInfo;
+ private CountDownLatch mDone = new CountDownLatch(1);
+ private HashSet<String> mOpenGlExtensions = new HashSet<String>();
+ private HashSet<String> mFormats = new HashSet<String>();
+ private String mGraphicsVendor;
+ private String mGraphicsRenderer;
+
+ @Override
+ public void onCreate(Bundle bundle) {
+ // Dismiss keyguard and keep screen on while this test is on.
+ Window window = getWindow();
+ window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD |
+ WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON |
+ WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ super.onCreate(bundle);
+
+ window.setFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED,
+ WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+
+ ActivityManager activityManager =
+ (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+ ConfigurationInfo info = activityManager.getDeviceConfigurationInfo();
+
+ mVersion = (info.reqGlEsVersion & 0xffff0000) >> 16;
+
+ new Thread() {
+ @Override
+ public void run() {
+ runIterations(mVersion);
+ }
+ }.start();
+ }
+
+ /**
+ * Wait for this activity to finish gathering information
+ */
+ public void waitForActivityToFinish() {
+ try {
+ mDone.await();
+ } catch (InterruptedException e) {
+ // just move on
+ }
+ }
+
+ private void runIterations(int glVersion) {
+ for (int i = 1; i <= glVersion; i++) {
+ final CountDownLatch done = new CountDownLatch(1);
+ final int version = i;
+ GlesStubActivity.this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ setContentView(new GlesSurfaceView(GlesStubActivity.this, version, done));
+ }
+ });
+ try {
+ done.await();
+ } catch (InterruptedException e) {
+ // just move on
+ }
+ }
+ mDone.countDown();
+ }
+
+ int getGlVersion() {
+ return mVersion;
+ }
+
+ String[] getOpenGlExtensions() {
+ return mOpenGlExtensions.toArray(new String[mOpenGlExtensions.size()]);
+ }
+
+ void addOpenGlExtension(String openGlExtension) {
+ mOpenGlExtensions.add(openGlExtension);
+ }
+
+ String[] getCompressedTextureFormats() {
+ return mFormats.toArray(new String[mFormats.size()]);
+ }
+
+ void addCompressedTextureFormat(String format) {
+ mFormats.add(format);
+ }
+
+ String getVendor() {
+ return mGraphicsVendor;
+ }
+
+ void setVendor(String vendor) {
+ mGraphicsVendor = vendor;
+ }
+
+ String getRenderer() {
+ return mGraphicsRenderer;
+ }
+
+ void setRenderer(String renderer) {
+ mGraphicsRenderer = renderer;
+ }
+
+ static class GlesSurfaceView extends GLSurfaceView {
+
+ public GlesSurfaceView(GlesStubActivity parent, int glVersion, CountDownLatch done) {
+ super(parent);
+
+ if (glVersion > 1) {
+ // Default is 1 so only set if bigger than 1
+ setEGLContextClientVersion(glVersion);
+ }
+ setRenderer(new OpenGlesRenderer(parent, glVersion, done));
+ }
+ }
+
+ static class OpenGlesRenderer implements GLSurfaceView.Renderer {
+
+ private final GlesStubActivity mParent;
+ private final int mGlVersion;
+ private final CountDownLatch mDone;
+
+ OpenGlesRenderer(GlesStubActivity parent, int glVersion, CountDownLatch done) {
+ mParent = parent;
+ mGlVersion = glVersion;
+ mDone = done;
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+ String extensions;
+ String vendor;
+ String renderer;
+ if (mGlVersion == 2) {
+ extensions = GLES20.glGetString(GLES20.GL_EXTENSIONS);
+ vendor = GLES20.glGetString(GLES20.GL_VENDOR);
+ renderer = GLES20.glGetString(GLES20.GL_RENDERER);
+ } else if (mGlVersion == 3) {
+ extensions = GLES30.glGetString(GLES30.GL_EXTENSIONS);
+ vendor = GLES30.glGetString(GLES30.GL_VENDOR);
+ renderer = GLES30.glGetString(GLES30.GL_RENDERER);
+ } else {
+ extensions = gl.glGetString(GL10.GL_EXTENSIONS);
+ vendor = gl.glGetString(GL10.GL_VENDOR);
+ renderer = gl.glGetString(GL10.GL_RENDERER);
+ }
+ mParent.setVendor(vendor);
+ mParent.setRenderer(renderer);
+ Scanner scanner = new Scanner(extensions);
+ scanner.useDelimiter(" ");
+ while (scanner.hasNext()) {
+ String ext = scanner.next();
+ mParent.addOpenGlExtension(ext);
+ if (ext.contains("texture")) {
+ if (ext.contains("compression") || ext.contains("compressed")) {
+ mParent.addCompressedTextureFormat(ext);
+ }
+ }
+ }
+ scanner.close();
+ mDone.countDown();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height) {}
+
+ @Override
+ public void onDrawFrame(GL10 gl) {}
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java
new file mode 100644
index 0000000..d7dcc08
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/GraphicsDeviceInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.Bundle;
+
+/**
+ * Graphics device info collector.
+ */
+public final class GraphicsDeviceInfo extends DeviceInfo {
+
+ private static final String LOG_TAG = "GraphicsDeviceInfo";
+
+ @Override
+ protected void collectDeviceInfo() {
+ GlesStubActivity stubActivity = GraphicsDeviceInfo.this.launchActivity(
+ "com.android.compatibility.common.deviceinfo",
+ GlesStubActivity.class,
+ new Bundle());
+ stubActivity.waitForActivityToFinish();
+
+ addResult("gl_version", stubActivity.getGlVersion());
+ addResult("vendor", stubActivity.getVendor());
+ addResult("renderer", stubActivity.getRenderer());
+
+ addArray("gl_texture", stubActivity.getCompressedTextureFormats());
+ addArray("gl_extension", stubActivity.getOpenGlExtensions());
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
new file mode 100644
index 0000000..40bf754
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LibraryDeviceInfo.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.util.Log;
+
+import java.io.Closeable;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Formatter;
+
+/**
+ * Library device info collector.
+ */
+public final class LibraryDeviceInfo extends DeviceInfo {
+
+ private static final String TAG = "LibraryDeviceInfo";
+ private static final int BUFFER_SIZE_BYTES = 4096;
+
+ @Override
+ protected void collectDeviceInfo() {
+ collectSystemLibs();
+ collectVendorLibs();
+ collectFrameworkJars();
+ }
+
+ private void collectSystemLibs() {
+ startArray("lib");
+ collectFileDetails("/system/lib", ".so");
+ endArray();
+ }
+
+ private void collectVendorLibs() {
+ startArray("vendor_lib");
+ collectFileDetails("/system/vendor/lib", ".so");
+ endArray();
+ }
+
+ private void collectFrameworkJars() {
+ startArray("framework_jar");
+ collectFileDetails("/system/framework", ".jar");
+ endArray();
+ }
+
+ private void collectFileDetails(String path, String suffix) {
+ File dir = new File(path);
+ for (File file : dir.listFiles()) {
+ String name = file.getName();
+ if (file.isFile() && name.endsWith(suffix)) {
+ String sha1 = "unknown";
+ try {
+ sha1 = getSha1sum(file);
+ } catch (IOException e) {
+ Log.e(TAG, "Failed to hash " + file + ": ", e);
+ }
+ startGroup();
+ addResult("name", name);
+ addResult("sha1", sha1);
+ endGroup();
+ }
+ }
+ }
+
+ private static String getSha1sum(File file) throws IOException {
+ InputStream in = null;
+ try {
+ in = new FileInputStream(file);
+ return sha1(in);
+ } finally {
+ close(in);
+ }
+ }
+
+ private static void close(Closeable s) throws IOException {
+ if (s == null) {
+ return;
+ }
+ s.close();
+ }
+
+ /**
+ * @return the SHA-1 digest of input as a hex string
+ */
+ public static String sha1(InputStream input) throws IOException {
+ try {
+ return toHexString(digest(input, "sha1"));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private static byte[] digest(InputStream in, String algorithm)
+ throws NoSuchAlgorithmException, IOException {
+ MessageDigest digest = MessageDigest.getInstance(algorithm);
+ byte[] buffer = new byte[BUFFER_SIZE_BYTES];
+ while (true) {
+ int read = in.read(buffer);
+ if (read < 0) {
+ break;
+ }
+ digest.update(buffer, 0, read);
+ }
+ return digest.digest();
+ }
+
+ private static String toHexString(byte[] buffer) {
+ Formatter formatter = new Formatter();
+ try {
+ for (byte b : buffer) {
+ formatter.format("%02X", b);
+ }
+ return formatter.toString();
+ } finally {
+ formatter.close();
+ }
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
new file mode 100644
index 0000000..831075f
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/LocaleDeviceInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+/**
+ * Locale device info collector.
+ */
+public final class LocaleDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+
+ String[] locales = getInstrumentation().getContext().getAssets().getLocales();
+ if (locales.length == 0) {
+ // default locale
+ addArray("locale", new String[] {"en_US"});
+ } else {
+ addArray("locale", locales);
+ }
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java
new file mode 100644
index 0000000..dbe3f48
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MediaDeviceInfo.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.Build;
+
+import android.media.CamcorderProfile;
+import android.media.MediaCodecInfo;
+import android.media.MediaCodecInfo.CodecProfileLevel;
+import android.media.MediaCodecList;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Media information collector.
+ */
+public final class MediaDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+
+ startArray("media_codec_info");
+
+ for (int i = 0; i < MediaCodecList.getCodecCount(); i++) {
+ MediaCodecInfo info = MediaCodecList.getCodecInfoAt(i);
+
+ startGroup();
+ addResult("name", info.getName());
+ addResult("encoder", info.isEncoder());
+
+ startArray("supported_type");
+ for (String type : info.getSupportedTypes()) {
+
+ startGroup();
+ addResult("type", type);
+ if (info.getCapabilitiesForType(type).profileLevels.length > 0) {
+
+ List<Integer> levelList = new ArrayList<>();
+ List<Integer> profileList = new ArrayList<>();
+ startArray("codec_profile_level");
+
+ for (CodecProfileLevel profileLevel :
+ info.getCapabilitiesForType(type).profileLevels) {
+ startGroup();
+ addResult("level", profileLevel.level);
+ addResult("profile", profileLevel.profile);
+ endGroup();
+ }
+ endArray(); // codec_profile_level
+ }
+ endGroup();
+ }
+ endArray();
+ endGroup();
+ }
+
+ endArray(); // media_codec_profile
+ }
+
+ static int[] toIntArray(List<Integer> integerList) {
+ int[] intArray = new int[integerList.size()];
+ for (int i = 0; i < integerList.size(); i++) {
+ intArray[i] = integerList.get(i);
+ }
+ return intArray;
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java
new file mode 100644
index 0000000..d5a12b4
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/MemoryDeviceInfo.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.app.ActivityManager;
+import android.app.ActivityManager.MemoryInfo;
+import android.content.Context;
+import android.os.Bundle;
+
+import com.android.compatibility.common.deviceinfo.DeviceInfo;
+
+/**
+ * MemoryDeviceInfo collector.
+ */
+public final class MemoryDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ ActivityManager activityManager = (ActivityManager)getInstrumentation()
+ .getTargetContext().getSystemService(Context.ACTIVITY_SERVICE);
+ addResult("low_ram_device", activityManager.isLowRamDevice());
+ addResult("memory_class", activityManager.getMemoryClass());
+ addResult("large_memory_class", activityManager.getLargeMemoryClass());
+
+ MemoryInfo memoryInfo = new MemoryInfo();
+ activityManager.getMemoryInfo(memoryInfo);
+ addResult("total_memory", memoryInfo.totalMem);
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
new file mode 100644
index 0000000..1844b37
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/PropertyDeviceInfo.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.Scanner;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * System property info collector.
+ */
+public final class PropertyDeviceInfo extends DeviceInfo {
+
+ private static final String LOG_TAG = "PropertyDeviceInfo";
+
+ @Override
+ protected void collectDeviceInfo() {
+ try {
+ collectRoProperties();
+ } catch (IOException e) {
+ Log.w(LOG_TAG, "Failed to collect properties", e);
+ }
+ }
+
+ private void collectRoProperties() throws IOException {
+ startArray("ro_property");
+ Pattern pattern = Pattern.compile("\\[(ro.+)\\]: \\[(.+)\\]");
+ Scanner scanner = null;
+ try {
+ Process getprop = new ProcessBuilder("getprop").start();
+ scanner = new Scanner(getprop.getInputStream());
+ while (scanner.hasNextLine()) {
+ String line = scanner.nextLine();
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ String name = matcher.group(1);
+ String value = matcher.group(2);
+
+ startGroup();
+ addResult("name", name);
+ addResult("value", value);
+ endGroup();
+ }
+ }
+ } finally {
+ endArray();
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java
new file mode 100644
index 0000000..5524531
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/ScreenDeviceInfo.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.util.DisplayMetrics;
+import android.view.Display;
+import android.view.WindowManager;
+
+/**
+ * Screen device info collector.
+ */
+public final class ScreenDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+
+ DisplayMetrics metrics = new DisplayMetrics();
+ WindowManager windowManager =
+ (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
+ Display display = windowManager.getDefaultDisplay();
+ display.getRealMetrics(metrics);
+
+ addResult("width_pixels", metrics.widthPixels);
+ addResult("height_pixels", metrics.heightPixels);
+ addResult("x_dpi", metrics.xdpi);
+ addResult("y_dpi", metrics.ydpi);
+ addResult("density", metrics.density);
+ addResult("density_dpi", metrics.densityDpi);
+
+ Configuration configuration = getContext().getResources().getConfiguration();
+ addResult("screen_size", getScreenSize(configuration));
+ addResult("smallest_screen_width_dp", configuration.smallestScreenWidthDp);
+ }
+
+ private static String getScreenSize(Configuration configuration) {
+ int screenLayout = configuration.screenLayout & Configuration.SCREENLAYOUT_SIZE_MASK;
+ String screenSize = String.format("0x%x", screenLayout);
+ switch (screenLayout) {
+ case Configuration.SCREENLAYOUT_SIZE_SMALL:
+ screenSize = "small";
+ break;
+
+ case Configuration.SCREENLAYOUT_SIZE_NORMAL:
+ screenSize = "normal";
+ break;
+
+ case Configuration.SCREENLAYOUT_SIZE_LARGE:
+ screenSize = "large";
+ break;
+
+ case Configuration.SCREENLAYOUT_SIZE_XLARGE:
+ screenSize = "xlarge";
+ break;
+
+ case Configuration.SCREENLAYOUT_SIZE_UNDEFINED:
+ screenSize = "undefined";
+ break;
+ }
+ return screenSize;
+ }
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
new file mode 100644
index 0000000..823b355
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/StorageDeviceInfo.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.Environment;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Scanner;
+
+/**
+ * Storage device info collector.
+ */
+public class StorageDeviceInfo extends DeviceInfo {
+ private static final String TAG = "StorageDeviceInfo";
+
+ @Override
+ protected void collectDeviceInfo() {
+ int total = 0;
+ total = Math.max(total, getContext().getExternalCacheDirs().length);
+ total = Math.max(total, getContext().getExternalFilesDirs(null).length);
+ total = Math.max(
+ total, getContext().getExternalFilesDirs(Environment.DIRECTORY_PICTURES).length);
+ total = Math.max(total, getContext().getObbDirs().length);
+
+ int emulated = 0;
+ int physical = 0;
+ if (Environment.isExternalStorageEmulated()) {
+ if (total == 1) {
+ emulated = 1;
+ } else {
+ emulated = 1;
+ physical = total - 1;
+ }
+ } else {
+ physical = total;
+ }
+
+ addResult("num_physical", physical);
+ addResult("num_emulated", emulated);
+
+ addArray("raw_partition", scanPartitions());
+ }
+
+ private String[] scanPartitions() {
+ List<String> partitionList = new ArrayList<>();
+ try {
+ Process df = new ProcessBuilder("df").start();
+ Scanner scanner = new Scanner(df.getInputStream());
+ try {
+ while (scanner.hasNextLine()) {
+ partitionList.add(scanner.nextLine());
+ }
+ } finally {
+ scanner.close();
+ }
+ } catch (Exception e) {
+ Log.w(TAG, Log.getStackTraceString(e));
+ }
+ return partitionList.toArray(new String[partitionList.size()]);
+ }
+
+}
diff --git a/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java
new file mode 100644
index 0000000..2886e23
--- /dev/null
+++ b/common/device-side/device-info/src/com/android/compatibility/common/deviceinfo/UserDeviceInfo.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.deviceinfo;
+
+import android.os.UserManager;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+/**
+ * User device info collector.
+ */
+public final class UserDeviceInfo extends DeviceInfo {
+
+ @Override
+ protected void collectDeviceInfo() {
+ addResult("max_supported_users", getMaxSupportedUsers());
+ }
+
+ private int getMaxSupportedUsers() {
+ try {
+ Method method = UserManager.class.getMethod("getMaxSupportedUsers");
+ return (Integer) method.invoke(null);
+ } catch (ClassCastException |
+ NoSuchMethodException |
+ InvocationTargetException |
+ IllegalAccessException e) {}
+ return -1;
+ }
+}
diff --git a/common/device-side/test-app/run_tests.sh b/common/device-side/test-app/run_tests.sh
new file mode 100755
index 0000000..fa5f553
--- /dev/null
+++ b/common/device-side/test-app/run_tests.sh
@@ -0,0 +1,43 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+if [ `adb devices | wc -l` -lt 2 ]; then
+ echo "NO DEVICES/EMULATORS AVAILABLE. CONNECT ONE."
+ exit 1
+fi
+
+# Take the last serial in the list of devices
+SERIAL=`adb devices | egrep -o "^\w+" | tail -n1`
+if [ -z ${SERIAL} ]; then
+ echo "FAILED TO GET ADB DEVICE SERIAL FOR TEST. EXITING"
+ exit 1
+fi
+
+echo "Running device side tests on device: ${SERIAL}"
+
+APK=${ANDROID_PRODUCT_OUT}/data/app/CompatibilityTestApp/CompatibilityTestApp.apk
+checkFile ${APK}
+
+COMMON_PACKAGE=com.android.compatibility.common
+RUNNER=android.support.test.runner.AndroidJUnitRunner
+# TODO [2015-12-09 kalle] Fail & exit on failing install?
+adb -s ${SERIAL} install -r -g ${APK}
+build_jar_path ${JAR_DIR} "${JARS}"
+java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand instrument --serial ${SERIAL} --package ${COMMON_PACKAGE} --runner ${RUNNER}
+adb -s ${SERIAL} uninstall ${COMMON_PACKAGE}
diff --git a/common/host-side/manifest-generator/tests/run_tests.sh b/common/host-side/manifest-generator/tests/run_tests.sh
new file mode 100755
index 0000000..758589c
--- /dev/null
+++ b/common/host-side/manifest-generator/tests/run_tests.sh
@@ -0,0 +1,27 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-manifest-generator\
+ compatibility-manifest-generator-tests"
+
+run_tests "com.android.compatibility.common.generator.ManifestGeneratorTest" "${JARS}" "${@}"
+
diff --git a/common/host-side/tradefed/res/config/everything.xml b/common/host-side/tradefed/res/config/everything.xml
index 048d13e..d1ac900 100644
--- a/common/host-side/tradefed/res/config/everything.xml
+++ b/common/host-side/tradefed/res/config/everything.xml
@@ -16,7 +16,6 @@
<configuration description="Common config for Compatibility suites to run all modules">
<include name="common-compatibility-config" />
- <option name="compatibility-test:include-filter" value=".*" />
- <option name="compatibility-test:plan" value="everything" />
+ <option name="compatibility:plan" value="everything" />
</configuration>
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
index 39a5ca6..f2ce00b 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelper.java
@@ -16,6 +16,7 @@
package com.android.compatibility.common.tradefed.build;
import com.android.compatibility.SuiteInfo;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IFolderBuildInfo;
import java.io.File;
@@ -24,7 +25,7 @@
import java.util.Map;
/**
- * A simple helper that stores and retrieves information from a {@link IFolderBuildInfo}.
+ * A simple helper that stores and retrieves information from a {@link IBuildInfo}.
*/
public class CompatibilityBuildHelper {
@@ -37,18 +38,18 @@
private static final String RESULT_DIR = "RESULT_DIR";
private static final String CONFIG_PATH_PREFIX = "DYNAMIC_CONFIG_FILE:";
private static final String DYNAMIC_CONFIG_OVERRIDE_URL = "DYNAMIC_CONFIG_OVERRIDE_URL";
- private final IFolderBuildInfo mBuildInfo;
+ private final IBuildInfo mBuildInfo;
private boolean mInitialized = false;
/**
- * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IFolderBuildInfo}.
+ * Creates a {@link CompatibilityBuildHelper} wrapping the given {@link IBuildInfo}.
*/
- public CompatibilityBuildHelper(IFolderBuildInfo buildInfo) {
+ public CompatibilityBuildHelper(IBuildInfo buildInfo) {
mBuildInfo = buildInfo;
}
/**
- * Initializes the {@link IFolderBuildInfo} from the manifest.
+ * Initializes the {@link IBuildInfo} from the manifest.
*/
public void init(String suitePlan, String dynamicConfigUrl) {
if (mInitialized) {
@@ -60,24 +61,24 @@
mBuildInfo.addBuildAttribute(SUITE_FULL_NAME, SuiteInfo.FULLNAME);
mBuildInfo.addBuildAttribute(SUITE_VERSION, SuiteInfo.VERSION);
mBuildInfo.addBuildAttribute(SUITE_PLAN, suitePlan);
- String mRootDirPath = System.getProperty(String.format("%s_ROOT", SuiteInfo.NAME));
- if (mRootDirPath == null || mRootDirPath.trim().equals("")) {
- File root = mBuildInfo.getRootDir();
- if (root != null) {
- mRootDirPath = root.getAbsolutePath();
- }
- if (mRootDirPath == null || mRootDirPath.trim().equals("")) {
- throw new IllegalArgumentException(
- String.format("Missing install path property %s_ROOT", SuiteInfo.NAME));
+ String rootDirPath = null;
+ if (mBuildInfo instanceof IFolderBuildInfo) {
+ File rootDir = ((IFolderBuildInfo) mBuildInfo).getRootDir();
+ if (rootDir != null) {
+ rootDirPath = rootDir.getAbsolutePath();
}
}
- File rootDir = new File(mRootDirPath);
+ rootDirPath = System.getProperty(String.format("%s_ROOT", SuiteInfo.NAME), rootDirPath);
+ if (rootDirPath == null || rootDirPath.trim().equals("")) {
+ throw new IllegalArgumentException(
+ String.format("Missing install path property %s_ROOT", SuiteInfo.NAME));
+ }
+ File rootDir = new File(rootDirPath);
if (!rootDir.exists()) {
throw new IllegalArgumentException(
String.format("Root directory doesn't exist %s", rootDir.getAbsolutePath()));
}
mBuildInfo.addBuildAttribute(ROOT_DIR, rootDir.getAbsolutePath());
- mBuildInfo.setRootDir(rootDir);
if (dynamicConfigUrl != null && !dynamicConfigUrl.isEmpty()) {
mBuildInfo.addBuildAttribute(DYNAMIC_CONFIG_OVERRIDE_URL,
dynamicConfigUrl.replace("{suite-name}", getSuiteName()));
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
index d026869..65f60bd 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildProvider.java
@@ -15,7 +15,7 @@
*/
package com.android.compatibility.common.tradefed.build;
-import com.android.tradefed.build.FolderBuildInfo;
+import com.android.tradefed.build.BuildInfo;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IBuildProvider;
import com.android.tradefed.config.OptionClass;
@@ -31,8 +31,8 @@
*/
@Override
public IBuildInfo getBuild() {
- // Create a blank FolderBuildInfo which will get populated later.
- return new FolderBuildInfo("" /* buildId */, "" /* testTarget */, "" /* buildName */);
+ // Create a blank BuildInfo which will get populated later.
+ return new BuildInfo();
}
/**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
index ea0b263..db4ac73 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/command/CompatibilityConsole.java
@@ -23,7 +23,6 @@
import com.android.compatibility.common.tradefed.testtype.ModuleRepo;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.TestStatus;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.command.Console;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.util.ArrayUtil;
@@ -213,8 +212,7 @@
private CompatibilityBuildHelper getBuildHelper() {
if (mBuildHelper == null) {
CompatibilityBuildProvider buildProvider = new CompatibilityBuildProvider();
- IFolderBuildInfo buildInfo = (IFolderBuildInfo) buildProvider.getBuild();
- mBuildHelper = new CompatibilityBuildHelper(buildInfo);
+ mBuildHelper = new CompatibilityBuildHelper(buildProvider.getBuild());
mBuildHelper.init("" /* suite plan */, "" /* dynamic config url */);
}
return mBuildHelper;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
index 55dbd00..cf21d23 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/ResultReporter.java
@@ -2,7 +2,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
-import com.android.compatibility.common.util.AbiUtils;
import com.android.compatibility.common.util.ICaseResult;
import com.android.compatibility.common.util.IInvocationResult;
import com.android.compatibility.common.util.IModuleResult;
@@ -10,14 +9,13 @@
import com.android.compatibility.common.util.InvocationResult;
import com.android.compatibility.common.util.MetricsStore;
import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.ResultHandler;
import com.android.compatibility.common.util.ResultUploader;
import com.android.compatibility.common.util.TestStatus;
-import com.android.compatibility.common.util.ResultHandler;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
@@ -92,7 +90,7 @@
private IModuleResult mCurrentModuleResult;
private ICaseResult mCurrentCaseResult;
private ITestResult mCurrentResult;
- private IFolderBuildInfo mBuild;
+ private IBuildInfo mBuild;
private CompatibilityBuildHelper mBuildHelper;
private ILogSaver mLogSaver;
@@ -102,7 +100,7 @@
@Override
public void invocationStarted(IBuildInfo buildInfo) {
mInitialized = false;
- mBuild = (IFolderBuildInfo) buildInfo;
+ mBuild = buildInfo;
mBuildHelper = new CompatibilityBuildHelper(mBuild);
mDeviceSerial = buildInfo.getDeviceSerial();
if (mDeviceSerial == null) {
@@ -181,8 +179,6 @@
public void testStarted(TestIdentifier test) {
mCurrentCaseResult = mCurrentModuleResult.getOrCreateResult(test.getClassName());
mCurrentResult = mCurrentCaseResult.getOrCreateResult(test.getTestName());
- // Reset the result
- mCurrentResult.resetResult();
}
/**
@@ -312,7 +308,7 @@
try {
File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
mBuildHelper.getSuiteVersion(), mBuildHelper.getSuitePlan(), mResult,
- mResultDir, mStartTime, elapsedTime + mStartTime);
+ mResultDir, mStartTime, elapsedTime + mStartTime, mReferenceUrl);
copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
copyFormattingFiles(mResultDir);
zipResults(mResultDir);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
index 076f902..7773d7d 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstaller.java
@@ -17,7 +17,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.targetprep.TargetSetupError;
import com.android.tradefed.targetprep.TestAppInstallSetup;
@@ -33,7 +32,7 @@
private CompatibilityBuildHelper mBuildHelper = null;
- protected File getTestsDir(IFolderBuildInfo buildInfo) throws FileNotFoundException {
+ protected File getTestsDir(IBuildInfo buildInfo) throws FileNotFoundException {
if (mBuildHelper == null) {
mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@@ -48,7 +47,7 @@
throws TargetSetupError {
File apkFile = null;
try {
- apkFile = new File(getTestsDir((IFolderBuildInfo) buildInfo), apkFileName);
+ apkFile = new File(getTestsDir(buildInfo), apkFileName);
if (!apkFile.isFile()) {
throw new FileNotFoundException();
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
index 34a528e..916e8ec 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ApkInstrumentationPreparer.java
@@ -21,7 +21,6 @@
import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
@@ -115,8 +114,7 @@
private boolean instrument(ITestDevice device, IBuildInfo buildInfo)
throws DeviceNotAvailableException, FileNotFoundException {
ITestInvocationListener listener = new TargetPreparerListener();
- CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(
- (IFolderBuildInfo) buildInfo);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
File testsDir = buildHelper.getTestsDir();
File apkFile = new File(testsDir, mApkFileName);
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
index 7a86168..c178d9c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DeviceInfoCollector.java
@@ -20,13 +20,11 @@
import com.android.compatibility.common.tradefed.testtype.CompatibilityTest;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.targetprep.BuildError;
-import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.targetprep.TargetSetupError;
import java.io.File;
@@ -87,8 +85,7 @@
}
private void getDeviceInfoFiles(ITestDevice device, IBuildInfo buildInfo) {
- CompatibilityBuildHelper buildHelper =
- new CompatibilityBuildHelper((IFolderBuildInfo) buildInfo);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
try {
File resultDir = buildHelper.getResultDir();
if (mDestDir != null) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
index 3284db0..8c455cd 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/DynamicConfigPusher.java
@@ -20,7 +20,6 @@
import com.android.compatibility.common.util.DynamicConfigHandler;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -78,8 +77,7 @@
public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError, BuildError,
DeviceNotAvailableException {
- CompatibilityBuildHelper buildHelper =
- new CompatibilityBuildHelper((IFolderBuildInfo) buildInfo);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
File localConfigFile = null;
try {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
index 054d815b..dba9eb5 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/FilePusher.java
@@ -18,7 +18,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.log.LogUtil.CLog;
@@ -43,7 +42,7 @@
private IAbi mAbi;
- protected File getTestsDir(IFolderBuildInfo buildInfo) throws FileNotFoundException {
+ protected File getTestsDir(IBuildInfo buildInfo) throws FileNotFoundException {
if (mBuildHelper == null) {
mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@@ -64,7 +63,7 @@
@Override
public File resolveRelativeFilePath(IBuildInfo buildInfo, String fileName) {
try {
- File f = new File(getTestsDir((IFolderBuildInfo) buildInfo),
+ File f = new File(getTestsDir(buildInfo),
String.format("%s%s", fileName, mAppendBitness ? mAbi.getBitness() : ""));
CLog.logAndDisplay(LogLevel.ERROR, "Copying from %s", f.getAbsolutePath());
return f;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
new file mode 100644
index 0000000..cea3136
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/LocationCheck.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+/**
+ * Checks that location is enabled for GPS or Network before running a compatibility test
+ */
+@OptionClass(alias="location-check")
+public class LocationCheck extends SettingsPreparer {
+
+ private static final String LOCATION_SETTING = "location_providers_allowed";
+
+ private static final String GPS = "gps";
+ private static final String NETWORK = "network";
+
+ private static final String GPS_FEATURE = "android.hardware.location.gps";
+ private static final String NETWORK_FEATURE = "android.hardware.location.network";
+
+
+ private boolean hasLocationFeature(ITestDevice device) throws DeviceNotAvailableException {
+ String adbFeatures = device.executeShellCommand("pm list features");
+ return (adbFeatures.contains(GPS_FEATURE) || adbFeatures.contains(NETWORK_FEATURE));
+ }
+
+ @Override
+ public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+
+ if (!hasLocationFeature(device)) {
+ return; // skip this precondition if required location feature is not present
+ }
+
+ mSettingName = LOCATION_SETTING;
+ mSettingType = SettingsPreparer.SettingType.SECURE;
+ mExpectedSettingValues.add(NETWORK);
+ mExpectedSettingValues.add(GPS);
+ mExpectedSettingValues.add(String.format("%s,%s", GPS, NETWORK));
+ mExpectedSettingValues.add(String.format("%s,%s", NETWORK, GPS));
+ mFailureMessage = "Location services must be enabled via GPS or Network in order to " +
+ "successfully run the test suite";
+ super.run(device, buildInfo);
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
index 60b6d31..7b20997 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/ResultFilePuller.java
@@ -17,7 +17,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.OptionClass;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -78,8 +77,7 @@
@Override
public void tearDown(ITestDevice device, IBuildInfo buildInfo, Throwable e)
throws DeviceNotAvailableException {
- CompatibilityBuildHelper buildHelper =
- new CompatibilityBuildHelper((IFolderBuildInfo) buildInfo);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(buildInfo);
try {
File resultDir = buildHelper.getResultDir();
if (mDestDir != null) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
index 6d82f7a..f21ef39 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/SettingsPreparer.java
@@ -38,12 +38,15 @@
SYSTEM;
}
- @Option(name = "device-setting", description = "The setting on the device to be checked",
- mandatory = true)
+ /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
+ * the SettingsPreparer class can define mSettingName at runtime */
+ @Option(name = "device-setting", description = "The setting on the device to be checked")
protected String mSettingName = null;
+ /* This option must be defined, but is not explicitly marked mandatory, as subclasses of
+ * the SettingsPreparer class can define mSettingType at runtime */
@Option(name = "setting-type",
- description = "If the setting is 'secure', 'global', or 'system'", mandatory = true)
+ description = "If the setting is 'secure', 'global', or 'system'")
protected SettingType mSettingType = null;
@Option(name = "set-value", description = "The value to be set for the setting")
@@ -52,10 +55,23 @@
@Option(name = "expected-values", description = "The set of expected values of the setting")
protected List<String> mExpectedSettingValues = new ArrayList<String>();
+ @Option(name = "failure-message", description = "The text printed for an unexpected value")
+ protected String mFailureMessage = null;
+
@Override
public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
+ if (mSettingName == null) {
+ throw new TargetSetupError("The \"device-setting\" option must be defined for the " +
+ "SettingsPreparer class");
+ }
+
+ if (mSettingType == null) {
+ throw new TargetSetupError("The \"setting-type\" option must be defined for the " +
+ "SettingsPreparer class");
+ }
+
/* At least one of the options "set-value" and "expected-values" must be set */
if (mSetValue == null && mExpectedSettingValues.isEmpty()) {
throw new TargetSetupError("At least one of the options \"set-value\" and " +
@@ -93,9 +109,12 @@
/* Case 3: Only expected-values given */
String currentSettingValue = device.executeShellCommand(shellCmdGet).trim();
if (!mExpectedSettingValues.contains(currentSettingValue)) {
- throw new TargetSetupError(
- String.format("Device setting \"%s\" returned \"%s\", not found in %s",
- mSettingName, currentSettingValue, mExpectedSettingValues.toString()));
+ if (mFailureMessage == null) {
+ mFailureMessage = String.format(
+ "Device setting \"%s\" returned \"%s\", not found in %s",
+ mSettingName, currentSettingValue, mExpectedSettingValues.toString());
+ }
+ throw new TargetSetupError(mFailureMessage);
}
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
new file mode 100644
index 0000000..9745179
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/StayAwakePreparer.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionClass;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.Arrays;
+
+/**
+ * Modifies the 'Stay Awake' setting of the device, so that the device's screen stays on
+ * whenever charging via USB
+ */
+@OptionClass(alias="stay-awake-preparer")
+public class StayAwakePreparer extends SettingsPreparer {
+
+ private static final String STAY_AWAKE_SETTING = "stay_on_while_plugged_in";
+
+ /*
+ * Values that are appropriate for the "Stay Awake" setting while running compatibility tests:
+ * (the second bit must be 'on' to allow screen to stay awake while charging via USB)
+ * 2 - Stay awake while charging via USB
+ * 3 - Stay awake while changing via USB or AC
+ * 6 - Stay awake while charging via USB or Wireless
+ * 7 - Stay awake while charging via USB or AC or Wireless
+ */
+ private static final String[] STAY_AWAKE_VALUES = new String[] {"2", "3", "6", "7"};
+ private static final String DEFAULT_VALUE = "2";
+
+ @Override
+ public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+
+ mSettingName = STAY_AWAKE_SETTING;
+ mSettingType = SettingsPreparer.SettingType.GLOBAL;
+ mSetValue = DEFAULT_VALUE;
+ for (String value : STAY_AWAKE_VALUES) {
+ mExpectedSettingValues.add(value);
+ }
+ super.run(device, buildInfo);
+ }
+
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
new file mode 100644
index 0000000..54b6bc0
--- /dev/null
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/TokenRequirement.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compatibility.common.tradefed.targetprep;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.targetprep.BuildError;
+import com.android.tradefed.targetprep.ITargetPreparer;
+import com.android.tradefed.targetprep.TargetSetupError;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * An {@link ITargetPreparer} that allows a test module to specify tokens that a device must have
+ * to run the tests contained.
+ *
+ * A token is string that is required by a test module and given to a device by the user, they are
+ * used by the scheduler to ensure tests are scheduled on the correct devices. Eg if the user is
+ * sharding the innvocation across 10 devices, they will not want to put a SIM card in every device,
+ * instead they can use a single SIM card and use tokens to tell the scheduler which device should
+ * be used to run the SIM card tests.
+ */
+public class TokenRequirement implements ITargetPreparer {
+
+ @Option(name = "token", description = "The token a device must have to run this module")
+ private Set<String> mTokens = new HashSet<>();
+
+ @Override
+ public void setUp(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
+ BuildError, DeviceNotAvailableException {
+ throw new TargetSetupError("TokenRequirement is not expected to run");
+ }
+
+ /**
+ * @return the {@link Set} of tokens required by this module.
+ */
+ public Set<String> getTokens() {
+ return mTokens;
+ }
+}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
index b13a2a8..0100969 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/targetprep/WifiCheck.java
@@ -40,6 +40,8 @@
@OptionClass(alias="wifi-check")
public class WifiCheck extends PreconditionPreparer {
+ private static final String WIFI_FEATURE = "android.hardware.wifi";
+
@Option(name = "wifi-ssid", description = "Name of the WiFi network with which to connect")
protected String mWifiSsid = null;
@@ -47,9 +49,19 @@
description = "The WPA-PSK associated with the wifi-ssid option")
protected String mWifiPsk = null;
+ private boolean hasWifiFeature(ITestDevice device) throws DeviceNotAvailableException {
+ String pmFeatures = device.executeShellCommand("pm list features");
+ return pmFeatures.contains(WIFI_FEATURE);
+ }
+
@Override
public void run(ITestDevice device, IBuildInfo buildInfo) throws TargetSetupError,
BuildError, DeviceNotAvailableException {
+
+ if(!hasWifiFeature(device)) {
+ return; // skip this precondition check if device doesn't support wifi
+ }
+
if (mWifiSsid == null) { // no connection to create, check for existing connectivity
if (!device.checkConnectivity()) {
throw new TargetSetupError("Device has no network connection, no ssid provided");
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
index 1454aa0..e6ae2ad 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/CompatibilityTest.java
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package com.android.compatibility.common.tradefed.testtype;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
@@ -27,7 +28,6 @@
import com.android.compatibility.common.util.TestStatus;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.config.OptionClass;
@@ -42,6 +42,7 @@
import com.android.tradefed.testtype.IRemoteTest;
import com.android.tradefed.testtype.IShardableTest;
import com.android.tradefed.util.AbiFormatter;
+import com.android.tradefed.util.ArrayUtil;
import java.io.FileNotFoundException;
import java.util.ArrayList;
@@ -54,7 +55,7 @@
/**
* A Test for running Compatibility Suites
*/
-@OptionClass(alias="compatibility-test")
+@OptionClass(alias = "compatibility")
public class CompatibilityTest implements IDeviceTest, IShardableTest, IBuildReceiver {
public static final String INCLUDE_FILTER_OPTION = "include-filter";
@@ -62,16 +63,19 @@
private static final String PLAN_OPTION = "plan";
private static final String MODULE_OPTION = "module";
private static final String TEST_OPTION = "test";
+ private static final String MODULE_ARG_OPTION = "module-arg";
+ private static final String TEST_ARG_OPTION = "test-arg";
public static final String RETRY_OPTION = "retry";
private static final String ABI_OPTION = "abi";
private static final String SHARD_OPTION = "shard";
public static final String SKIP_DEVICE_INFO_OPTION = "skip-device-info";
public static final String SKIP_PRECONDITIONS_OPTION = "skip-preconditions";
+ public static final String DEVICE_TOKEN_OPTION = "device-token";
private static final String URL = "dynamic-config-url";
private static final TestStatus[] RETRY_TEST_STATUS = new TestStatus[] {
- TestStatus.FAIL,
- TestStatus.NOT_EXECUTED
+ TestStatus.FAIL,
+ TestStatus.NOT_EXECUTED
};
@Option(name = PLAN_OPTION,
@@ -101,6 +105,18 @@
importance = Importance.IF_UNSET)
private String mTestName = null;
+ @Option(name = MODULE_ARG_OPTION,
+ description = "the arguments to pass to a module. The expected format is"
+ + "\"<module-name>:<arg-name>:<arg-value>\"",
+ importance = Importance.ALWAYS)
+ private List<String> mModuleArgs = new ArrayList<>();
+
+ @Option(name = TEST_ARG_OPTION,
+ description = "the arguments to pass to a test. The expected format is"
+ + "\"<test-class>:<arg-name>:<arg-value>\"",
+ importance = Importance.ALWAYS)
+ private List<String> mTestArgs = new ArrayList<>();
+
@Option(name = RETRY_OPTION,
shortName = 'r',
description = "retry a previous session.",
@@ -121,55 +137,55 @@
description = "Specify the url for override config")
private String mURL;
- @Option(name = SKIP_DEVICE_INFO_OPTION, description =
- "Whether device info collection should be skipped")
+ @Option(name = SKIP_DEVICE_INFO_OPTION,
+ description = "Whether device info collection should be skipped")
private boolean mSkipDeviceInfo = false;
- @Option(name = SKIP_PRECONDITIONS_OPTION, description =
- "Whether preconditions should be skipped")
+ @Option(name = SKIP_PRECONDITIONS_OPTION,
+ description = "Whether preconditions should be skipped")
private boolean mSkipPreconditions = false;
- @Option(name = "bugreport-on-failure", description =
- "Take a bugreport on every test failure. " +
- "Warning: can potentially use a lot of disk space.")
+ @Option(name = DEVICE_TOKEN_OPTION,
+ description = "Holds the devices' tokens, used when scheduling tests that have"
+ + "prerequisits such as requiring a SIM card. Format is <serial>:<token>",
+ importance = Importance.ALWAYS)
+ private List<String> mDeviceTokens = new ArrayList<>();
+
+ @Option(name = "bugreport-on-failure",
+ description = "Take a bugreport on every test failure. " +
+ "Warning: can potentially use a lot of disk space.")
private boolean mBugReportOnFailure = false;
- @Option(name = "logcat-on-failure", description =
- "Take a logcat snapshot on every test failure.")
+ @Option(name = "logcat-on-failure",
+ description = "Take a logcat snapshot on every test failure.")
private boolean mLogcatOnFailure = false;
- @Option(name = "screenshot-on-failure", description =
- "Take a screenshot on every test failure.")
+ @Option(name = "screenshot-on-failure",
+ description = "Take a screenshot on every test failure.")
private boolean mScreenshotOnFailure = false;
- private int mShardAssignment;
private int mTotalShards;
private ITestDevice mDevice;
- private IFolderBuildInfo mBuild;
+ private IBuildInfo mBuild;
private CompatibilityBuildHelper mBuildHelper;
- private List<IModuleDef> mModules = new ArrayList<>();
- private int mLastModuleIndex = 0;
/**
- * Create a new {@link CompatibilityTest} that will run the default list of modules.
+ * Create a new {@link CompatibilityTest} that will run the default list of
+ * modules.
*/
public CompatibilityTest() {
- this(0 /*shardAssignment*/, 1 /*totalShards*/);
+ this(1 /* totalShards */);
}
/**
- * Create a new {@link CompatibilityTest} that will run a sublist of modules.
+ * Create a new {@link CompatibilityTest} that will run a sublist of
+ * modules.
*/
- public CompatibilityTest(int shardAssignment, int totalShards) {
- if (shardAssignment < 0) {
- throw new IllegalArgumentException(
- "shardAssignment cannot be negative. found:" + shardAssignment);
- }
+ public CompatibilityTest(int totalShards) {
if (totalShards < 1) {
throw new IllegalArgumentException(
- "shardAssignment must be at least 1. found:" + totalShards);
+ "Must be at least 1 shard. Given:" + totalShards);
}
- mShardAssignment = shardAssignment;
mTotalShards = totalShards;
}
@@ -194,7 +210,7 @@
*/
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = (IFolderBuildInfo) buildInfo;
+ mBuild = buildInfo;
mBuildHelper = new CompatibilityBuildHelper(mBuild);
mBuildHelper.init(mSuitePlan, mURL);
}
@@ -205,63 +221,85 @@
@Override
public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
try {
- Set<IAbi> abiSet = getAbis();
- if (abiSet == null || abiSet.isEmpty()) {
- if (mAbiName == null) {
- throw new IllegalArgumentException("Could not get device's ABIs");
- } else {
- throw new IllegalArgumentException(String.format("Device %s does't support %s",
- mDevice.getSerialNumber(), mAbiName));
+ IModuleRepo moduleRepo = ModuleRepo.getInstance();
+ // Synchronized so only one shard enters and sets up the moduleRepo. When the other
+ // shards enter after this, moduleRepo is already initialized so they dont do anything
+ synchronized (moduleRepo) {
+ if (!moduleRepo.isInitialized()) {
+ setupFilters();
+ // Initialize the repository, {@link CompatibilityBuildHelper#getTestsDir} can
+ // throw a {@link FileNotFoundException}
+ moduleRepo.initialize(mTotalShards, mBuildHelper.getTestsDir(), getAbis(),
+ mDeviceTokens, mTestArgs, mModuleArgs, mIncludeFilters,
+ mExcludeFilters, mBuild);
}
}
- CLog.logAndDisplay(LogLevel.INFO, "ABIs: %s", abiSet);
- setupTestModules(abiSet);
-
- // TODO(stuartscott): Enable skipping of deviceinfo
- // if (mSkipDeviceInfo) {
- // remove device info from modules
- // }
+ // Get the tests to run in this shard
+ List<IModuleDef> modules = moduleRepo.getModules(getDevice().getSerialNumber());
listener = new FailureListener(listener, getDevice(), mBugReportOnFailure,
mLogcatOnFailure, mScreenshotOnFailure);
- int moduleCount = mModules.size();
- CLog.logAndDisplay(LogLevel.INFO, "Start test run of %d module%s", moduleCount,
- (moduleCount > 1) ? "s" : "");
+ int moduleCount = modules.size();
+ CLog.logAndDisplay(LogLevel.INFO, "Starting %d module%s on %s", moduleCount,
+ (moduleCount > 1) ? "s" : "", mDevice.getSerialNumber());
// Set values and run preconditions
- for (int i = mLastModuleIndex; i < moduleCount; i++) {
- IModuleDef module = mModules.get(i);
+ for (int i = 0; i < moduleCount; i++) {
+ IModuleDef module = modules.get(i);
module.setBuild(mBuild);
module.setDevice(mDevice);
module.prepare(mSkipPreconditions);
}
// Run the tests
- for (int i = mLastModuleIndex; i < moduleCount; i++) {
- mModules.get(i).run(listener);
- // Track of the last complete test package index for resume
- mLastModuleIndex = i;
+ for (int i = 0; i < moduleCount; i++) {
+ modules.get(i).run(listener);
}
} catch (DeviceNotAvailableException e) {
// Pass up
throw e;
- } catch (RuntimeException e) {
+ } catch (FileNotFoundException | RuntimeException e) {
CLog.logAndDisplay(LogLevel.ERROR, "Exception: %s", e.getMessage());
CLog.e(e);
} catch (Error e) {
CLog.logAndDisplay(LogLevel.ERROR, "Error: %s", e.getMessage());
CLog.e(e);
+ } finally {
+ ModuleRepo.tearDown();
}
}
/**
- * Set {@code mModules} to the list of test modules to run.
- * @param abis
+ * Gets the set of ABIs supported by both Compatibility and the device under test
+ *
+ * @return The set of ABIs to run the tests on
+ * @throws DeviceNotAvailableException
*/
- private void setupTestModules(Set<IAbi> abis) {
- if (!mModules.isEmpty()) {
- CLog.d("Resume tests using existing module list");
- return;
+ Set<IAbi> getAbis() throws DeviceNotAvailableException {
+ Set<IAbi> abis = new HashSet<>();
+ for (String abi : AbiFormatter.getSupportedAbis(mDevice, "")) {
+ // Only test against ABIs supported by Compatibility, and if the
+ // --abi option was given, it must match.
+ if (AbiUtils.isAbiSupportedByCompatibility(abi)
+ && (mAbiName == null || mAbiName.equals(abi))) {
+ abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
+ }
}
+ if (abis == null || abis.isEmpty()) {
+ if (mAbiName == null) {
+ throw new IllegalArgumentException("Could not get device's ABIs");
+ } else {
+ throw new IllegalArgumentException(String.format(
+ "Device %s doesn't support %s", mDevice.getSerialNumber(), mAbiName));
+ }
+ }
+ return abis;
+ }
+
+ /**
+ * Sets the include/exclude filters up based on if a module name was given or whether this is a
+ * retry run.
+ */
+ void setupFilters() {
if (mRetrySessionId != null) {
// We're retrying so clear the filters
mIncludeFilters.clear();
@@ -287,69 +325,57 @@
for (TestStatus status : RETRY_TEST_STATUS) {
for (ITestResult r : cr.getResults(status)) {
// Create the filter for the test to be run.
- mIncludeFilters.add(new TestFilter(module.getAbi(), module.getName(),
- r.getFullName()).toString());
+ TestFilter filter = new TestFilter(
+ module.getAbi(), module.getName(), r.getFullName());
+ mIncludeFilters.add(filter.toString());
+ // Reset the result so that the test gets retried.
+ r.reset();
}
}
}
}
- }
- if (mModuleName != null) {
+ } else if (mModuleName != null) {
mIncludeFilters.clear();
- mIncludeFilters.add(new TestFilter(mAbiName, mModuleName, mTestName).toString());
- if (mTestName != null) {
- // We're filtering it down to the lowest level, no need to give excludes
- mExcludeFilters.clear();
- } else {
- // If we dont specify a test name, we only want to run this module with any
- // exclusions defined by the plan as long as they dont exclude the whole module.
- List<String> excludeFilters = new ArrayList<>();
- for (String excludeFilter : mExcludeFilters) {
- TestFilter filter = TestFilter.createFrom(excludeFilter);
- String name = filter.getName();
- // Add the filter if it applies to this module, and it has a test name
- if ((mModuleName.equals(name) || mModuleName.matches(name) ||
- name.matches(mModuleName)) && filter.getTest() != null) {
- excludeFilters.add(excludeFilter);
+ try {
+ List<String> modules = ModuleRepo.getModuleNamesMatching(
+ mBuildHelper.getTestsDir(), mModuleName);
+ if (modules.size() == 0) {
+ throw new IllegalArgumentException(
+ String.format("No modules found matching %s", mModuleName));
+ } else if (modules.size() > 1) {
+ throw new IllegalArgumentException(String.format(
+ "Multiple modules found matching %s:\n%s\nWhich one did you mean?\n",
+ mModuleName, ArrayUtil.join("\n", modules)));
+ } else {
+ String module = modules.get(0);
+ mIncludeFilters.add(new TestFilter(mAbiName, module, mTestName).toString());
+ if (mTestName != null) {
+ // We're filtering it down to the lowest level, no need to give excludes
+ mExcludeFilters.clear();
+ } else {
+ // If we dont specify a test name, we only want to run this module with any
+ // previous exclusions as long as they dont exclude the whole module.
+ List<String> excludeFilters = new ArrayList<>();
+ for (String excludeFilter : mExcludeFilters) {
+ TestFilter filter = TestFilter.createFrom(excludeFilter);
+ String name = filter.getName();
+ // Add the filter if it applies to this module, and it has a test name
+ if (module.equals(name) && filter.getTest() != null) {
+ excludeFilters.add(excludeFilter);
+ }
+ }
+ mExcludeFilters = excludeFilters;
}
}
- mExcludeFilters = excludeFilters;
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ } else {
+ // If a module has an arg, assume it's included
+ for (String arg : mModuleArgs) {
+ mIncludeFilters.add(arg.split(":")[0]);
}
}
- try {
- // Collect ALL tests
- IModuleRepo testRepo = new ModuleRepo(mBuildHelper.getTestsDir(), abis);
- List<IModuleDef> modules = testRepo.getModules(mIncludeFilters, mExcludeFilters);
-
- // Filter by shard
- int numTestmodules = modules.size();
- int totalShards = Math.min(mTotalShards, numTestmodules);
-
- mModules.clear();
- for (int i = mShardAssignment; i < numTestmodules; i += totalShards) {
- mModules.add(modules.get(i));
- }
- } catch (FileNotFoundException e) {
- CLog.e(e);
- }
- }
-
- /**
- * Gets the set of ABIs supported by both Compatibility and the device under test
- * @return The set of ABIs to run the tests on
- * @throws DeviceNotAvailableException
- */
- Set<IAbi> getAbis() throws DeviceNotAvailableException {
- Set<IAbi> abis = new HashSet<>();
- for (String abi : AbiFormatter.getSupportedAbis(mDevice, "")) {
- // Only test against ABIs supported by Compatibility, and if the --abi option was given,
- // it must match.
- if (AbiUtils.isAbiSupportedByCompatibility(abi)
- && (mAbiName == null || mAbiName.equals(abi))) {
- abis.add(new Abi(abi, AbiUtils.getBitness(abi)));
- }
- }
- return abis;
}
/**
@@ -362,11 +388,11 @@
}
List<IRemoteTest> shardQueue = new LinkedList<>();
- for (int shardAssignment = 0; shardAssignment < mShards; shardAssignment++) {
- CompatibilityTest test = new CompatibilityTest(shardAssignment, mShards /* total */);
+ for (int i = 0; i < mShards; i++) {
+ CompatibilityTest test = new CompatibilityTest(mShards);
OptionCopier.copyOptionsNoThrow(this, test);
- // Set the shard count because the copy option on the previous line copies
- // over the mShard value
+ // Set the shard count because the copy option on the previous line
+ // copies over the mShard value
test.mShards = 0;
shardQueue.add(test);
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
index 432b865..f8520b2 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleDef.java
@@ -16,14 +16,12 @@
package com.android.compatibility.common.tradefed.testtype;
import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IDeviceTest;
import com.android.tradefed.testtype.IRemoteTest;
-import java.util.List;
-import java.util.regex.Pattern;
+import java.util.Set;
/**
* Container for Compatibility test info.
@@ -46,14 +44,14 @@
IAbi getAbi();
/**
- * @return a list of preparers used for setup or teardown of test cases in this module
+ * @return the {@link Set} of tokens a device must have in order to run this module.
*/
- List<ITargetPreparer> getPreparers();
+ Set<String> getTokens();
/**
- * @return a {@link List} of {@link IRemoteTest}s to run the test module.
+ * @return the {@link IRemoteTest} that runs the tests.
*/
- List<IRemoteTest> getTests();
+ IRemoteTest getTest();
/**
* Adds a filter to include a specific test
@@ -72,11 +70,6 @@
void addExcludeFilter(String name);
/**
- * @return true iff this module's name matches the give regular expression pattern.
- */
- boolean nameMatches(Pattern pattern);
-
- /**
* Runs the module's precondition checks and setup tasks.
*/
void prepare(boolean skipPrep) throws DeviceNotAvailableException;
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
index 40e944b..2e6b450 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/IModuleRepo.java
@@ -15,8 +15,10 @@
*/
package com.android.compatibility.common.tradefed.testtype;
-import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IAbi;
+import java.io.File;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -27,39 +29,49 @@
public interface IModuleRepo {
/**
- * Get a {@link IModuleDef} given an id.
- *
- * @param id the id of the module (created by {@link AbiUtils#createId(String, String)})
+ * @return true if this repository has been initialized.
*/
- IModuleDef getModule(String id);
+ boolean isInitialized();
/**
- * @return a {@link Map} of all modules in repo.
+ * Initializes the repository.
*/
- Map<String, IModuleDef> getModules();
+ void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
+ List<String> testArgs, List<String> moduleArgs, List<String> mIncludeFilters,
+ List<String> mExcludeFilters, IBuildInfo buildInfo);
/**
- * @return a sorted {@link List} of {@link IModuleDef}s given the filters.
+ * @return a {@link Map} of all modules to run on the device referenced by the given serial.
*/
- List<IModuleDef> getModules(List<String> includeFilters, List<String> excludeFilters);
+ List<IModuleDef> getModules(String serial);
/**
- * @return a {@link Map} of all module in repo keyed by name.
+ * @return the number of shards this repo is initialized for.
*/
- Map<String, List<IModuleDef>> getModulesByName();
+ int getNumberOfShards();
/**
- * @return a sorted {@link List} of module names.
+ * @return the maximum number of modules a shard will run.
*/
- List<String> getModuleNames();
+ int getModulesPerShard();
/**
- * @return a {@link Set} of modules names that match the given regular expression.
+ * @return the {@link Map} of device serials to tokens.
*/
- Set<String> getModulesMatching(String regex);
+ Map<String, Set<String>> getDeviceTokens();
/**
- * @return a sorted {@link List} of module ids.
+ * @return the {@link Set} of device serials that have taken their workload.
*/
- List<String> getModuleIds();
+ Set<String> getSerials();
+
+ /**
+ * @return the modules which dont have prerequisites but have not been assigned to a device.
+ */
+ Set<IModuleDef> getRemainingModules();
+
+ /**
+ * @return the modules which have prerequisites and have not been assigned to a device.
+ */
+ Set<IModuleDef> getRemainingWithTokens();
}
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
index 6524a51..b1ea78c 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/JarHostTest.java
@@ -17,7 +17,6 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.config.Option;
import com.android.tradefed.config.Option.Importance;
import com.android.tradefed.testtype.HostTest;
@@ -67,7 +66,7 @@
@Override
public void setBuild(IBuildInfo build) {
mBuild = build;
- mHelper = new CompatibilityBuildHelper((IFolderBuildInfo) build);
+ mHelper = new CompatibilityBuildHelper(build);
}
/**
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
index 1b5f915..9930f33 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleDef.java
@@ -18,6 +18,7 @@
import com.android.compatibility.common.tradefed.result.IModuleListener;
import com.android.compatibility.common.tradefed.result.ModuleListener;
import com.android.compatibility.common.tradefed.targetprep.PreconditionPreparer;
+import com.android.compatibility.common.tradefed.targetprep.TokenRequirement;
import com.android.compatibility.common.util.AbiUtils;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;
@@ -39,8 +40,9 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashSet;
import java.util.List;
-import java.util.regex.Pattern;
+import java.util.Set;
/**
* Container for Compatibility test module info.
@@ -50,7 +52,8 @@
private final String mId;
private final String mName;
private final IAbi mAbi;
- private List<IRemoteTest> mTests = null;
+ private final Set<String> mTokens = new HashSet<>();
+ private IRemoteTest mTest = null;
private List<ITargetPreparer> mPreconditions = new ArrayList<>();
private List<ITargetPreparer> mPreparers = new ArrayList<>();
private List<ITargetCleaner> mCleaners = new ArrayList<>();
@@ -59,16 +62,18 @@
private List<String> mIncludeFilters = new ArrayList<>();
private List<String> mExcludeFilters = new ArrayList<>();
- public ModuleDef(String name, IAbi abi, List<IRemoteTest> tests,
+ public ModuleDef(String name, IAbi abi, IRemoteTest test,
List<ITargetPreparer> preparers) {
mId = AbiUtils.createId(abi.getName(), name);
mName = name;
mAbi = abi;
- mTests = tests;
+ mTest = test;
for (ITargetPreparer preparer : preparers) {
// Separate preconditions from target preparers.
if (preparer instanceof PreconditionPreparer) {
mPreconditions.add(preparer);
+ } else if (preparer instanceof TokenRequirement) {
+ mTokens.addAll(((TokenRequirement) preparer).getTokens());
} else {
mPreparers.add(preparer);
}
@@ -84,6 +89,14 @@
* {@inheritDoc}
*/
@Override
+ public String toString() {
+ return mId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public String getId() {
return mId;
}
@@ -108,16 +121,16 @@
* {@inheritDoc}
*/
@Override
- public List<IRemoteTest> getTests() {
- return mTests;
+ public Set<String> getTokens() {
+ return mTokens;
}
/**
* {@inheritDoc}
*/
@Override
- public List<ITargetPreparer> getPreparers() {
- return mPreparers;
+ public IRemoteTest getTest() {
+ return mTest;
}
/**
@@ -148,14 +161,6 @@
* {@inheritDoc}
*/
@Override
- public boolean nameMatches(Pattern pattern) {
- return pattern.matcher(mName).matches();
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public void setBuild(IBuildInfo build) {
mBuild = build;
}
@@ -203,24 +208,22 @@
}
}
- // Run tests
- for (IRemoteTest test : mTests) {
- CLog.d("Test: %s", test.getClass().getSimpleName());
- if (test instanceof IAbiReceiver) {
- ((IAbiReceiver) test).setAbi(mAbi);
- }
- if (test instanceof IBuildReceiver) {
- ((IBuildReceiver) test).setBuild(mBuild);
- }
- if (test instanceof IDeviceTest) {
- ((IDeviceTest) test).setDevice(mDevice);
- }
- if (test instanceof ITestFilterReceiver) {
- ((ITestFilterReceiver) test).addAllIncludeFilters(mIncludeFilters);
- ((ITestFilterReceiver) test).addAllExcludeFilters(mExcludeFilters);
- }
- test.run(moduleListener);
+
+ CLog.d("Test: %s", mTest.getClass().getSimpleName());
+ if (mTest instanceof IAbiReceiver) {
+ ((IAbiReceiver) mTest).setAbi(mAbi);
}
+ if (mTest instanceof IBuildReceiver) {
+ ((IBuildReceiver) mTest).setBuild(mBuild);
+ }
+ if (mTest instanceof IDeviceTest) {
+ ((IDeviceTest) mTest).setDevice(mDevice);
+ }
+ if (mTest instanceof ITestFilterReceiver) {
+ ((ITestFilterReceiver) mTest).addAllIncludeFilters(mIncludeFilters);
+ ((ITestFilterReceiver) mTest).addAllExcludeFilters(mExcludeFilters);
+ }
+ mTest.run(moduleListener);
// Tear down
for (ITargetCleaner cleaner : mCleaners) {
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
index 10db046..c982990 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/testtype/ModuleRepo.java
@@ -17,25 +17,28 @@
import com.android.compatibility.common.util.AbiUtils;
import com.android.compatibility.common.util.TestFilter;
-import com.android.tradefed.config.Configuration;
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.ConfigurationException;
import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfiguration;
import com.android.tradefed.config.IConfigurationFactory;
import com.android.tradefed.log.LogUtil.CLog;
-import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IBuildReceiver;
import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
import java.io.File;
import java.io.FilenameFilter;
import java.util.ArrayList;
-import java.util.Collections;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
-import java.util.regex.Pattern;
/**
* Retrieves Compatibility test module definitions from the repository.
@@ -44,45 +47,194 @@
private static final String CONFIG_EXT = ".config";
- /** mapping of module id to definition */
- private final Map<String, IModuleDef> mModules;
- private final Set<IAbi> mAbis;
+ static IModuleRepo sInstance;
- /**
- * Creates a {@link ModuleRepo}, initialized from provided build
- */
- public ModuleRepo(File testsDir, Set<IAbi> abis) {
- this(new HashMap<String, IModuleDef>(), abis);
- parse(testsDir);
+ private int mShards;
+ private int mModulesPerShard;
+ private Set<String> mSerials = new HashSet<>();
+ private Map<String, Set<String>> mDeviceTokens = new HashMap<>();
+ private Map<String, Map<String, String>> mTestArgs = new HashMap<>();
+ private Map<String, Map<String, String>> mModuleArgs = new HashMap<>();
+ private boolean mIncludeAll;
+ private Map<String, List<TestFilter>> mIncludeFilters = new HashMap<>();
+ private Map<String, List<TestFilter>> mExcludeFilters = new HashMap<>();
+ private IConfigurationFactory mConfigFactory = ConfigurationFactory.getInstance();
+
+ private volatile boolean mInitialized = false;
+
+ // Holds all the 'normal' tests waiting to be run.
+ private Set<IModuleDef> mRemainingModules = new HashSet<>();
+ // Holds all the 'special' tests waiting to be run. Meaning the DUT must have a specific token.
+ private Set<IModuleDef> mRemainingWithTokens = new HashSet<>();
+
+ public static IModuleRepo getInstance() {
+ if (sInstance == null) {
+ sInstance = new ModuleRepo();
+ }
+ return sInstance;
+ }
+
+ public static void tearDown() {
+ sInstance = null;
}
/**
- * Creates a {@link ModuleRepo}, initialized with the given modules
+ * {@inheritDoc}
*/
- public ModuleRepo(Map<String, IModuleDef> modules, Set<IAbi> abis) {
- mModules = modules;
- mAbis = abis;
+ @Override
+ public int getNumberOfShards() {
+ return mShards;
}
/**
- * Builds mTestMap based on directory contents
+ * {@inheritDoc}
*/
- private void parse(File dir) {
- File[] configFiles = dir.listFiles(new ConfigFilter());
- IConfigurationFactory configFactory = ConfigurationFactory.getInstance();
+ @Override
+ public int getModulesPerShard() {
+ return mModulesPerShard;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Map<String, Set<String>> getDeviceTokens() {
+ return mDeviceTokens;
+ }
+
+ /**
+ * A {@link FilenameFilter} to find all modules in a directory who match the given pattern.
+ */
+ public static class NameFilter implements FilenameFilter {
+
+ private String mPattern;
+
+ public NameFilter(String pattern) {
+ mPattern = pattern;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean accept(File dir, String name) {
+ return name.contains(mPattern) && name.endsWith(CONFIG_EXT);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<String> getSerials() {
+ return mSerials;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<IModuleDef> getRemainingModules() {
+ return mRemainingModules;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Set<IModuleDef> getRemainingWithTokens() {
+ return mRemainingWithTokens;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isInitialized() {
+ return mInitialized;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void initialize(int shards, File testsDir, Set<IAbi> abis, List<String> deviceTokens,
+ List<String> testArgs, List<String> moduleArgs, List<String> includeFilters,
+ List<String> excludeFilters, IBuildInfo buildInfo) {
+ mInitialized = true;
+ mShards = shards;
+ for (String line : deviceTokens) {
+ String[] parts = line.split(":");
+ if (parts.length == 2) {
+ String key = parts[0];
+ String value = parts[1];
+ Set<String> list = mDeviceTokens.get(key);
+ if (list == null) {
+ list = new HashSet<>();
+ mDeviceTokens.put(key, list);
+ }
+ list.add(value);
+ } else {
+ throw new IllegalArgumentException(
+ String.format("Could not parse device token: %s", line));
+ }
+ }
+ putArgs(testArgs, mTestArgs);
+ putArgs(moduleArgs, mModuleArgs);
+ mIncludeAll = includeFilters.isEmpty();
+ // Include all the inclusions
+ addFilters(includeFilters, mIncludeFilters, abis);
+ // Exclude all the exclusions
+ addFilters(excludeFilters, mExcludeFilters, abis);
+
+ File[] configFiles = testsDir.listFiles(new ConfigFilter());
for (File configFile : configFiles) {
+ final String name = configFile.getName().replace(CONFIG_EXT, "");
+ final String[] pathArg = new String[] { configFile.getAbsolutePath() };
try {
// Invokes parser to process the test module config file
// Need to generate a different config for each ABI as we cannot guarantee the
- // configs are idempotent. This however means we parse the same file multiple times.
- for (IAbi abi : mAbis) {
- Configuration config = (Configuration) configFactory.createConfigurationFromArgs(
- new String[]{configFile.getAbsolutePath()});
- String name = configFile.getName().replace(CONFIG_EXT, "");
+ // configs are idempotent. This however means we parse the same file multiple times
+ for (IAbi abi : abis) {
+ IConfiguration config = mConfigFactory.createConfigurationFromArgs(pathArg);
+ String id = AbiUtils.createId(abi.getName(), name);
+ {
+ Map<String, String> args = new HashMap<>();
+ if (mModuleArgs.containsKey(name)) {
+ args.putAll(mModuleArgs.get(name));
+ }
+ if (mModuleArgs.containsKey(id)) {
+ args.putAll(mModuleArgs.get(id));
+ }
+ if (args != null && args.size() > 0) {
+ for (Entry<String, String> entry : args.entrySet()) {
+ config.injectOptionValue(entry.getKey(), entry.getValue());
+ }
+ }
+ }
List<IRemoteTest> tests = config.getTests();
- List<ITargetPreparer> preparers = config.getTargetPreparers();
- IModuleDef def = new ModuleDef(name, abi, tests, preparers);
- mModules.put(AbiUtils.createId(abi.getName(), name), def);
+ for (IRemoteTest test : tests) {
+ String className = test.getClass().getName();
+ Map<String, String> args = new HashMap<>();
+ if (mTestArgs.containsKey(className)) {
+ args.putAll(mTestArgs.get(className));
+ }
+ if (args != null && args.size() > 0) {
+ for (Entry<String, String> entry : args.entrySet()) {
+ config.injectOptionValue(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+ List<IRemoteTest> shardedTests = tests;
+ if (mShards > 1) {
+ shardedTests = splitShardableTests(tests, buildInfo);
+ }
+ for (IRemoteTest test : shardedTests) {
+ if (test instanceof IBuildReceiver) {
+ ((IBuildReceiver)test).setBuild(buildInfo);
+ }
+ addModuleDef(name, abi, test, pathArg);
+ }
}
} catch (ConfigurationException e) {
throw new RuntimeException(String.format("error parsing config file: %s",
@@ -91,6 +243,91 @@
}
}
+ private static List<IRemoteTest> splitShardableTests(List<IRemoteTest> tests,
+ IBuildInfo buildInfo) {
+ ArrayList<IRemoteTest> shardedList = new ArrayList<>(tests.size());
+ for (IRemoteTest test : tests) {
+ if (test instanceof IShardableTest) {
+ if (test instanceof IBuildReceiver) {
+ ((IBuildReceiver)test).setBuild(buildInfo);
+ }
+ shardedList.addAll(((IShardableTest)test).split());
+ } else {
+ shardedList.add(test);
+ }
+ }
+ return shardedList;
+ }
+
+ private static void addFilters(List<String> stringFilters,
+ Map<String, List<TestFilter>> filters, Set<IAbi> abis) {
+ for (String filterString : stringFilters) {
+ TestFilter filter = TestFilter.createFrom(filterString);
+ String abi = filter.getAbi();
+ if (abi == null) {
+ for (IAbi a : abis) {
+ addFilter(a.getName(), filter, filters);
+ }
+ } else {
+ addFilter(abi, filter, filters);
+ }
+ }
+ }
+
+ private static void addFilter(String abi, TestFilter filter,
+ Map<String, List<TestFilter>> filters) {
+ getFilter(filters, AbiUtils.createId(abi, filter.getName())).add(filter);
+ }
+
+ private static List<TestFilter> getFilter(Map<String, List<TestFilter>> filters, String id) {
+ List<TestFilter> fs = filters.get(id);
+ if (fs == null) {
+ fs = new ArrayList<>();
+ filters.put(id, fs);
+ }
+ return fs;
+ }
+
+ private void addModuleDef(String name, IAbi abi, IRemoteTest test,
+ String[] configPaths) throws ConfigurationException {
+ // Invokes parser to process the test module config file
+ IConfiguration config = mConfigFactory.createConfigurationFromArgs(configPaths);
+ addModuleDef(new ModuleDef(name, abi, test, config.getTargetPreparers()));
+ }
+
+ private void addModuleDef(IModuleDef moduleDef) {
+ String id = moduleDef.getId();
+ boolean includeModule = mIncludeAll;
+ for (TestFilter include : getFilter(mIncludeFilters, id)) {
+ String test = include.getTest();
+ if (test != null) {
+ // We're including a subset of tests
+ moduleDef.addIncludeFilter(test);
+ }
+ includeModule = true;
+ }
+ for (TestFilter exclude : getFilter(mExcludeFilters, id)) {
+ String test = exclude.getTest();
+ if (test != null) {
+ // Excluding a subset of tests, so keep module but give filter
+ moduleDef.addExcludeFilter(test);
+ } else {
+ // Excluding all tests in the module so just remove the whole thing
+ includeModule = false;
+ }
+ }
+ if (includeModule) {
+ Set<String> tokens = moduleDef.getTokens();
+ if (tokens == null || tokens.isEmpty()) {
+ mRemainingModules.add(moduleDef);
+ } else {
+ mRemainingWithTokens.add(moduleDef);
+ }
+ float numModules = mRemainingModules.size() + mRemainingWithTokens.size();
+ mModulesPerShard = (int) ((numModules / mShards) + 0.5f); // Round up
+ }
+ }
+
/**
* A {@link FilenameFilter} to find all the config files in a directory.
*/
@@ -109,146 +346,103 @@
* {@inheritDoc}
*/
@Override
- public IModuleDef getModule(String id) {
- return mModules.get(id);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Map<String, IModuleDef> getModules() {
- return mModules;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Map<String, List<IModuleDef>> getModulesByName() {
- Map<String, List<IModuleDef>> modules = new HashMap<>();
- for (IModuleDef moduleDef : mModules.values()) {
- String name = moduleDef.getName();
- List<IModuleDef> defs = modules.get(name);
- if (defs == null) {
- defs = new ArrayList<IModuleDef>();
- modules.put(name, defs);
+ public synchronized List<IModuleDef> getModules(String serial) {
+ Set<String> tokens = mDeviceTokens.get(serial);
+ List<IModuleDef> modules = getModulesWithTokens(tokens);
+ int diff = mModulesPerShard - modules.size();
+ if (diff > 0) {
+ modules.addAll(getModules(diff));
+ }
+ mSerials.add(serial);
+ if (mSerials.size() == mShards) {
+ // All shards have been given their workload.
+ if (!mRemainingWithTokens.isEmpty()) {
+ CLog.logAndDisplay(LogLevel.INFO, "Device Tokens:");
+ for (String s : mDeviceTokens.keySet()) {
+ CLog.logAndDisplay(LogLevel.INFO, "%s: %s", s, mDeviceTokens.get(s));
+ }
+ CLog.logAndDisplay(LogLevel.INFO, "Module Tokens:");
+ for (IModuleDef module : mRemainingWithTokens) {
+ CLog.logAndDisplay(LogLevel.INFO, "%s: %s", module.getId(), module.getTokens());
+ }
+ throw new IllegalArgumentException("Not all modules could be scheduled.");
}
- defs.add(moduleDef);
}
return modules;
}
/**
- * {@inheritDoc}
+ * Iterates through the remaining tests that require tokens and if the device has all the
+ * required tokens it will queue that module to run on that device, else the module gets put
+ * back into the list.
*/
- @Override
- public List<String> getModuleIds() {
- List<String> ids = new ArrayList<>(mModules.keySet());
- Collections.sort(ids);
- return ids;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public List<String> getModuleNames() {
- Set<String> names = new HashSet<>();
- for (IModuleDef moduleDef : mModules.values()) {
- names.add(moduleDef.getName());
- }
- List<String> namesList = new ArrayList<>(names);
- Collections.sort(namesList);
- return namesList;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public Set<String> getModulesMatching(String regex) {
- Set<String> names = new HashSet<>();
- Pattern pattern = Pattern.compile(regex);
- for (IModuleDef moduleDef : mModules.values()) {
- if (moduleDef.nameMatches(pattern)) {
- names.add(moduleDef.getName());
- }
- }
- return names;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public List<IModuleDef> getModules(List<String> includeFilters, List<String> excludeFilters) {
- Map<String, IModuleDef> moduleDefs = new HashMap<>();
- Set<String> ids;
- // Include all the inclusions
- for (String filterString : includeFilters) {
- TestFilter filter = TestFilter.createFrom(filterString);
- String test = filter.getTest();
- ids = getAllIds(filter);
- for (String id : ids) {
- IModuleDef module = getModule(id);
- if (test != null) {
- // We're including a subset of tests
- module.addIncludeFilter(test);
- }
- moduleDefs.put(id, module);
- }
- }
- // Exclude all the exclusions
- for (String filterString : excludeFilters) {
- TestFilter filter = TestFilter.createFrom(filterString);
- String test = filter.getTest();
- ids = getAllIds(filter);
- // Iterate through all IDs
- for (String id : ids) {
- IModuleDef module = moduleDefs.get(id);
- if (module != null) {
- if (test != null) {
- // Excluding a subset of tests, so keep module but give filter
- module.addExcludeFilter(test);
- } else {
- // Excluding all tests in the module so just remove the whole thing
- moduleDefs.remove(id);
- }
+ private List<IModuleDef> getModulesWithTokens(Set<String> tokens) {
+ List<IModuleDef> modules = new ArrayList<>();
+ if (tokens != null) {
+ Set<IModuleDef> copy = mRemainingWithTokens;
+ mRemainingWithTokens = new HashSet<>();
+ for (IModuleDef module : copy) {
+ // If a device has all the tokens required by the module then it can run it.
+ if (tokens.containsAll(module.getTokens())) {
+ modules.add(module);
+ } else {
+ mRemainingWithTokens.add(module);
}
}
}
- if (moduleDefs.isEmpty()) {
- throw new IllegalStateException("Nothing to do. Use 'list modules' to see available"
- + " modules, and 'list results' to see available sessions to retry.");
- }
- // Note: run() relies on the fact that the list is reliably sorted for sharding purposes
- List<IModuleDef> sortedModuleDefs = new ArrayList<>(moduleDefs.values());
- Collections.sort(sortedModuleDefs);
- return sortedModuleDefs;
+ return modules;
}
/**
- * Returns all IDs matching the given filter.
+ * Returns a {@link List} of modules that do not require tokens.
*/
- private Set<String> getAllIds(TestFilter filter) {
- String abi = filter.getAbi();
- String name = filter.getName();
- Set<String> filteredNames = getModulesMatching(name);
- if (filteredNames.isEmpty()) {
- throw new IllegalArgumentException(String.format(
- "Not modules matching %s. Use 'list modules' to see available modules.",
- filter.getName()));
+ private List<IModuleDef> getModules(int count) {
+ int size = mRemainingModules.size();
+ if (count >= size) {
+ count = size;
}
- Set<String> ids = new HashSet<>();
- for (String module : filteredNames) {
- if (abi != null) {
- ids.add(AbiUtils.createId(abi, module));
+ Set<IModuleDef> copy = mRemainingModules;
+ mRemainingModules = new HashSet<>();
+ List<IModuleDef> modules = new ArrayList<>();
+ for (IModuleDef module : copy) {
+ // Give 'count' modules to this shard and then put the rest back in the queue.
+ if (count > 0) {
+ modules.add(module);
+ count--;
} else {
- // ABI not specified, test on all ABIs
- for (IAbi a : mAbis) ids.add(AbiUtils.createId(a.getName(), module));
+ mRemainingModules.add(module);
}
}
- return ids;
+ return modules;
+ }
+
+ /**
+ * @return the {@link List} of modules whose name contains the given pattern.
+ */
+ public static List<String> getModuleNamesMatching(File directory, String pattern) {
+ String[] names = directory.list(new NameFilter(pattern));
+ List<String> modules = new ArrayList<String>(names.length);
+ for (String name : names) {
+ int index = name.indexOf(CONFIG_EXT);
+ if (index > 0) {
+ modules.add(name.substring(0, index));
+ }
+ }
+ return modules;
+ }
+
+ private static void putArgs(List<String> args, Map<String, Map<String, String>> argsMap) {
+ for (String arg : args) {
+ String[] parts = arg.split(":");
+ String target = parts[0];
+ String key = parts[1];
+ String value = parts[2];
+ Map<String, String> map = argsMap.get(target);
+ if (map == null) {
+ map = new HashMap<>();
+ argsMap.put(target, map);
+ }
+ map.put(key, value);
+ }
}
}
diff --git a/common/host-side/tradefed/tests/run_tests.sh b/common/host-side/tradefed/tests/run_tests.sh
new file mode 100755
index 0000000..1d1940d
--- /dev/null
+++ b/common/host-side/tradefed/tests/run_tests.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-common-util-hostsidelib\
+ compatibility-common-util-tests\
+ compatibility-host-util\
+ compatibility-host-util-tests\
+ compatibility-mock-tradefed\
+ compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.tradefed.UnitTests" "${JARS}" "${@}"
+
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
index 99847f5..55d15dd 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/build/CompatibilityBuildHelperTest.java
@@ -16,7 +16,7 @@
package com.android.compatibility.common.tradefed.build;
-import com.android.tradefed.build.IFolderBuildInfo;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.util.FileUtil;
import junit.framework.TestCase;
@@ -40,14 +40,14 @@
private File mRoot = null;
private File mBase = null;
private File mTests = null;
- private IFolderBuildInfo mBuild;
+ private IBuildInfo mBuild;
private CompatibilityBuildHelper mHelper;
@Override
public void setUp() throws Exception {
mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
- mBuild = (IFolderBuildInfo) provider.getBuild();
+ mBuild = provider.getBuild();
mHelper = new CompatibilityBuildHelper(mBuild);
}
@@ -79,8 +79,7 @@
public void testProperty() throws Exception {
setProperty(null);
CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
- IFolderBuildInfo info = (IFolderBuildInfo) provider.getBuild();
- CompatibilityBuildHelper helper = new CompatibilityBuildHelper(info);
+ CompatibilityBuildHelper helper = new CompatibilityBuildHelper(provider.getBuild());
try {
// Should fail with root unset
helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
index 5cdc13f..3fcf8b5 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ResultReporterTest.java
@@ -24,8 +24,8 @@
import com.android.compatibility.common.util.ITestResult;
import com.android.compatibility.common.util.TestStatus;
import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.tradefed.build.FolderBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
+import com.android.tradefed.build.BuildInfo;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.OptionSetter;
import com.android.tradefed.util.FileUtil;
@@ -66,7 +66,7 @@
"newrule_green.png"};
private ResultReporter mReporter;
- private IFolderBuildInfo mBuildInfo;
+ private IBuildInfo mBuildInfo;
private CompatibilityBuildHelper mBuildHelper;
private File mRoot = null;
@@ -84,7 +84,7 @@
mTests = new File(mBase, TESTCASES);
mTests.mkdirs();
System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
- mBuildInfo = new FolderBuildInfo(BUILD_NUMBER, "", "");
+ mBuildInfo = new BuildInfo(BUILD_NUMBER, "", "");
mBuildHelper = new CompatibilityBuildHelper(mBuildInfo);
mBuildHelper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
index 899ac2c..8714c1d 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleDefTest.java
@@ -16,14 +16,10 @@
package com.android.compatibility.common.tradefed.testtype;
+import com.android.compatibility.common.tradefed.util.NoOpTestInvocationListener;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.ddmlib.testrunner.TestIdentifier;
-import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.result.ITestInvocationListener;
-import com.android.tradefed.result.InputStreamSource;
-import com.android.tradefed.result.LogDataType;
-import com.android.tradefed.result.TestSummary;
import com.android.tradefed.targetprep.ITargetPreparer;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IRemoteTest;
@@ -33,8 +29,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.Map;
-import java.util.regex.Pattern;
public class ModuleDefTest extends TestCase {
@@ -47,31 +41,17 @@
public void testAccessors() throws Exception {
IAbi abi = new Abi(ABI, "");
- IModuleDef def = new ModuleDef(NAME, abi, new ArrayList<IRemoteTest>(),
- new ArrayList<ITargetPreparer>());
+ MockRemoteTest mockTest = new MockRemoteTest();
+ IModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
assertEquals("Incorrect ID", ID, def.getId());
assertEquals("Incorrect ABI", ABI, def.getAbi().getName());
assertEquals("Incorrect Name", NAME, def.getName());
- assertNotNull("Expected tests", def.getTests());
- assertNotNull("Expected preparers", def.getPreparers());
- }
-
- public void testNameMatching() throws Exception {
- IAbi abi = new Abi(ABI, "");
- ModuleDef def = new ModuleDef(NAME, abi, new ArrayList<IRemoteTest>(),
- new ArrayList<ITargetPreparer>());
- assertTrue("Expected equality", def.nameMatches(Pattern.compile(NAME)));
- assertTrue("Expected regex equality", def.nameMatches(Pattern.compile(".*")));
- assertFalse("Expected no match to ID", def.nameMatches(Pattern.compile(ID)));
- assertFalse("Expected no match to empty", def.nameMatches(Pattern.compile("")));
}
public void testAddFilters() throws Exception {
IAbi abi = new Abi(ABI, "");
- List<IRemoteTest> tests = new ArrayList<>();
MockRemoteTest mockTest = new MockRemoteTest();
- tests.add(mockTest);
- ModuleDef def = new ModuleDef(NAME, abi, tests, new ArrayList<ITargetPreparer>());
+ ModuleDef def = new ModuleDef(NAME, abi, mockTest, new ArrayList<ITargetPreparer>());
def.addIncludeFilter(CLASS);
def.addExcludeFilter(TEST_1);
MockListener mockListener = new MockListener();
@@ -114,76 +94,5 @@
}
- private class MockListener implements ITestInvocationListener {
-
- @Override
- public void invocationStarted(IBuildInfo buildInfo) {
- // Do nothing
- }
-
- @Override
- public void testRunStarted(String name, int numTests) {
- // Do nothing
- }
-
- @Override
- public void testStarted(TestIdentifier test) {
- // Do nothing
- }
-
- @Override
- public void testEnded(TestIdentifier test, Map<String, String> metrics) {
- // Do nothing
- }
-
- @Override
- public void testIgnored(TestIdentifier test) {
- // Do nothing
- }
-
- @Override
- public void testFailed(TestIdentifier test, String trace) {
- // Do nothing
- }
-
- @Override
- public void testAssumptionFailure(TestIdentifier test, String trace) {
- // Do nothing
- }
-
- @Override
- public void testRunStopped(long elapsedTime) {
- // Do nothing
- }
-
- @Override
- public void testRunEnded(long elapsedTime, Map<String, String> metrics) {
- // Do nothing
- }
-
- @Override
- public void testRunFailed(String id) {
- // Do nothing
- }
-
- @Override
- public TestSummary getSummary() {
- return null;
- }
-
- @Override
- public void invocationEnded(long elapsedTime) {
- // Do nothing
- }
-
- @Override
- public void invocationFailed(Throwable cause) {
- // Do nothing
- }
-
- @Override
- public void testLog(String name, LogDataType type, InputStreamSource stream) {
- // Do nothing
- }
- }
+ private class MockListener extends NoOpTestInvocationListener {}
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
index bff1072..65702fe 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ModuleRepoTest.java
@@ -16,16 +16,227 @@
package com.android.compatibility.common.tradefed.testtype;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.tradefed.testtype.ModuleRepo.ConfigFilter;
+import com.android.compatibility.common.tradefed.testtype.IModuleDef;
+import com.android.compatibility.common.util.AbiUtils;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.testtype.IAbi;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+import com.android.tradefed.util.FileUtil;
+
import junit.framework.TestCase;
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
public class ModuleRepoTest extends TestCase {
+ private static final String TOKEN =
+ "<target_preparer class=\"com.android.compatibility.common.tradefed.targetprep.TokenRequirement\">\n"
+ + "<option name=\"token\" value=\"%s\" />\n"
+ + "</target_preparer>\n";
+ private static final String CONFIG =
+ "<configuration description=\"Auto Generated File\">\n" +
+ "%s" +
+ "<test class=\"com.android.compatibility.common.tradefed.testtype.%s\">\n" +
+ "<option name=\"module\" value=\"%s\" />" +
+ "</test>\n" +
+ "</configuration>";
+ private static final String FOOBAR_TOKEN = "foobar";
+ private static final String SERIAL1 = "abc";
+ private static final String SERIAL2 = "def";
+ private static final String SERIAL3 = "ghi";
+ private static final Set<String> SERIALS = new HashSet<>();
+ private static final Set<IAbi> ABIS = new HashSet<>();
+ private static final List<String> DEVICE_TOKENS = new ArrayList<>();
+ private static final List<String> TEST_ARGS= new ArrayList<>();
+ private static final List<String> MODULE_ARGS = new ArrayList<>();
+ private static final List<String> INCLUDES = new ArrayList<>();
+ private static final List<String> EXCLUDES = new ArrayList<>();
+ private static final Set<String> FILES = new HashSet<>();
+ private static final String FILENAME = "%s.config";
+ private static final String ABI_32 = "armeabi-v7a";
+ private static final String ABI_64 = "arm64-v8a";
+ private static final String MODULE_NAME_A = "FooModuleA";
+ private static final String MODULE_NAME_B = "FooModuleB";
+ private static final String MODULE_NAME_C = "FooModuleC";
+ private static final String ID_A_32 = AbiUtils.createId(ABI_32, MODULE_NAME_A);
+ private static final String ID_A_64 = AbiUtils.createId(ABI_64, MODULE_NAME_A);
+ private static final String ID_B_32 = AbiUtils.createId(ABI_32, MODULE_NAME_B);
+ private static final String ID_B_64 = AbiUtils.createId(ABI_64, MODULE_NAME_B);
+ private static final String ID_C_32 = AbiUtils.createId(ABI_32, MODULE_NAME_C);
+ private static final String ID_C_64 = AbiUtils.createId(ABI_64, MODULE_NAME_C);
+ private static final String TEST_ARG = TestStub.class.getName() + ":foo:bar";
+ private static final String MODULE_ARG = "%s:blah:foobar";
+ private static final String TEST_STUB = "TestStub"; // Trivial test stub
+ private static final String SHARDABLE_TEST_STUB = "ShardableTestStub"; // Shardable and IBuildReceiver
+ static {
+ SERIALS.add(SERIAL1);
+ SERIALS.add(SERIAL2);
+ SERIALS.add(SERIAL3);
+ ABIS.add(new Abi(ABI_32, "32"));
+ ABIS.add(new Abi(ABI_64, "64"));
+ DEVICE_TOKENS.add(String.format("%s:%s", SERIAL3, FOOBAR_TOKEN));
+ TEST_ARGS.add(TEST_ARG);
+ MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_A));
+ MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_B));
+ MODULE_ARGS.add(String.format(MODULE_ARG, MODULE_NAME_C));
+ FILES.add(String.format(FILENAME, MODULE_NAME_A));
+ FILES.add(String.format(FILENAME, MODULE_NAME_B));
+ FILES.add(String.format(FILENAME, MODULE_NAME_C));
+ }
+ private IModuleRepo mRepo;
+ private File mTestsDir;
+ private IBuildInfo mBuild;
+
@Override
public void setUp() throws Exception {
+ mTestsDir = setUpConfigs();
+ ModuleRepo.sInstance = null;// Clear the instance so it gets recreated.
+ mRepo = ModuleRepo.getInstance();
+ mBuild = new CompatibilityBuildProvider().getBuild();
+ }
+
+ private File setUpConfigs() throws IOException {
+ File testsDir = FileUtil.createNamedTempDir("testcases");
+ createConfig(testsDir, MODULE_NAME_A, null);
+ createConfig(testsDir, MODULE_NAME_B, null);
+ createConfig(testsDir, MODULE_NAME_C, FOOBAR_TOKEN);
+ return testsDir;
+ }
+
+ private void createConfig(File testsDir, String name, String token) throws IOException {
+ createConfig(testsDir, name, token, TEST_STUB);
+ }
+
+ private void createConfig(File testsDir, String name, String token, String moduleClass) throws IOException {
+ File config = new File(testsDir, String.format(FILENAME, name));
+ String preparer = "";
+ if (token != null) {
+ preparer = String.format(TOKEN, token);
+ }
+ FileUtil.writeToFile(String.format(CONFIG, preparer, moduleClass, name), config);
}
@Override
public void tearDown() throws Exception {
+ tearDownConfigs(mTestsDir);
}
+ private void tearDownConfigs(File testsDir) {
+ FileUtil.recursiveDelete(testsDir);
+ }
+
+ public void testInitialization() throws Exception {
+ mRepo.initialize(3, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+ EXCLUDES, mBuild);
+ assertTrue("Should be initialized", mRepo.isInitialized());
+ assertEquals("Wrong number of shards", 3, mRepo.getNumberOfShards());
+ assertEquals("Wrong number of modules per shard", 2, mRepo.getModulesPerShard());
+ Set<IModuleDef> modules = mRepo.getRemainingModules();
+ Map<String, Set<String>> deviceTokens = mRepo.getDeviceTokens();
+ assertEquals("Wrong number of devices with tokens", 1, deviceTokens.size());
+ Set<String> tokens = deviceTokens.get(SERIAL3);
+ assertEquals("Wrong number of tokens", 1, tokens.size());
+ assertTrue("Unexpected device token", tokens.contains(FOOBAR_TOKEN));
+ assertEquals("Wrong number of modules", 4, modules.size());
+ Set<IModuleDef> tokenModules = mRepo.getRemainingWithTokens();
+ assertEquals("Wrong number of modules with tokens", 2, tokenModules.size());
+ List<IModuleDef> serial1Modules = mRepo.getModules(SERIAL1);
+ assertEquals("Wrong number of modules", 2, serial1Modules.size());
+ List<IModuleDef> serial2Modules = mRepo.getModules(SERIAL2);
+ assertEquals("Wrong number of modules", 2, serial2Modules.size());
+ List<IModuleDef> serial3Modules = mRepo.getModules(SERIAL3);
+ assertEquals("Wrong number of modules", 2, serial3Modules.size());
+ // Serial 3 should have the modules with tokens
+ for (IModuleDef module : serial3Modules) {
+ assertEquals("Wrong module", MODULE_NAME_C, module.getName());
+ }
+ Set<String> serials = mRepo.getSerials();
+ assertEquals("Wrong number of serials", 3, serials.size());
+ assertTrue("Unexpected device serial", serials.containsAll(SERIALS));
+ }
+
+ public void testConfigFilter() throws Exception {
+ File[] configFiles = mTestsDir.listFiles(new ConfigFilter());
+ assertEquals("Wrong number of config files found.", 3, configFiles.length);
+ for (File file : configFiles) {
+ assertTrue(String.format("Unrecognised file: %s", file.getAbsolutePath()),
+ FILES.contains(file.getName()));
+ }
+ }
+
+ public void testFiltering() throws Exception {
+ List<String> includeFilters = new ArrayList<>();
+ includeFilters.add(MODULE_NAME_A);
+ List<String> excludeFilters = new ArrayList<>();
+ excludeFilters.add(ID_A_32);
+ excludeFilters.add(MODULE_NAME_B);
+ mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, includeFilters,
+ excludeFilters, mBuild);
+ List<IModuleDef> modules = mRepo.getModules(SERIAL1);
+ assertEquals("Incorrect number of modules", 1, modules.size());
+ IModuleDef module = modules.get(0);
+ assertEquals("Incorrect ID", ID_A_64, module.getId());
+ checkArgs(module);
+ }
+
+ public void testParsing() throws Exception {
+ mRepo.initialize(1, mTestsDir, ABIS, DEVICE_TOKENS, TEST_ARGS, MODULE_ARGS, INCLUDES,
+ EXCLUDES, mBuild);
+ List<IModuleDef> modules = mRepo.getModules(SERIAL3);
+ Set<String> idSet = new HashSet<>();
+ for (IModuleDef module : modules) {
+ idSet.add(module.getId());
+ }
+ assertEquals("Incorrect number of IDs", 6, idSet.size());
+ assertTrue("Missing ID_A_32", idSet.contains(ID_A_32));
+ assertTrue("Missing ID_A_64", idSet.contains(ID_A_64));
+ assertTrue("Missing ID_B_32", idSet.contains(ID_B_32));
+ assertTrue("Missing ID_B_64", idSet.contains(ID_B_64));
+ assertTrue("Missing ID_C_32", idSet.contains(ID_C_32));
+ assertTrue("Missing ID_C_64", idSet.contains(ID_C_64));
+ for (IModuleDef module : modules) {
+ checkArgs(module);
+ }
+ }
+
+ private void checkArgs(IModuleDef module) {
+ IRemoteTest test = module.getTest();
+ assertTrue("Incorrect test type", test instanceof TestStub);
+ TestStub stub = (TestStub) test;
+ assertEquals("Incorrect test arg", "bar", stub.mFoo);
+ assertEquals("Incorrect module arg", "foobar", stub.mBlah);
+ }
+
+ public void testSplit() throws Exception {
+ createConfig(mTestsDir, "sharder_1", null, SHARDABLE_TEST_STUB);
+ createConfig(mTestsDir, "sharder_2", null, SHARDABLE_TEST_STUB);
+ createConfig(mTestsDir, "sharder_3", null, SHARDABLE_TEST_STUB);
+ Set<IAbi> abis = new HashSet<>();
+ abis.add(new Abi(ABI_64, "64"));
+ ArrayList<String> emptyList = new ArrayList<>();
+
+ mRepo.initialize(3, mTestsDir, abis, DEVICE_TOKENS, emptyList, emptyList, emptyList,
+ emptyList, mBuild);
+
+ Set<IModuleDef> modules = mRepo.getRemainingModules();
+
+ int shardableCount = 0;
+ for (IModuleDef def : modules) {
+ IRemoteTest test = def.getTest();
+ if (test instanceof IShardableTest) {
+ assertNotNull("Build not set", ((ShardableTestStub)test).mBuildInfo);
+ shardableCount++;
+ }
+ }
+ assertEquals("Shards wrong", 3*3, shardableCount);
+ }
}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
new file mode 100644
index 0000000..52a1aad
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/ShardableTestStub.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.testtype.IRemoteTest;
+import com.android.tradefed.testtype.IShardableTest;
+
+import junit.framework.Assert;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class ShardableTestStub implements IRemoteTest, IShardableTest, IBuildReceiver {
+
+ @Option(name = "module")
+ String mModule;
+ @Option(name = "foo")
+ String mFoo;
+ @Option(name = "blah")
+ String mBlah;
+
+ public IBuildInfo mBuildInfo = null;
+
+ Collection<IRemoteTest> mShards;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setBuild(IBuildInfo buildInfo) {
+ mBuildInfo = buildInfo;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ @Override
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ // Do nothing
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Collection<IRemoteTest> split() {
+ Assert.assertNotNull(mBuildInfo);
+
+ mShards = new ArrayList<>();
+ for (int i = 0; i < 3; i++) {
+ mShards.add(new ShardableTestStub());
+ }
+ return mShards;
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
new file mode 100644
index 0000000..8a6ab69
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/testtype/TestStub.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.compatibility.common.tradefed.testtype;
+
+import com.android.tradefed.config.Option;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.ITestInvocationListener;
+import com.android.tradefed.testtype.IRemoteTest;
+
+public class TestStub implements IRemoteTest {
+
+ @Option(name = "module")
+ String mModule;
+ @Option(name = "foo")
+ String mFoo;
+ @Option(name = "blah")
+ String mBlah;
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void run(ITestInvocationListener listener) throws DeviceNotAvailableException {
+ // Do nothing
+ }
+
+}
diff --git a/common/host-side/util/tests/run_tests.sh b/common/host-side/util/tests/run_tests.sh
new file mode 100755
index 0000000..d4513f9
--- /dev/null
+++ b/common/host-side/util/tests/run_tests.sh
@@ -0,0 +1,31 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-common-util-hostsidelib\
+ compatibility-common-util-tests\
+ compatibility-host-util\
+ compatibility-host-util-tests\
+ compatibility-mock-tradefed\
+ compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.util.HostUnitTests" "${JARS}" "${@}"
+
diff --git a/common/util/src/com/android/compatibility/common/util/ITestResult.java b/common/util/src/com/android/compatibility/common/util/ITestResult.java
index f9d8541..f27cf48 100644
--- a/common/util/src/com/android/compatibility/common/util/ITestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ITestResult.java
@@ -118,7 +118,8 @@
void passed(ReportLog report);
/**
- * Reset the state of this {@link ITestResult}.
+ * Resets the result.
*/
- void resetResult();
+ void reset();
+
}
diff --git a/common/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
index ecd6570..6efefc3 100644
--- a/common/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -66,6 +66,7 @@
private static final String OS_VERSION_ATTR = "os_version";
private static final String PASS_ATTR = "pass";
private static final String REPORT_VERSION_ATTR = "report_version";
+ private static final String REFERENCE_URL_ATTR = "reference_url";
private static final String RESULT_ATTR = "result";
private static final String RESULT_TAG = "Result";
private static final String SCREENSHOT_TAG = "Screenshot";
@@ -183,13 +184,14 @@
* @param result
* @param resultDir
* @param startTime
+ * @param referenceUrl A nullable string that can contain a URL to a related data
* @return The result file created.
* @throws IOException
* @throws XmlPullParserException
*/
public static File writeResults(String suiteName, String suiteVersion, String suitePlan,
- IInvocationResult result, File resultDir, long startTime, long endTime)
- throws IOException, XmlPullParserException {
+ IInvocationResult result, File resultDir, long startTime, long endTime,
+ String referenceUrl) throws IOException, XmlPullParserException {
int passed = result.countResults(TestStatus.PASS);
int failed = result.countResults(TestStatus.FAIL);
int notExecuted = result.countResults(TestStatus.NOT_EXECUTED);
@@ -208,6 +210,9 @@
serializer.attribute(NS, SUITE_VERSION_ATTR, suiteVersion);
serializer.attribute(NS, SUITE_PLAN_ATTR, suitePlan);
serializer.attribute(NS, REPORT_VERSION_ATTR, RESULT_FILE_VERSION);
+ if (referenceUrl != null) {
+ serializer.attribute(NS, REFERENCE_URL_ATTR, referenceUrl);
+ }
// Device Info
Set<String> devices = result.getDeviceSerials();
diff --git a/common/util/src/com/android/compatibility/common/util/TestResult.java b/common/util/src/com/android/compatibility/common/util/TestResult.java
index 574e422..03aaca29 100644
--- a/common/util/src/com/android/compatibility/common/util/TestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/TestResult.java
@@ -36,7 +36,7 @@
public TestResult(ICaseResult parent, String name) {
mParent = parent;
mTestName = name;
- resetResult();
+ reset();
}
/**
@@ -200,13 +200,14 @@
* {@inheritDoc}
*/
@Override
- public void resetResult() {
- setResultStatus(TestStatus.NOT_EXECUTED);
- setMessage(null);
- setStackTrace(null);
- setReportLog(null);
- setBugReport(null);
- setLog(null);
+ public void reset() {
+ mResult = TestStatus.NOT_EXECUTED;
+ mMessage = null;
+ mStackTrace = null;
+ mReport = null;
+ mBugReport = null;
+ mLog = null;
+ mScreenshot = null;
}
/**
diff --git a/common/util/tests/run_tests.sh b/common/util/tests/run_tests.sh
new file mode 100755
index 0000000..0045014
--- /dev/null
+++ b/common/util/tests/run_tests.sh
@@ -0,0 +1,29 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-common-util-hostsidelib\
+ compatibility-common-util-tests\
+ compatibility-host-util\
+ compatibility-host-util-tests\
+ compatibility-mock-tradefed\
+ compatibility-tradefed-tests"
+
+run_tests "com.android.compatibility.common.util.UnitTests" "${JARS}" "${@}"
+
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 9efd415..be3c109 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -68,6 +68,7 @@
"at four.big.insects.Marley.sing(Marley.java:10)";
private static final long START_MS = 1431586801000L;
private static final long END_MS = 1431673199000L;
+ private static final String REFERENCE_URL="http://android.com";
private static final String JOIN = "%s%s";
private static final String XML_BASE =
"<?xml version='1.0' encoding='UTF-8' standalone='no' ?>" +
@@ -75,7 +76,7 @@
"<Result start=\"%d\" end=\"%d\" suite_name=\"%s\" suite_version=\"%s\" " +
"suite_plan=\"%s\" report_version=\"%s\" devices=\"%s\" host_name=\"%s\"" +
"os_name=\"%s\" os_version=\"%s\" os_arch=\"%s\" java_vendor=\"%s\"" +
- "java_version=\"%s\">\n" +
+ "java_version=\"%s\" reference_url=\"%s\">\n" +
"%s%s%s" +
"</Result>";
private static final String XML_DEVICE_INFO =
@@ -164,7 +165,7 @@
// Serialize to file
ResultHandler.writeResults(SUITE_NAME, SUITE_VERSION, SUITE_PLAN, result, resultDir,
- START_MS, END_MS);
+ START_MS, END_MS, REFERENCE_URL);
// Parse the results and assert correctness
checkResult(ResultHandler.getResults(resultsDir), resultDir);
@@ -203,7 +204,7 @@
} catch (UnknownHostException ignored) {}
String output = String.format(XML_BASE, START_MS, END_MS, SUITE_NAME, SUITE_VERSION,
SUITE_PLAN, REPORT_VERSION, DEVICES, hostName, OS_NAME, OS_VERSION, OS_ARCH,
- JAVA_VENDOR, JAVA_VERSION, deviceInfo, summary, modules);
+ JAVA_VENDOR, JAVA_VERSION, REFERENCE_URL, deviceInfo, summary, modules);
writer.write(output);
writer.flush();
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 61f9a4d..55fe0d9 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -19,11 +19,16 @@
# Only compile source java files in this apk.
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_MODULE := CtsAppSecurityTests
+LOCAL_MODULE := CtsAppSecurityHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
-LOCAL_CTS_TEST_PACKAGE := android.tests.appsecurity
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+
+LOCAL_CTS_TEST_PACKAGE := android.appsecurity
+
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/appsecurity/AndroidTest.xml
similarity index 61%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/appsecurity/AndroidTest.xml
index 49d705a..d59358c 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/appsecurity/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for the CTS App Security host tests">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsAppSecurityHostTestCases.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
similarity index 94%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 2ae2e10..d8c2134 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -14,17 +14,17 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
-import static com.android.cts.appsecurity.SplitTests.ABI_TO_APK;
-import static com.android.cts.appsecurity.SplitTests.APK;
-import static com.android.cts.appsecurity.SplitTests.APK_mdpi;
-import static com.android.cts.appsecurity.SplitTests.APK_xxhdpi;
-import static com.android.cts.appsecurity.SplitTests.CLASS;
-import static com.android.cts.appsecurity.SplitTests.PKG;
+import static android.appsecurity.cts.SplitTests.ABI_TO_APK;
+import static android.appsecurity.cts.SplitTests.APK;
+import static android.appsecurity.cts.SplitTests.APK_mdpi;
+import static android.appsecurity.cts.SplitTests.APK_xxhdpi;
+import static android.appsecurity.cts.SplitTests.CLASS;
+import static android.appsecurity.cts.SplitTests.PKG;
-import com.android.cts.appsecurity.SplitTests.BaseInstallMultiple;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -39,7 +39,7 @@
*/
public class AdoptableHostTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -48,7 +48,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -88,7 +88,8 @@
final LocalVolumeInfo vol = getAdoptionVolume();
// Move app and verify
- assertSuccess(getDevice().executeShellCommand("pm move-package " + PKG + " " + vol.uuid));
+ assertSuccess(getDevice().executeShellCommand(
+ "pm move-package " + PKG + " " + vol.uuid));
runDeviceTests(PKG, CLASS, "testDataNotInternal");
runDeviceTests(PKG, CLASS, "testDataRead");
runDeviceTests(PKG, CLASS, "testNative");
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
similarity index 96%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index d7caabe..00acdf5 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -79,7 +79,7 @@
private static final String LOG_TAG = "AppSecurityTests";
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -91,11 +91,11 @@
*/
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return mCtsBuild.getTestApp(fileName);
+ return MigrationHelper.getTestFile(mCtsBuild, fileName);
}
@Override
@@ -125,7 +125,8 @@
false, options);
assertNotNull("shared uid app with different cert than existing app installed " +
"successfully", installResult);
- assertEquals("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE", installResult);
+ assertEquals("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE",
+ installResult.substring(0, installResult.indexOf(':')));
} finally {
getDevice().uninstallPackage(SHARED_UI_PKG);
getDevice().uninstallPackage(SHARED_UI_DIFF_CERT_PKG);
@@ -151,7 +152,8 @@
true /* reinstall */, options);
assertNotNull("app upgrade with different cert than existing app installed " +
"successfully", installResult);
- assertEquals("INSTALL_FAILED_UPDATE_INCOMPATIBLE", installResult);
+ assertEquals("INSTALL_FAILED_UPDATE_INCOMPATIBLE",
+ installResult.substring(0, installResult.indexOf(':')));
} finally {
getDevice().uninstallPackage(SIMPLE_APP_PKG);
}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
similarity index 88%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index a4ec65a..300aa3a 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -36,7 +36,7 @@
private static final String CLIENT_APK = "CtsDocumentClient.apk";
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -45,7 +45,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -58,8 +58,10 @@
getDevice().uninstallPackage(PROVIDER_PKG);
getDevice().uninstallPackage(CLIENT_PKG);
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(PROVIDER_APK), false));
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(CLIENT_APK), false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
}
@Override
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
similarity index 95%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index b475b3c..32a1789 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -53,7 +53,7 @@
private static final String MULTIUSER_CLASS = ".MultiUserStorageTest";
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -62,11 +62,11 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return mCtsBuild.getTestApp(fileName);
+ return MigrationHelper.getTestFile(mCtsBuild, fileName);
}
@Override
@@ -226,7 +226,9 @@
}
private void wipePrimaryExternalStorage() throws DeviceNotAvailableException {
- getDevice().executeShellCommand("rm -rf /sdcard/*");
+ getDevice().executeShellCommand("rm -rf /sdcard/Android");
+ getDevice().executeShellCommand("rm -rf /sdcard/DCIM");
+ getDevice().executeShellCommand("rm -rf /sdcard/MUST_*");
}
private int[] createUsersForTest() throws DeviceNotAvailableException {
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
similarity index 98%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 9637a6c..53a54dd 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.cts.appsecurity;
+package android.appsecurity.cts;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -101,7 +101,7 @@
private static final String LOG_TAG = "AppsecurityHostTests";
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return mCtsBuild.getTestApp(fileName);
+ return MigrationHelper.getTestFile(mCtsBuild, fileName);
}
/**
@@ -224,14 +224,14 @@
*/
private ITestDevice mDevice;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
/**
* {@inheritDoc}
*/
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
similarity index 78%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 20a92aa..6c5e4a5 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -35,7 +35,7 @@
private static final String APK_COMPAT = "CtsUsePermissionAppCompat.apk";
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -44,7 +44,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -66,7 +66,8 @@
public void testFail() throws Exception {
// Sanity check that remote failure is host failure
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
try {
runDeviceTests(PKG, ".UsePermissionTest", "testFail");
fail("Expected remote failure");
@@ -76,7 +77,8 @@
public void testKill() throws Exception {
// Sanity check that remote kill is host failure
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
try {
runDeviceTests(PKG, ".UsePermissionTest", "testKill");
fail("Expected remote failure");
@@ -85,39 +87,46 @@
}
public void testDefault() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
runDeviceTests(PKG, ".UsePermissionTest", "testDefault");
}
public void testGranted() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
grantPermission(PKG, "android.permission.READ_EXTERNAL_STORAGE");
grantPermission(PKG, "android.permission.WRITE_EXTERNAL_STORAGE");
runDeviceTests(PKG, ".UsePermissionTest", "testGranted");
}
public void testInteractiveGrant() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
runDeviceTests(PKG, ".UsePermissionTest", "testInteractiveGrant");
}
public void testRuntimeGroupGrantSpecificity() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantSpecificity");
}
public void testRuntimeGroupGrantExpansion() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK), false, false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
runDeviceTests(PKG, ".UsePermissionTest", "testRuntimeGroupGrantExpansion");
}
public void testCompatDefault() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK_COMPAT), false, false));
+ assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+ false, false));
runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatDefault");
}
public void testCompatRevoked() throws Exception {
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(APK_COMPAT), false, false));
+ assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, APK_COMPAT),
+ false, false));
setAppOps(PKG, "android:read_external_storage", "deny");
setAppOps(PKG, "android:write_external_storage", "deny");
runDeviceTests(PKG, ".UsePermissionCompatTest", "testCompatRevoked");
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
similarity index 97%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index e73280c..a2ef1f3 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -14,10 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -83,7 +83,7 @@
}
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -92,7 +92,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -297,16 +297,16 @@
public static class BaseInstallMultiple<T extends BaseInstallMultiple<?>> {
private final ITestDevice mDevice;
- private final CtsBuildHelper mBuild;
+ private final IBuildInfo mBuild;
private final IAbi mAbi;
private final List<String> mArgs = new ArrayList<>();
private final List<File> mApks = new ArrayList<>();
private boolean mUseNaturalAbi;
- public BaseInstallMultiple(ITestDevice device, CtsBuildHelper build, IAbi abi) {
+ public BaseInstallMultiple(ITestDevice device, IBuildInfo buildInfo, IAbi abi) {
mDevice = device;
- mBuild = build;
+ mBuild = buildInfo;
mAbi = abi;
addArg("-g");
}
@@ -317,7 +317,7 @@
}
T addApk(String apk) throws FileNotFoundException {
- mApks.add(mBuild.getTestApp(apk));
+ mApks.add(MigrationHelper.getTestFile(mBuild, apk));
return (T) this;
}
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
similarity index 99%
rename from hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java
rename to hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
index fdf84d3..7048074 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/Utils.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/Utils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.cts.appsecurity;
+package android.appsecurity.cts;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
diff --git a/hostsidetests/appsecurity/test-apps/Android.mk b/hostsidetests/appsecurity/test-apps/Android.mk
index f6091e4..ae48006 100644
--- a/hostsidetests/appsecurity/test-apps/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/Android.mk
@@ -16,6 +16,9 @@
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# Build the test APKs using their own makefiles
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
index 4459e69..47323a3 100644
--- a/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppAccessData/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsAppAccessData
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# although not strictly necessary, sign this app with different cert than CtsAppWithData
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
index 0916254..df52f08 100644
--- a/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/AppWithData/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsAppWithData
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
index 272ef28..54c2cc2 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/Android.mk
@@ -26,6 +26,9 @@
LOCAL_PACKAGE_NAME := CtsDocumentClient
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index f308211..c2c4345 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -25,6 +25,7 @@
import android.provider.DocumentsContract;
import android.provider.DocumentsContract.Document;
import android.provider.DocumentsProvider;
+import android.support.test.uiautomator.Configurator;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
@@ -34,6 +35,7 @@
import android.test.MoreAsserts;
import android.text.format.DateUtils;
import android.util.Log;
+import android.view.MotionEvent;
import com.android.cts.documentclient.MyActivity.Result;
@@ -59,6 +61,8 @@
public void setUp() throws Exception {
super.setUp();
+ Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_FINGER);
+
mDevice = UiDevice.getInstance(getInstrumentation());
mActivity = launchActivity(getInstrumentation().getTargetContext().getPackageName(),
MyActivity.class, null);
@@ -134,15 +138,24 @@
assertTrue("CtsCreate root", findRoot("CtsCreate").exists());
assertFalse("CtsGetContent root", findRoot("CtsGetContent").exists());
- // Pick a specific file from our test provider
+ // Choose the local root.
mDevice.waitForIdle();
findRoot("CtsLocal").click();
+ // Try picking a virtual file. Virtual files must not be returned for CATEGORY_OPENABLE
+ // though, so the click should be ignored.
+ mDevice.waitForIdle();
+ findDocument("VIRTUAL_FILE").click();
+ mDevice.waitForIdle();
+
+ // Pick a regular file.
mDevice.waitForIdle();
findDocument("FILE1").click();
+ // Confirm that the returned file is a regular file caused by the second click.
final Result result = mActivity.getResult();
final Uri uri = result.data.getData();
+ assertEquals("doc:file1", DocumentsContract.getDocumentId(uri));
// We should now have permission to read/write
MoreAsserts.assertEquals("fileone".getBytes(), readFully(uri));
@@ -152,6 +165,26 @@
MoreAsserts.assertEquals("replaced!".getBytes(), readFully(uri));
}
+ public void testOpenVirtual() throws Exception {
+ if (!supportedHardware()) return;
+
+ final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+ intent.setType("*/*");
+ mActivity.startActivityForResult(intent, 42);
+
+ // Pick a virtual file from the local root.
+ mDevice.waitForIdle();
+ findRoot("CtsLocal").click();
+
+ mDevice.waitForIdle();
+ findDocument("VIRTUAL_FILE").click();
+
+ // Confirm that the returned file is actually the selected one.
+ final Result result = mActivity.getResult();
+ final Uri uri = result.data.getData();
+ assertEquals("virtual-file", DocumentsContract.getDocumentId(uri));
+ }
+
public void testCreateNew() throws Exception {
if (!supportedHardware()) return;
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
index bbf7734..84a1665 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/Android.mk
@@ -26,6 +26,9 @@
LOCAL_PACKAGE_NAME := CtsDocumentProvider
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
index 9d38a94..ab7696f 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentProvider/src/com/android/cts/documentprovider/MyDocumentsProvider.java
@@ -124,6 +124,13 @@
mCreateRoot.children.add(file2);
}
+ {
+ Doc virtualFile = buildDoc("doc:virtual-file", "VIRTUAL_FILE", "application/icecream");
+ virtualFile.flags = Document.FLAG_VIRTUAL_DOCUMENT;
+ mLocalRoot.children.add(virtualFile);
+ mCreateRoot.children.add(virtualFile);
+ }
+
Doc dir1 = buildDoc("doc:dir1", "DIR1", Document.MIME_TYPE_DIR);
mLocalRoot.children.add(dir1);
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
index a7de92a..bbe351a 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.mk
@@ -23,6 +23,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := CtsExternalStorageApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_DEX_PREOPT := false
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
index 4c64204..717d9f9 100644
--- a/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/InstrumentationAppDiffCert/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsInstrumentationAppDiffCert
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with different cert than CtsTargetInstrumentationApp
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
index c37d052..270dac8 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsMultiUserStorageApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_DEX_PREOPT := false
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
index 43d3547..2c67bdc 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareApp/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsPermissionDeclareApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsUsePermissionDiffCert
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
index 5109c99..af051a0 100644
--- a/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/PermissionDeclareAppCompat/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsPermissionDeclareAppCompat
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsUsePermissionDiffCert
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
index c662d39..73cb625 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsReadExternalStorageApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_DEX_PREOPT := false
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
index 05438ef..f1f6efe 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstall/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsSharedUidInstall
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsSharedUidInstallDiffCert
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
index eaed910..937a8aa 100644
--- a/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SharedUidInstallDiffCert/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsSharedUidInstallDiffCert
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsSharedUidInstall
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
index 01cffdb..8ba76b6 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstall/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsSimpleAppInstall
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsSimpleAppInstallDiffCert
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
index 032ef57..17707ee 100644
--- a/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SimpleAppInstallDiffCert/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsSimpleAppInstallDiffCert
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsSimpleAppInstall
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
index de46dea..3dd25da 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/Android.mk
@@ -27,6 +27,9 @@
LOCAL_PACKAGE_NAME := CtsSplitApp
LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 v7 fr de
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_ASSET_DIR := $(LOCAL_PATH)/assets
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
@@ -52,6 +55,9 @@
LOCAL_PACKAGE_NAME := CtsSplitAppDiffRevision
LOCAL_PACKAGE_SPLITS := v7
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MANIFEST_FILE := revision/AndroidManifest.xml
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundredRevisionTwelve --replace-version
@@ -76,6 +82,9 @@
LOCAL_PACKAGE_NAME := CtsSplitAppDiffVersion
LOCAL_PACKAGE_SPLITS := v7
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 101 --version-name OneHundredOne --replace-version
@@ -99,6 +108,9 @@
LOCAL_PACKAGE_NAME := CtsSplitAppDiffCert
LOCAL_PACKAGE_SPLITS := v7
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
LOCAL_AAPT_FLAGS := --version-code 100 --version-name OneHundred --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
index fbb7764..e6ea9cf 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/feature/Android.mk
@@ -28,6 +28,9 @@
LOCAL_MODULE_TAGS := tests
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
featureOf := CtsSplitApp
featureOfApk := $(call intermediates-dir-for,APPS,$(featureOf))/package.apk
localRStamp := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)/src/R.stamp
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
index 507b13a..9989ce3 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/jni/Android.mk
@@ -23,4 +23,7 @@
LOCAL_LDLIBS += -llog
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_SHARED_LIBRARY)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
index 5053e7d..ba2da56 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/Android.mk
@@ -1 +1,15 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
include $(call all-subdir-makefiles)
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
index 9faaba1..f322622 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/arm64-v8a/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
index 87b32aa..bbdc18b 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi-v7a/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
index fe289e0..f10c843 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/armeabi/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
index d66d674..fdd2129 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
index 7232324..8c58c0d 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/mips64/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
index f1cd994..fe60583 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
index 521f6f2..32f28db 100644
--- a/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/SplitApp/libs/x86_64/Android.mk
@@ -22,6 +22,9 @@
LOCAL_JAVA_RESOURCE_DIRS := raw
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
LOCAL_AAPT_FLAGS := --version-code 100 --replace-version
diff --git a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
index f5ac52f..3300cc3 100644
--- a/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/TargetInstrumentationApp/Android.mk
@@ -25,6 +25,9 @@
LOCAL_PACKAGE_NAME := CtsTargetInstrumentationApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with different cert than CtsInstrumentationAppDiffCert
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey1
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
index f91d0c4..0842ea3 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp/Android.mk
@@ -27,6 +27,9 @@
LOCAL_PACKAGE_NAME := CtsUsePermissionApp
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
index 70b4b0f..45b97c0 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionAppCompat/Android.mk
@@ -27,6 +27,9 @@
LOCAL_PACKAGE_NAME := CtsUsePermissionAppCompat
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
LOCAL_PROGUARD_ENABLED := disabled
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
index 6e0d090..966aded 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/Android.mk
@@ -26,6 +26,9 @@
LOCAL_PACKAGE_NAME := CtsUsePermissionDiffCert
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# sign this app with a different cert than CtsPermissionDeclareApp
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/cts-testkey2
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
index cdd77e8..53daf9a 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.mk
@@ -23,6 +23,9 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
../ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_PACKAGE_NAME := CtsWriteExternalStorageApp
LOCAL_DEX_PREOPT := false
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 5e6aa3e..3861ddf 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -154,11 +154,10 @@
* storage.
*/
public void testPrimaryOtherPackageWriteAccess() throws Exception {
- deleteContents(Environment.getExternalStorageDirectory());
-
final File ourCache = getContext().getExternalCacheDir();
final File otherCache = new File(ourCache.getAbsolutePath()
.replace(getContext().getPackageName(), PACKAGE_NONE));
+ deleteContents(otherCache);
assertTrue(otherCache.mkdirs());
assertDirReadWriteAccess(otherCache);
@@ -237,8 +236,9 @@
* Verify that .nomedia is created correctly.
*/
public void testVerifyNoMediaCreated() throws Exception {
- deleteContents(Environment.getExternalStorageDirectory());
-
+ for (File file : getAllPackageSpecificPaths(getContext())) {
+ deleteContents(file);
+ }
final List<File> paths = getAllPackageSpecificPaths(getContext());
// Require that .nomedia was created somewhere above each dir
diff --git a/hostsidetests/appsecurity/test-apps/keysets/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
index 935fa95..7193868 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/Android.mk
@@ -16,6 +16,9 @@
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# Build the test APKs using their own makefiles
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
index 207160f..f1cf063 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malBadKey/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
index 84f3f75..ed8fdb8 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malNoDef/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
index 7290f06..d539925 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/malOneDef/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
index f5a7286..6f60a7a 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permDef/Android.mk
@@ -23,6 +23,8 @@
LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningA
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -35,5 +37,7 @@
LOCAL_PACKAGE_NAME := CtsKeySetPermDefSigningB
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
index 678d89d..e9db2a8 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/permUse/Android.mk
@@ -24,6 +24,9 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed cts-keyset-test-b
@@ -36,4 +39,7 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
index b8acc99..d8f43f7 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/testApp/Android.mk
@@ -16,6 +16,9 @@
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_SDK_VERSION := current
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
index 79d053b..7f00bb3 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uA/Android.mk
@@ -16,13 +16,14 @@
#apks signed by cts-keyset-test-a
include $(CLEAR_VARS)
-
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := CtsKeySetSigningAUpgradeA
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_SUPPORT_PACKAGE)
@@ -34,24 +35,26 @@
LOCAL_PACKAGE_NAME := CtsKeySetSigningBUpgradeA
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed by cts-keyset-test-ec-a
include $(CLEAR_VARS)
-
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
LOCAL_PACKAGE_NAME := CtsKeySetSigningEcAUpgradeA
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-ec-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed by cts-keyset-test-a and cts-keyset-test-b
include $(CLEAR_VARS)
-
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
@@ -59,4 +62,7 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
index 406529c..6b27445 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAB/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
index 23d6b17..b6b230c 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uAuB/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
index f2cedf9..cb1a6a0 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uB/Android.mk
@@ -24,6 +24,9 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed cts-keyset-test-b
@@ -36,6 +39,9 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed by cts-keyset-test-a and cts-keyset-test-c
@@ -49,4 +55,7 @@
LOCAL_ADDITIONAL_CERTIFICATES := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-c
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
index 1d6d5a5..5e56d12 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uBsharedUser/Android.mk
@@ -24,6 +24,9 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-a
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
#apks signed cts-keyset-test-b
@@ -36,4 +39,7 @@
LOCAL_CERTIFICATE := cts/hostsidetests/appsecurity/certs/keysets/cts-keyset-test-b
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
index 3d0109a..ddc0012 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uEcA/Android.mk
@@ -17,6 +17,9 @@
#apks signed by cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
index 9b327fe..4e383de 100644
--- a/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
+++ b/hostsidetests/appsecurity/test-apps/keysets/uNone/Android.mk
@@ -17,6 +17,9 @@
#apks signed cts-keyset-test-a
include $(CLEAR_VARS)
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_MODULE_TAGS := tests
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index 1fd7102..e2dbaba 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -21,10 +21,15 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsAtraceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
LOCAL_CTS_TEST_PACKAGE := android.host.atrace
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/atrace/AndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/atrace/AndroidTest.xml
index 49d705a..b8aeb31 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/atrace/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for CTS atrace host test cases">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsAtraceHostTestCases.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/atrace/AtraceTestApp/Android.mk b/hostsidetests/atrace/AtraceTestApp/Android.mk
index 0eb7cfd..bbb79ee 100644
--- a/hostsidetests/atrace/AtraceTestApp/Android.mk
+++ b/hostsidetests/atrace/AtraceTestApp/Android.mk
@@ -30,4 +30,7 @@
#LOCAL_DEX_PREOPT := false
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 760723e..5f5ebe1 100644
--- a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
+++ b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
@@ -16,7 +16,7 @@
package android.atrace.cts;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
@@ -118,14 +118,14 @@
}
}
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
/**
* {@inheritDoc}
*/
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
// Collection of all userspace tags, and 'sched'
@@ -201,7 +201,7 @@
getDevice().uninstallPackage(TEST_PKG);
// install the test app
- File testAppFile = mCtsBuild.getTestApp(TEST_APK);
+ File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
String installResult = getDevice().installPackage(testAppFile, false);
assertNull(
String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index 6708c3d..ad0d6e1 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -22,10 +22,15 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt tools-common-prebuilt cts-tradefed
+LOCAL_JAVA_LIBRARIES := tradefed-prebuilt tools-common-prebuilt cts-tradefed_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
LOCAL_CTS_TEST_PACKAGE := android.adminhostside
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
# Build the test APKs using their own makefiles
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/devicepolicy/AndroidTest.xml
similarity index 61%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/devicepolicy/AndroidTest.xml
index 49d705a..dd3444f 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/devicepolicy/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for the CTS Device Policy host tests">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsDevicePolicyManagerTestCases.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
index 22a78e2..6ef29a5 100644
--- a/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/CertInstaller/Android.mk
@@ -28,4 +28,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
index 0548af6..e1f1a89 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
index b3532fb..d75e632 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
old mode 100644
new mode 100755
index 5774b0c..27fd36f
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/KeyManagementTest.java
@@ -47,7 +47,7 @@
public class KeyManagementTest extends
ActivityInstrumentationTestCase2<KeyManagementActivity> {
- private static final int KEYCHAIN_TIMEOUT_MS = 8000;
+ private static final int KEYCHAIN_TIMEOUT_MS = 6 * 60 * 1000;
private DevicePolicyManager mDevicePolicyManager;
public KeyManagementTest() {
diff --git a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
index 98cdf52..bb9a819 100644
--- a/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentReceiver/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/IntentSender/Android.mk b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
index e5246c5..9bb1933 100644
--- a/hostsidetests/devicepolicy/app/IntentSender/Android.mk
+++ b/hostsidetests/devicepolicy/app/IntentSender/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
index 5f645b6..24b5c39 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTests/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
index 2465ef3..2254e39 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/Android.mk
@@ -28,4 +28,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
index 9db6718..229cead 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/Android.mk
@@ -31,4 +31,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
index e68c884..ecf9837 100644
--- a/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
+++ b/hostsidetests/devicepolicy/app/PackageInstaller/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
index a2224db..744c30d 100644
--- a/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimpleApp/Android.mk
@@ -31,4 +31,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
index 7460552..a6dd2c9 100644
--- a/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
+++ b/hostsidetests/devicepolicy/app/SimplePreMApp/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := 21
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
index c0e35fa..6890544 100644
--- a/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
+++ b/hostsidetests/devicepolicy/app/WidgetProvider/Android.mk
@@ -26,4 +26,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
index 8cfc58d..5aa11b4 100644
--- a/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
+++ b/hostsidetests/devicepolicy/app/WifiConfigCreator/Android.mk
@@ -30,4 +30,7 @@
LOCAL_SDK_VERSION := current
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 5d99bd1..d431d27 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -16,7 +16,7 @@
package com.android.cts.devicepolicy;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.InstrumentationResultParser;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -54,7 +54,7 @@
private static final int FLAG_PRIMARY = 1; // From the UserInfo class
- protected CtsBuildHelper mCtsBuild;
+ protected IBuildInfo mCtsBuild;
private String mPackageVerifier;
private HashSet<String> mAvailableFeatures;
@@ -62,7 +62,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -88,7 +88,8 @@
protected void installApp(String fileName)
throws FileNotFoundException, DeviceNotAvailableException {
CLog.logAndDisplay(LogLevel.INFO, "Installing app " + fileName);
- String installResult = getDevice().installPackage(mCtsBuild.getTestApp(fileName), true);
+ String installResult = getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, fileName), true);
assertNull(String.format("Failed to install %s, Reason: %s", fileName, installResult),
installResult);
}
@@ -97,7 +98,7 @@
DeviceNotAvailableException {
final ITestDevice device = getDevice();
- final File apk = mCtsBuild.getTestApp(appFileName);
+ final File apk = MigrationHelper.getTestFile(mCtsBuild, appFileName);
final String remotePath = "/data/local/tmp/" + apk.getName();
if (!device.pushFile(apk, remotePath)) {
throw new IllegalStateException("Failed to push " + apk);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 8d22638..7602802 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,6 +16,8 @@
package com.android.cts.devicepolicy;
+import com.android.cts.migration.MigrationHelper;
+
import java.io.File;
import java.lang.Exception;
@@ -132,7 +134,7 @@
if (!mHasFeature) {
return;
}
- final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
try {
// Install the test and prepare the test apk.
installApp(PACKAGE_INSTALLER_APK);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index a062724..a936408 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -16,6 +16,7 @@
package com.android.cts.devicepolicy;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
@@ -223,7 +224,7 @@
final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources";
final String UNKNOWN_SOURCES_SETTING = "install_non_market_apps";
final String SECURE_SETTING_CATEGORY = "secure";
- final File apk = mCtsBuild.getTestApp(TEST_APP_APK);
+ final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
String unknownSourceSetting = null;
try {
// Install the test and prepare the test apk.
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index 9e7a84f..e9b08a4 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -18,7 +18,6 @@
import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IBuildReceiver;
@@ -873,7 +872,7 @@
getDevice().uninstallPackage(TEST_PKG);
// install the test app
- File testAppFile = MigrationHelper.getTestFile((IFolderBuildInfo) mCtsBuild, TEST_APK);
+ File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
String installResult = getDevice().installPackage(testAppFile, false);
assertNull(
String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/jank/Android.mk b/hostsidetests/jank/Android.mk
index 003d0d6..0698e53 100644
--- a/hostsidetests/jank/Android.mk
+++ b/hostsidetests/jank/Android.mk
@@ -38,7 +38,7 @@
$(cts_library_jar_): $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_DEVICE_JAR_))/javalib.jar | $(ACP)
$(hide) mkdir -p $(CTS_TESTCASES_OUT)
- $(hide) $(ACP) -fp $(call intermediates-dir-for,JAVA_LIBRARIES,$(LOCAL_DEVICE_JAR_))/javalib.jar $@
+ $(hide) $(ACP) -fp $< $@
$(CTS_TESTCASES_OUT)/CtsJankHostTestCases.xml: $(cts_library_jar_)
diff --git a/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java b/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java
index 57ba131..a33a3e4 100644
--- a/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java
+++ b/hostsidetests/jank/src/android/jank/cts/CtsHostJankTest.java
@@ -18,7 +18,6 @@
import com.android.compatibility.common.util.ResultUnit;
import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.IAbi;
import com.android.tradefed.testtype.IAbiReceiver;
@@ -43,7 +42,7 @@
private final String mJarName;
private final String mJarPath;
protected ITestDevice mDevice;
- protected IFolderBuildInfo mBuild;
+ protected IBuildInfo mBuild;
protected IAbi mAbi;
public CtsHostJankTest(String jarName, String deviceTestClass, String hostTestClass) {
@@ -66,7 +65,7 @@
*/
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = (IFolderBuildInfo) buildInfo;
+ mBuild = buildInfo;
}
/**
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
index b950b59..186728c 100644
--- a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -18,7 +18,6 @@
import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -46,7 +45,7 @@
private static final String DEVICE_JAR_FILENAME = "CtsJdwpApp.jar";
private static final String JAR_MAIN_CLASS_NAME = "com.android.cts.jdwpsecurity.JdwpTest";
- private IFolderBuildInfo mBuildInfo;
+ private IBuildInfo mBuildInfo;
private static String getDeviceScriptFilepath() {
return DEVICE_LOCATION + File.separator + DEVICE_SCRIPT_FILENAME;
@@ -58,7 +57,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuildInfo = (IFolderBuildInfo) buildInfo;
+ mBuildInfo = buildInfo;
}
@Override
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index c9f3bb3..b377996 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -22,11 +22,16 @@
LOCAL_MODULE := CtsMonkeyTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
# prefix zzz intentional to run this last
LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/monkey/AndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/monkey/AndroidTest.xml
index 49d705a..5c7ec5b 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/monkey/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for the CTS monkey host tests">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsMonkeyTestCases.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
index c8c9863..26023be 100755
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -1,7 +1,7 @@
package com.android.cts.monkey;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -23,7 +23,7 @@
static final String MONKEY_CMD = "monkey --pct-motion 0 --pct-majornav 0 --pct-syskeys 0 --pct-anyevent 0 --pct-rotation 0";
IAbi mAbi;
- CtsBuildHelper mBuild;
+ IBuildInfo mBuild;
ITestDevice mDevice;
@Override
@@ -33,7 +33,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mBuild = buildInfo;
}
@Override
@@ -43,7 +43,7 @@
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
for (int i = 0; i < PKGS.length; i++) {
mDevice.uninstallPackage(PKGS[i]);
- File app = mBuild.getTestApp(APKS[i]);
+ File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
mDevice.installPackage(app, false, options);
}
clearLogCat();
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
index 2e675e8..373a512 100644
--- a/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/PackageTest.java
@@ -20,6 +20,7 @@
public class PackageTest extends AbstractMonkeyTest {
+ private static final int MAX_ERROR_LENGTH = 256;
private static final Pattern ALLOW_MONKEY =
Pattern.compile("^.*Allowing.*cmp=com\\.android\\.cts\\.monkey/\\.MonkeyActivity.*$",
Pattern.MULTILINE);
@@ -30,18 +31,25 @@
public void testSinglePackage() throws Exception {
String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0] + " 5000");
- assertTrue(out, ALLOW_MONKEY.matcher(out).find());
- assertFalse(out, ALLOW_CHIMP.matcher(out).find());
+ out = truncateError(out);
+ assertTrue("Monkey not found in: " + out, ALLOW_MONKEY.matcher(out).find());
+ assertFalse("Chimp found in: " + out, ALLOW_CHIMP.matcher(out).find());
out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[1] + " 5000");
- assertFalse(out, ALLOW_MONKEY.matcher(out).find());
- assertTrue(out, ALLOW_CHIMP.matcher(out).find());
+ out = truncateError(out);
+ assertFalse("Monkey found in: " + out, ALLOW_MONKEY.matcher(out).find());
+ assertTrue("Chimp not found in: " + out, ALLOW_CHIMP.matcher(out).find());
}
public void testMultiplePackages() throws Exception {
String out = mDevice.executeShellCommand(MONKEY_CMD + " -v -p " + PKGS[0]
+ " -p " + PKGS[1] + " 5000");
- assertTrue(out, ALLOW_MONKEY.matcher(out).find());
- assertTrue(out, ALLOW_CHIMP.matcher(out).find());
+ out = truncateError(out);
+ assertTrue("Monkey not found in: " + out, ALLOW_MONKEY.matcher(out).find());
+ assertTrue("Chimp not found in: " + out, ALLOW_CHIMP.matcher(out).find());
+ }
+
+ private static final String truncateError(String input) {
+ return input.substring(0, Math.min(input.length(), MAX_ERROR_LENGTH));
}
}
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
index c04d4b2..49288ad 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp/Android.mk
@@ -30,4 +30,7 @@
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
index b3cb181..8d58435 100644
--- a/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
+++ b/hostsidetests/monkey/test-apps/CtsMonkeyApp2/Android.mk
@@ -30,4 +30,7 @@
LOCAL_DEX_PREOPT := false
+# tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index 6637d61..b4e1e3d 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -21,10 +21,15 @@
LOCAL_MODULE := CtsHostsideNetworkTests
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
# Build the test APKs using their own makefiles
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/net/AndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/net/AndroidTest.xml
index 49d705a..4b6994a 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/net/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for CTS net host test cases">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsHostsideNetworkTests.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/net/app/Android.mk b/hostsidetests/net/app/Android.mk
index 055287a..b64c4c9 100644
--- a/hostsidetests/net/app/Android.mk
+++ b/hostsidetests/net/app/Android.mk
@@ -29,4 +29,7 @@
LOCAL_PROGUARD_ENABLED := disabled
LOCAL_DEX_PREOPT := false
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
index a7698f3..f42de0e 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTests.java
@@ -16,7 +16,7 @@
package com.android.cts.net;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
@@ -39,7 +39,7 @@
private static final String TEST_APK = "CtsHostsideNetworkTestsApp.apk";
private IAbi mAbi;
- private CtsBuildHelper mCtsBuild;
+ private IBuildInfo mCtsBuild;
@Override
public void setAbi(IAbi abi) {
@@ -48,7 +48,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mCtsBuild = buildInfo;
}
@Override
@@ -60,7 +60,8 @@
getDevice().uninstallPackage(TEST_PKG);
- assertNull(getDevice().installPackage(mCtsBuild.getTestApp(TEST_APK), false));
+ assertNull(getDevice().installPackage(
+ MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
}
@Override
diff --git a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
index 1c0b342..b75ea94 100644
--- a/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
+++ b/hostsidetests/sample/src/android/sample/cts/SampleHostResultTest.java
@@ -24,7 +24,6 @@
import com.android.compatibility.common.util.ResultUnit;
import com.android.compatibility.common.util.Stat;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
@@ -84,7 +83,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
// Get the build, this is used to access the APK.
- mBuildHelper = new CompatibilityBuildHelper((IFolderBuildInfo) buildInfo);
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@Override
diff --git a/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java b/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java
new file mode 100644
index 0000000..f822e7e
--- /dev/null
+++ b/hostsidetests/security/src/android/security/cts/EncryptionHostTest.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.security.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.UUID;
+
+/**
+ * Host side encryption tests
+ *
+ * These tests analyze a userdebug device for correct encryption properties
+ */
+public class EncryptionHostTest extends DeviceTestCase {
+ ITestDevice mDevice;
+ boolean mUserDebug;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mDevice = getDevice();
+ mUserDebug = "userdebug".equals(mDevice.executeShellCommand("getprop ro.build.type").trim());
+ if (!mUserDebug) {
+ return;
+ }
+
+ mDevice.executeAdbCommand("root");
+ assertTrue(mDevice.isAdbRoot());
+ }
+
+ public void testEncrypted() throws DeviceNotAvailableException {
+ if (!mUserDebug || !mDevice.isDeviceEncrypted()) {
+ return;
+ }
+
+ // Create file with name and contents a random UUID so we can search for it
+ String uuid = UUID.randomUUID().toString();
+ mDevice.executeShellCommand("echo " + uuid + " > /data/local/tmp/" + uuid);
+ String uuidReturned = mDevice.executeShellCommand("cat /data/local/tmp/" + uuid).trim();
+ assertTrue(uuid.equals(uuidReturned));
+
+ // Get name of /data device
+ String fstabName = mDevice.executeShellCommand("ls /fstab.*");
+ String[] fstab = mDevice.executeShellCommand("cat " + fstabName).split("\n");
+ String path = null;
+ for (String line : fstab) {
+ String[] entries = line.split("[ \t]+");
+ if (entries.length < 2) continue;
+ if ("/data".equals(entries[1])) {
+ path = entries[0];
+ break;
+ }
+ }
+ assertFalse(path == null);
+
+ // grep it for the data
+ String result = mDevice.executeShellCommand("grep " + uuid + " " + path + " ").trim();
+ assertTrue("".equals(result));
+
+ // Clean up
+ mDevice.executeShellCommand("rm /data/local/tmp/" + uuid);
+ }
+}
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index 79a6d51..7bf46a3 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -16,8 +16,6 @@
package android.security.cts;
-import com.android.ddmlib.Log;
-import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -33,7 +31,6 @@
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.String;
-import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -723,7 +720,8 @@
/* take the output of a ps -Z to do our analysis */
CollectingOutputReceiver psOut = new CollectingOutputReceiver();
- tDevice.executeShellCommand("ps -Z", psOut);
+ // TODO: remove "toybox" below and just run "ps"
+ tDevice.executeShellCommand("toybox ps -A -o label,user,pid,ppid,cmdline", psOut);
String psOutString = psOut.getOutput();
Pattern p = Pattern.compile(
"^([\\w_:]+)\\s+([\\w_]+)\\s+(\\d+)\\s+(\\d+)\\s+(\\p{Graph}+)$",
@@ -742,7 +740,7 @@
procMap.put(domainLabel, new ArrayList<ProcessDetails>());
}
procMap.get(domainLabel).add(proc);
- if (procTitle.equals("kthreadd") && ppid == 0) {
+ if (procTitle.equals("[kthreadd]") && ppid == 0) {
kernelParentThreadpid = pid;
}
if (exeMap.get(procTitle) == null) {
diff --git a/hostsidetests/services/Android.mk b/hostsidetests/services/Android.mk
new file mode 100644
index 0000000..178cb8a
--- /dev/null
+++ b/hostsidetests/services/Android.mk
@@ -0,0 +1,17 @@
+#
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+include $(call all-subdir-makefiles)
diff --git a/hostsidetests/services/activitymanager/Android.mk b/hostsidetests/services/activitymanager/Android.mk
new file mode 100644
index 0000000..35d34da
--- /dev/null
+++ b/hostsidetests/services/activitymanager/Android.mk
@@ -0,0 +1,38 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+# Must match the package name in CtsTestCaseList.mk
+LOCAL_MODULE := CtsServicesHostTestCases
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+
+LOCAL_CTS_TEST_PACKAGE := android.server
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_CTS_HOST_JAVA_LIBRARY)
+
+# Build the test APKs using their own makefiles
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/services/activitymanager/AndroidTest.xml b/hostsidetests/services/activitymanager/AndroidTest.xml
new file mode 100644
index 0000000..e8f052f
--- /dev/null
+++ b/hostsidetests/services/activitymanager/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Sample host test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsDeviceServicesTestApp.apk" />
+ </target_preparer>
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsServivcesHostTestCases.jar" />
+ </test>
+</configuration>
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/services/activitymanager/OldAndroidTest.xml
similarity index 61%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/services/activitymanager/OldAndroidTest.xml
index 49d705a..669fe02 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/services/activitymanager/OldAndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="CTS package preparer for install/uninstall of the apk used as a test operation target">
+ <include name="common-config" />
+ <option name="cts-apk-installer:test-file-name" value="CtsDeviceServicesTestApp.apk" />
+</configuration>
diff --git a/hostsidetests/services/activitymanager/app/Android.mk b/hostsidetests/services/activitymanager/app/Android.mk
new file mode 100644
index 0000000..c6d4722
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Don't include this package in any target.
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsServicesTestApp
+
+include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/hostsidetests/services/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
new file mode 100755
index 0000000..027a73d
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.server.app">
+
+ <application>
+ <activity android:name=".TestActivity"
+ android:resizeable="true"
+ android:supportsPictureInPicture="true"
+ />
+ </application>
+</manifest>
+
diff --git a/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java b/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
new file mode 100644
index 0000000..222cdde
--- /dev/null
+++ b/hostsidetests/services/activitymanager/app/src/android/server/app/TestActivity.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.server.app;
+
+import android.app.Activity;
+
+public class TestActivity extends Activity {
+}
diff --git a/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
new file mode 100644
index 0000000..b31a945
--- /dev/null
+++ b/hostsidetests/services/activitymanager/src/android/server/cts/ActivityManagerTests.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.server.cts;
+
+import com.android.ddmlib.Log.LogLevel;
+import com.android.tradefed.device.CollectingOutputReceiver;
+import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.log.LogUtil.CLog;
+import com.android.tradefed.testtype.DeviceTestCase;
+
+import java.util.HashSet;
+
+public class ActivityManagerTests extends DeviceTestCase {
+
+ // Constants copied from ActivityManager.StackId. If they are changed there, these must be
+ // updated.
+ /** First static stack ID. */
+ public static final int FIRST_STATIC_STACK_ID = 0;
+
+ /** Home activity stack ID. */
+ public static final int HOME_STACK_ID = FIRST_STATIC_STACK_ID;
+
+ /** ID of stack where fullscreen activities are normally launched into. */
+ public static final int FULLSCREEN_WORKSPACE_STACK_ID = 1;
+
+ /** ID of stack where freeform/resized activities are normally launched into. */
+ public static final int FREEFORM_WORKSPACE_STACK_ID = FULLSCREEN_WORKSPACE_STACK_ID + 1;
+
+ /** ID of stack that occupies a dedicated region of the screen. */
+ public static final int DOCKED_STACK_ID = FREEFORM_WORKSPACE_STACK_ID + 1;
+
+ private static final String STACK_ID_PREFIX = "Stack id=";
+ private static final String TASK_ID_PREFIX = "taskId";
+
+ private static final String TEST_ACTIVITY_NAME = "TestActivity";
+
+ private static final String AM_STACK_LIST = "am stack list";
+ private static final String AM_START_ACTIVITY = "am start -n android.server.app/.TestActivity";
+ private static final String AM_FORCE_STOP = "am force-stop android.server.app";
+ private static final String AM_MOVE_TASK = "am stack movetask ";
+
+ /**
+ * A reference to the device under test.
+ */
+ private ITestDevice mDevice;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ // Get the device, this gives a handle to run commands and install APKs.
+ mDevice = getDevice();
+ }
+
+ @Override
+ protected void tearDown() {
+ try {
+ mDevice.executeShellCommand(AM_FORCE_STOP);
+ } catch (DeviceNotAvailableException e) {
+ }
+ }
+
+ public void testStackList() throws Exception {
+ mDevice.executeShellCommand(AM_START_ACTIVITY);
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+ String output = outputReceiver.getOutput();
+ HashSet<Integer> stacks = new HashSet<>();
+ for (String line : output.split("\\n")) {
+ CLog.logAndDisplay(LogLevel.INFO, line);
+ if (line.startsWith(STACK_ID_PREFIX)) {
+ final String sub = line.substring(STACK_ID_PREFIX.length());
+ final int index = sub.indexOf(" ");
+ final int currentStack = Integer.parseInt(sub.substring(0, index));
+ stacks.add(currentStack);
+ } else if (line.startsWith(TASK_ID_PREFIX)) {
+ }
+ }
+ assertTrue("At least two stacks expected, home and fullscreen.", stacks.size() >= 2);
+ assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
+ assertTrue("Stacks must contain fullscreen stack.", stacks.contains(
+ FULLSCREEN_WORKSPACE_STACK_ID));
+ }
+
+ // Utility method for debugging, not used directly here, but useful, so kept around.
+ private void printStacksAndTasks() throws DeviceNotAvailableException {
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+ String output = outputReceiver.getOutput();
+ for (String line : output.split("\\n")) {
+ CLog.logAndDisplay(LogLevel.INFO, line);
+ }
+ }
+
+ private int getTestActivityTaskId() throws DeviceNotAvailableException {
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+ final String output = outputReceiver.getOutput();
+ for (String line : output.split("\\n")) {
+ if (line.contains(TEST_ACTIVITY_NAME)) {
+ for (String word : line.split("\\s+")) {
+ if (word.startsWith(TASK_ID_PREFIX)) {
+ final String withColon = word.split("=")[1];
+ return Integer.parseInt(withColon.substring(0, withColon.length() - 1));
+ }
+ }
+ }
+ }
+ return -1;
+ }
+
+ public void testDockActivity() throws Exception {
+ mDevice.executeShellCommand(AM_START_ACTIVITY);
+ final int taskId = getTestActivityTaskId();
+ final String cmd = AM_MOVE_TASK + taskId + " " + DOCKED_STACK_ID + " true";
+ mDevice.executeShellCommand(cmd);
+ CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
+ mDevice.executeShellCommand(AM_STACK_LIST, outputReceiver);
+ final String output = outputReceiver.getOutput();
+ HashSet<Integer> stacks = new HashSet<>();
+ for (String line : output.split("\\n")) {
+ CLog.logAndDisplay(LogLevel.INFO, line);
+ if (line.startsWith(STACK_ID_PREFIX)) {
+ final String sub = line.substring(STACK_ID_PREFIX.length());
+ final int index = sub.indexOf(" ");
+ final int currentStack = Integer.parseInt(sub.substring(0, index));
+ stacks.add(currentStack);
+ }
+ }
+ assertTrue("At least two stacks expected, home and docked.", stacks.size() >= 2);
+ assertTrue("Stacks must contain home stack.", stacks.contains(HOME_STACK_ID));
+ assertTrue("Stacks must contain docked stack.", stacks.contains(DOCKED_STACK_ID));
+ }
+}
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index b231b25..30b0337 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -21,7 +21,6 @@
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -73,7 +72,7 @@
private IAbi mAbi;
/** A reference to the build. */
- private IFolderBuildInfo mBuildInfo;
+ private IBuildInfo mBuildInfo;
/** A reference to the device under test. */
private ITestDevice mDevice;
@@ -89,7 +88,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuildInfo = (IFolderBuildInfo) buildInfo;
+ mBuildInfo = buildInfo;
}
@Override
diff --git a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
index f41eabf..d91944a 100644
--- a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
@@ -26,7 +26,7 @@
import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
import com.android.tradefed.testtype.IAbi;
@@ -39,7 +39,7 @@
* Test to measure installation time of a APK.
*/
public class InstallTimeTest extends DeviceTestCase implements IAbiReceiver, IBuildReceiver {
- private IFolderBuildInfo mBuild;
+ private IBuildInfo mBuild;
private ITestDevice mDevice;
private IAbi mAbi;
@@ -55,7 +55,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = (IFolderBuildInfo) buildInfo;
+ mBuild = buildInfo;
}
@Override
@@ -75,7 +75,7 @@
MetricsReportLog report = new MetricsReportLog(mDevice.getSerialNumber(), mAbi.getName(),
String.format("%s#%s", getClass().getName(), "testInstallTime"));
final int NUMBER_REPEAT = 10;
- final IFolderBuildInfo build = mBuild;
+ final IBuildInfo build = mBuild;
final ITestDevice device = mDevice;
double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
@Override
diff --git a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
index cccf86d..4af40a2 100644
--- a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
@@ -24,7 +24,6 @@
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestRunResult;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.result.CollectingTestListener;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -47,7 +46,7 @@
private static final String TAG = "TaskSwitchingTest";
private final static String RUNNER = "android.support.test.runner.AndroidJUnitRunner";
private static final String RESULT_KEY = "COMPATIBILITY_TEST_RESULT";
- private IFolderBuildInfo mBuild;
+ private IBuildInfo mBuild;
private ITestDevice mDevice;
private ReportLog mReport = null;
private IAbi mAbi;
@@ -70,7 +69,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = (IFolderBuildInfo) buildInfo;
+ mBuild = buildInfo;
}
@Override
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index f93dfa4..facc4d8 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -21,10 +21,15 @@
LOCAL_MODULE := CtsUsbTests
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed_v2 compatibility-host-util tradefed-prebuilt
+
+LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
LOCAL_CTS_TEST_PACKAGE := android.usb
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
# Build the test APKs using their own makefiles
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/hostsidetests/usb/AndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to hostsidetests/usb/AndroidTest.xml
index 49d705a..013e97f 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/hostsidetests/usb/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,8 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for CTS USB host test cases">
+ <test class="com.android.compatibility.common.tradefed.testtype.JarHostTest" >
+ <option name="jar" value="CtsUsbTests.jar" />
+ </test>
+</configuration>
diff --git a/hostsidetests/usb/SerialTestApp/Android.mk b/hostsidetests/usb/SerialTestApp/Android.mk
index a8f51ad..80316b2 100644
--- a/hostsidetests/usb/SerialTestApp/Android.mk
+++ b/hostsidetests/usb/SerialTestApp/Android.mk
@@ -28,4 +28,7 @@
LOCAL_SDK_VERSION := current
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index 7c85707..5377711 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -16,7 +16,7 @@
package com.android.cts.usb;
import com.android.compatibility.common.util.AbiUtils;
-import com.android.cts.tradefed.build.CtsBuildHelper;
+import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestRunResult;
import com.android.tradefed.build.IBuildInfo;
@@ -45,7 +45,7 @@
private static final String APK_NAME="CtsUsbSerialTestApp.apk";
private ITestDevice mDevice;
private IAbi mAbi;
- private CtsBuildHelper mBuild;
+ private IBuildInfo mBuild;
@Override
public void setAbi(IAbi abi) {
@@ -54,7 +54,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mBuild = CtsBuildHelper.createBuildHelper(buildInfo);
+ mBuild = buildInfo;
}
@Override
@@ -62,7 +62,7 @@
super.setUp();
mDevice = getDevice();
mDevice.uninstallPackage(PACKAGE_NAME);
- File app = mBuild.getTestApp(APK_NAME);
+ File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
mDevice.installPackage(app, false, options);
}
diff --git a/libs/deviceutil/src/android/cts/util/DeviceReportLog.java b/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
index efc31f0..4dd185e 100644
--- a/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
+++ b/libs/deviceutil/src/android/cts/util/DeviceReportLog.java
@@ -45,7 +45,7 @@
public void deliverReportToHost(Instrumentation instrumentation) {
Log.i(TAG, "deliverReportToHost");
String report = generateReport();
- if (!report.equals("")) {
+ if (report != null && !report.isEmpty()) {
Bundle output = new Bundle();
output.putString(CTS_RESULT_KEY, report);
instrumentation.sendStatus(INST_STATUS_IN_PROGRESS, output);
diff --git a/libs/deviceutil/src/android/cts/util/MediaUtils.java b/libs/deviceutil/src/android/cts/util/MediaUtils.java
index b3ebbad..0a454b6 100755
--- a/libs/deviceutil/src/android/cts/util/MediaUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaUtils.java
@@ -160,6 +160,14 @@
return null;
}
+ public static boolean canEncode(MediaFormat format) {
+ if (sMCL.findEncoderForFormat(format) == null) {
+ Log.i(TAG, "no encoder for " + format);
+ return false;
+ }
+ return true;
+ }
+
public static boolean canDecode(MediaFormat format) {
if (sMCL.findDecoderForFormat(format) == null) {
Log.i(TAG, "no decoder for " + format);
@@ -407,6 +415,10 @@
return canDecode(format);
}
+ public static boolean checkEncoderForFormat(MediaFormat format) {
+ return check(canEncode(format), "no encoder for " + format);
+ }
+
public static boolean checkDecoderForFormat(MediaFormat format) {
return check(canDecode(format), "no decoder for " + format);
}
diff --git a/libs/migration/src/com/android/cts/migration/MigrationHelper.java b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
index d940cde..5fa0ff8 100644
--- a/libs/migration/src/com/android/cts/migration/MigrationHelper.java
+++ b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
@@ -1,7 +1,6 @@
package com.android.cts.migration;
import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.build.IFolderBuildInfo;
import java.io.File;
import java.io.FileNotFoundException;
@@ -19,11 +18,11 @@
private static final String CTS_BUILD_HELPER =
"com.android.cts.tradefed.build.CtsBuildHelper";
- public static File getTestFile(IFolderBuildInfo mBuild, String filename)
+ public static File getTestFile(IBuildInfo mBuild, String filename)
throws FileNotFoundException {
try {
Class<?> cls = Class.forName(COMPATIBILITY_BUILD_HELPER);
- Constructor<?> cons = cls.getConstructor(IFolderBuildInfo.class);
+ Constructor<?> cons = cls.getConstructor(IBuildInfo.class);
Object instance = cons.newInstance(mBuild);
Method method = cls.getMethod("getTestsDir");
File dir = (File) method.invoke(instance);
@@ -34,7 +33,6 @@
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// Ignore and fall back to CtsBuildHelper
- e.printStackTrace();
}
try {
Class<?> cls = Class.forName(CTS_BUILD_HELPER);
@@ -48,7 +46,6 @@
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
IllegalArgumentException | InvocationTargetException e) {
// Ignore
- e.printStackTrace();
}
throw new FileNotFoundException("Couldn't load file " + filename);
}
diff --git a/run_unit_tests.sh b/run_unit_tests.sh
index 4d0480f..d83da77 100755
--- a/run_unit_tests.sh
+++ b/run_unit_tests.sh
@@ -16,12 +16,12 @@
# Helper script for running unit tests for compatibility libraries
-checkFile() {
- if [ ! -f "$1" ]; then
- echo "Unable to locate $1"
- exit
- fi;
-}
+CTS_DIR=$(dirname ${0})
+source ${CTS_DIR}/test_defs.sh
+
+echo
+echo "---- BUILD ---- "
+echo
# check if in Android build env
if [ ! -z ${ANDROID_BUILD_TOP} ]; then
@@ -36,115 +36,43 @@
fi;
fi;
-############### Build the tests ###############
-make compatibility-common-util-tests compatibility-host-util-tests compatibility-device-util-tests compatibility-tradefed-tests cts-tradefed-tests_v2 compatibility-device-info-tests compatibility-manifest-generator-tests compatibility-host-media-preconditions-tests CompatibilityTestApp -j32
+BUILD_TARGETS="
+ compatibility-common-util-tests\
+ compatibility-host-util-tests\
+ compatibility-device-util-tests\
+ compatibility-tradefed-tests\
+ cts-tradefed-tests_v2\
+ compatibility-device-info-tests\
+ compatibility-manifest-generator-tests
+ compatibility-host-media-preconditions-tests\
+ CompatibilityTestApp"
-############### Run the device side tests ###############
-JAR_DIR=${ANDROID_HOST_OUT}/framework
-JARS="
- ddmlib-prebuilt\
- hosttestlib\
- tradefed-prebuilt"
-JAR_PATH=
-for JAR in $JARS; do
- checkFile ${JAR_DIR}/${JAR}.jar
- JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
-done
+pushd ${CTS_DIR}/..
+make ${BUILD_TARGETS} -j32
+BUILD_STATUS=$?
+popd
+if [ "${BUILD_STATUS}" != "0" ]; then
+ echo "BUILD FAILED - EXIT"
+ exit 1;
+fi;
-APK=${ANDROID_PRODUCT_OUT}/data/app/CompatibilityTestApp/CompatibilityTestApp.apk
-checkFile ${APK}
-TF_CONSOLE=com.android.tradefed.command.Console
-COMMON_PACKAGE=com.android.compatibility.common
-RUNNER=android.support.test.runner.AndroidJUnitRunner
-adb install -r -g ${APK}
-java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand instrument --package ${COMMON_PACKAGE} --runner ${RUNNER}
-adb uninstall ${COMMON_PACKAGE}
+echo
+echo "---- DEVICE-SIDE TESTS ---- "
+echo
+
+${CTS_DIR}/common/device-side/test-app/run_tests.sh
+
+echo
+echo "---- HOST TESTS ---- "
+echo
############### Run the host side tests ###############
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-common-util-tests\
- compatibility-host-util\
- compatibility-host-util-tests\
- compatibility-mock-tradefed\
- compatibility-tradefed-tests\
- ddmlib-prebuilt\
- hosttestlib\
- tradefed-prebuilt"
-JAR_PATH=
-for JAR in $JARS; do
- checkFile ${JAR_DIR}/${JAR}.jar
- JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
-done
+${CTS_DIR}/common/host-side/tradefed/tests/run_tests.sh
+${CTS_DIR}/common/host-side/manifest-generator/tests/run_tests.sh
+${CTS_DIR}/common/host-side/util/tests/run_tests.sh
+${CTS_DIR}/common/util/tests/run_tests.sh
-TEST_CLASSES="
- com.android.compatibility.common.tradefed.UnitTests\
- com.android.compatibility.common.util.HostUnitTests\
- com.android.compatibility.common.util.UnitTests"
+${CTS_DIR}/tools/cts-tradefed/tests/run_tests.sh
-for CLASS in ${TEST_CLASSES}; do
- java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} "$@"
-done
-
-############### Run the cts tests ###############
-JARS="
- compatibility-common-util-hostsidelib\
- compatibility-host-util\
- cts-tradefed-tests_v2\
- cts-tradefed_v2\
- ddmlib-prebuilt\
- hosttestlib\
- tradefed-prebuilt"
-JAR_PATH=
-for JAR in $JARS; do
- checkFile ${JAR_DIR}/${JAR}.jar
- JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
-done
-
-TEST_CLASSES="
- com.android.compatibility.tradefed.CtsTradefedTest"
-
-for CLASS in ${TEST_CLASSES}; do
- java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} "$@"
-done
-
-############### Run the manifest generator tests ###############
-JARS="
- compatibility-manifest-generator\
- compatibility-manifest-generator-tests\
- ddmlib-prebuilt\
- hosttestlib\
- tradefed-prebuilt"
-JAR_PATH=
-for JAR in $JARS; do
- checkFile ${JAR_DIR}/${JAR}.jar
- JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
-done
-
-TEST_CLASSES="
- com.android.compatibility.common.generator.ManifestGeneratorTest"
-
-for CLASS in ${TEST_CLASSES}; do
- java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} "$@"
-done
-
-############### Run precondition tests ###############
-JARS="
- tradefed-prebuilt\
- compatibility-host-util\
- cts-tradefed_v2\
- compatibility-host-media-preconditions\
- compatibility-host-media-preconditions-tests"
-JAR_PATH=
-for JAR in $JARS; do
- checkFile ${JAR_DIR}/${JAR}.jar
- JAR_PATH=${JAR_PATH}:${JAR_DIR}/${JAR}.jar
-done
-
-TEST_CLASSES="
- android.mediastress.cts.preconditions.MediaPreparerTest"
-
-for CLASS in ${TEST_CLASSES}; do
- java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} "$@"
-done
+${CTS_DIR}/tests/tests/mediastress/preconditions/tests/run_tests.sh
diff --git a/test_defs.sh b/test_defs.sh
new file mode 100644
index 0000000..5d5090d
--- /dev/null
+++ b/test_defs.sh
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Common tools for running unit tests of the compatibility libs
+
+JAR_DIR=${ANDROID_HOST_OUT}/framework
+TF_CONSOLE=com.android.tradefed.command.Console
+
+COMMON_JARS="
+ ddmlib-prebuilt\
+ hosttestlib\
+ tradefed-prebuilt"
+
+checkFile() {
+ if [ ! -f "$1" ]; then
+ echo "Unable to locate $1"
+ exit
+ fi;
+}
+
+build_jar_path() {
+ JAR_PATH=
+ for JAR in ${2} ${COMMON_JARS}; do
+ checkFile ${1}/${JAR}.jar
+ JAR_PATH=${JAR_PATH}:${1}/${JAR}.jar
+ done
+}
+
+run_tests() {
+ build_jar_path "${JAR_DIR}" "${2}"
+ for CLASS in ${1}; do
+ java $RDBG_FLAG -cp ${JAR_PATH} ${TF_CONSOLE} run singleCommand host -n --class ${CLASS} ${3}
+ done
+}
diff --git a/tests/accessibility/AndroidTest.xml b/tests/accessibility/AndroidTest.xml
index f60e6b1..7c7c480 100644
--- a/tests/accessibility/AndroidTest.xml
+++ b/tests/accessibility/AndroidTest.xml
@@ -20,12 +20,12 @@
<option name="test-file-name" value="CtsSomeAccessibilityServices.apk" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer" >
- <option name="run-command" value="settings put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
- <option name="run-command" value="settings put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
- <option name="run-command" value="settings put secure accessibility_enabled 1" />
- <option name="teardown-command" value="settings put secure enabled_accessibility_services """ />
- <option name="teardown-command" value="settings put secure touch_exploration_granted_accessibility_services """ />
- <option name="teardown-command" value="settings put secure accessibility_enabled 0" />
+ <option name="run-command" value="settings --user cur put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+ <option name="run-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+ <option name="run-command" value="settings --user cur put secure accessibility_enabled 1" />
+ <option name="teardown-command" value="settings --user cur put secure enabled_accessibility_services """ />
+ <option name="teardown-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services """ />
+ <option name="teardown-command" value="settings --user cur put secure accessibility_enabled 0" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.view.accessibility.cts" />
diff --git a/tests/accessibility/OldAndroidTest.xml b/tests/accessibility/OldAndroidTest.xml
index 7832508..d127319 100644
--- a/tests/accessibility/OldAndroidTest.xml
+++ b/tests/accessibility/OldAndroidTest.xml
@@ -15,11 +15,11 @@
-->
<configuration description="Base config for CTS package preparer">
<include name="common-config" />
- <option name="run-command:run-command" value="settings put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
- <option name="run-command:run-command" value="settings put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
- <option name="run-command:run-command" value="settings put secure accessibility_enabled 1" />
- <option name="run-command:teardown-command" value="settings put secure enabled_accessibility_services """ />
- <option name="run-command:teardown-command" value="settings put secure touch_exploration_granted_accessibility_services """ />
- <option name="run-command:teardown-command" value="settings put secure accessibility_enabled 0" />
+ <option name="run-command:run-command" value="settings --user cur put secure enabled_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+ <option name="run-command:run-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services android.view.accessibility.services/.SpeakingAccessibilityService:android.view.accessibility.services/.VibratingAccessibilityService" />
+ <option name="run-command:run-command" value="settings --user cur put secure accessibility_enabled 1" />
+ <option name="run-command:teardown-command" value="settings --user cur put secure enabled_accessibility_services """ />
+ <option name="run-command:teardown-command" value="settings --user cur put secure touch_exploration_granted_accessibility_services """ />
+ <option name="run-command:teardown-command" value="settings --user cur put secure accessibility_enabled 0" />
<option name="cts-apk-installer:test-file-name" value="CtsSomeAccessibilityServices.apk" />
</configuration>
diff --git a/tests/admin/AndroidTest.xml b/tests/admin/AndroidTest.xml
index 80b5b7b..6831d14 100644
--- a/tests/admin/AndroidTest.xml
+++ b/tests/admin/AndroidTest.xml
@@ -21,8 +21,9 @@
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <option name="run-command" value="dpm set-active-admin android.admin.app/.CtsDeviceAdminReceiver" />
- <option name="run-command" value="dpm set-active-admin android.admin.app/.CtsDeviceAdminReceiver2" />
+ <option name="run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver" />
+ <option name="run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver2" />
+ <option name="run-command" value="dpm set-device-owner --user cur android.admin.app/.CtsDeviceAdminDeviceOwner" />
</target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
diff --git a/tests/admin/OldAndroidTest.xml b/tests/admin/OldAndroidTest.xml
index a73921a..0cfada8 100644
--- a/tests/admin/OldAndroidTest.xml
+++ b/tests/admin/OldAndroidTest.xml
@@ -15,6 +15,6 @@
-->
<configuration description="CTS device admin test config">
<include name="common-config" />
- <option name="run-command:run-command" value="dpm set-active-admin android.admin.app/.CtsDeviceAdminReceiver" />
- <option name="run-command:run-command" value="dpm set-active-admin android.admin.app/.CtsDeviceAdminReceiver2" />
+ <option name="run-command:run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver" />
+ <option name="run-command:run-command" value="dpm set-active-admin --user cur android.admin.app/.CtsDeviceAdminReceiver2" />
</configuration>
diff --git a/tests/admin/app/AndroidManifest.xml b/tests/admin/app/AndroidManifest.xml
index 4f63bdc..0834579 100644
--- a/tests/admin/app/AndroidManifest.xml
+++ b/tests/admin/app/AndroidManifest.xml
@@ -22,6 +22,15 @@
<uses-library android:name="android.test.runner"/>
+ <receiver android:name="android.admin.app.CtsDeviceAdminDeviceOwner"
+ android:permission="android.permission.BIND_DEVICE_ADMIN">
+ <meta-data android:name="android.app.device_admin"
+ android:resource="@xml/device_admin" />
+ <intent-filter>
+ <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+ </intent-filter>
+ </receiver>
+
<receiver android:name="android.admin.app.CtsDeviceAdminReceiver"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data android:name="android.app.device_admin"
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/admin/TestDeviceAdminReceiver.java b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java
similarity index 61%
rename from apps/CtsVerifier/src/com/android/cts/verifier/admin/TestDeviceAdminReceiver.java
rename to tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java
index 5ecb36d..619f700 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/admin/TestDeviceAdminReceiver.java
+++ b/tests/admin/app/src/android/admin/app/CtsDeviceAdminDeviceOwner.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,15 +14,10 @@
* limitations under the License.
*/
-package com.android.cts.verifier.admin;
+package android.admin.app;
import android.app.admin.DeviceAdminReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-public class TestDeviceAdminReceiver extends DeviceAdminReceiver {
+public class CtsDeviceAdminDeviceOwner extends DeviceAdminReceiver {
- public static ComponentName getComponent(Context context) {
- return new ComponentName(context, TestDeviceAdminReceiver.class);
- }
}
diff --git a/tests/admin/app/src/android/admin/app/DeactivationTest.java b/tests/admin/app/src/android/admin/app/DeactivationTest.java
index 03c4375..d6a7bf8 100644
--- a/tests/admin/app/src/android/admin/app/DeactivationTest.java
+++ b/tests/admin/app/src/android/admin/app/DeactivationTest.java
@@ -31,12 +31,22 @@
private static final ComponentName RECEIVER2 = new ComponentName(PACKAGE,
CtsDeviceAdminReceiver2.class.getName());
+ // Device admin we use to reset password. Note profile owner can do this too,
+ // but DPM.clearProfileOwner() is hidden, so we just use a device owner.
+ private static final ComponentName DEVICE_OWNER = new ComponentName(PACKAGE,
+ CtsDeviceAdminDeviceOwner.class.getName());
+
public void testDeactivateAdmins() throws Exception {
DevicePolicyManager manager = (DevicePolicyManager)
getContext().getSystemService(Context.DEVICE_POLICY_SERVICE);
assertNotNull(manager);
+
+ manager.clearDeviceOwnerApp(PACKAGE);
+
manager.removeActiveAdmin(RECEIVER1);
manager.removeActiveAdmin(RECEIVER2);
+ manager.removeActiveAdmin(DEVICE_OWNER);
+
for (int i = 0; i < 1000 && isActive(manager); i++) {
try {
Thread.sleep(100);
@@ -50,6 +60,6 @@
private boolean isActive(DevicePolicyManager manager) {
return manager.isAdminActive(RECEIVER1) ||
manager.isAdminActive(RECEIVER2) ||
- manager.isDeviceOwnerApp(PACKAGE);
+ manager.isAdminActive(DEVICE_OWNER);
}
}
\ No newline at end of file
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 432cce5..86c708a 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -29,6 +29,7 @@
import android.os.UserManager;
import android.provider.Settings;
import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.Suppress;
import android.util.Log;
import java.util.List;
@@ -98,6 +99,8 @@
mDevicePolicyManager.setPasswordQuality(mComponent,
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
mDevicePolicyManager.setPasswordMinimumLength(mComponent, 0);
+
+ // Note resetPassword() doesn't take "who", but because the caller package has
assertTrue(mDevicePolicyManager.resetPassword("", 0));
}
@@ -674,6 +677,9 @@
}
}
+ // This test registers itself as DO, so this is no longer testable. We do a positive test
+ // for clearDeviceOwnerApp()
+ @Suppress
public void testClearDeviceOwnerApp_failIfNotDeviceOwner() {
if (!mDeviceAdmin) {
Log.w(TAG, "Skipping testClearDeviceOwnerApp_failIfNotDeviceOwner");
diff --git a/tests/app/AndroidTest.xml b/tests/app/AndroidTest.xml
index 5a4c7ef..3725db8 100644
--- a/tests/app/AndroidTest.xml
+++ b/tests/app/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS App test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsSimpleApp.apk" />
@@ -23,4 +24,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.app.cts" />
</test>
-</configuration>
\ No newline at end of file
+
+</configuration>
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index e4ebebc..21cf064 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -183,6 +183,14 @@
</intent-filter>
</activity>
+ <activity android:name="android.app.stubs.FragmentTestActivity"
+ android:label="FragmentTestActivity">
+ <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.app.stubs.ChildTabActivity" android:label="ChildTabActivity" />
<activity android:name="android.app.stubs.LauncherActivityStub"
diff --git a/tests/app/app/res/layout/activity_content.xml b/tests/app/app/res/layout/activity_content.xml
new file mode 100644
index 0000000..8870e60
--- /dev/null
+++ b/tests/app/app/res/layout/activity_content.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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/content"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
diff --git a/tests/app/app/res/layout/fragment_end.xml b/tests/app/app/res/layout/fragment_end.xml
new file mode 100644
index 0000000..aa3d9e8
--- /dev/null
+++ b/tests/app/app/res/layout/fragment_end.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:transitionName="destination"
+ android:id="@+id/hello"
+ android:text="@string/hello"/>
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#0F0"
+ android:id="@+id/greenSquare"/>
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#F00"
+ android:id="@+id/redSquare"/>
+</LinearLayout>
diff --git a/tests/app/app/res/layout/fragment_start.xml b/tests/app/app/res/layout/fragment_start.xml
new file mode 100644
index 0000000..793e9b5
--- /dev/null
+++ b/tests/app/app/res/layout/fragment_start.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#0F0"
+ android:id="@+id/greenSquare"/>
+ <View android:layout_width="10dp"
+ android:layout_height="10dp"
+ android:background="#F00"
+ android:id="@+id/redSquare"/>
+ <TextView android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:transitionName="source"
+ android:id="@+id/hello"
+ android:text="@string/hello"/>
+</LinearLayout>
diff --git a/tests/app/app/res/values/strings.xml b/tests/app/app/res/values/strings.xml
index c167278..5e9e6d7 100644
--- a/tests/app/app/res/values/strings.xml
+++ b/tests/app/app/res/values/strings.xml
@@ -176,4 +176,5 @@
text, I would love to see the kind of devices you guys now use! Guys, maybe some devices need longer string!
I think so, so how about double this string, like copy and paste! </string>
<string name="rectangle200">"M 0,0 l 200,0 l 0, 200 l -200, 0 z"</string>
+ <string name="hello">Hello World</string>
</resources>
diff --git a/tests/app/app/src/android/app/stubs/FragmentTestActivity.java b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
new file mode 100644
index 0000000..65ba911
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/FragmentTestActivity.java
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.stubs;
+
+import android.app.Activity;
+import android.app.Fragment;
+import android.content.Context;
+import android.os.Bundle;
+import android.transition.Transition;
+import android.transition.Transition.TransitionListener;
+import android.transition.TransitionInflater;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * A simple activity used for Fragment Transitions
+ */
+public class FragmentTestActivity extends Activity {
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.activity_content);
+ }
+
+ public static class TestFragment extends Fragment {
+ public static final int ENTER = 0;
+ public static final int RETURN = 1;
+ public static final int EXIT = 2;
+ public static final int REENTER = 3;
+ public static final int SHARED_ELEMENT_ENTER = 4;
+ public static final int SHARED_ELEMENT_RETURN = 5;
+ private static final int TRANSITION_COUNT = 6;
+
+ private static final String LAYOUT_ID = "layoutId";
+ private static final String TRANSITION_KEY = "transition_";
+ private int mLayoutId = R.layout.fragment_start;
+ private final int[] mTransitionIds = new int[] {
+ android.R.transition.explode,
+ android.R.transition.explode,
+ android.R.transition.fade,
+ android.R.transition.fade,
+ android.R.transition.move,
+ android.R.transition.move,
+ };
+ private final TransitionCalledListener[] mListeners =
+ new TransitionCalledListener[TRANSITION_COUNT];
+ private OnTransitionListener mOnTransitionListener;
+
+ public TestFragment() {
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ mListeners[i] = new TransitionCalledListener();
+ }
+ }
+
+ public TestFragment(int layoutId) {
+ this();
+ mLayoutId = layoutId;
+ }
+
+ public void clearTransitions() {
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ mTransitionIds[i] = 0;
+ }
+ }
+
+ public void clearNotifications() {
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ mListeners[i].transitionStarted = false;
+ mListeners[i].transitionEnded = false;
+ }
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ if (savedInstanceState != null) {
+ mLayoutId = savedInstanceState.getInt(LAYOUT_ID, mLayoutId);
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ String key = TRANSITION_KEY + i;
+ mTransitionIds[i] = savedInstanceState.getInt(key, mTransitionIds[i]);
+ }
+ }
+ }
+
+ @Override
+ public void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putInt(LAYOUT_ID, mLayoutId);
+ for (int i = 0; i < TRANSITION_COUNT; i++) {
+ String key = TRANSITION_KEY + i;
+ outState.putInt(key, mTransitionIds[i]);
+ }
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ return inflater.inflate(mLayoutId, container, false);
+ }
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ setEnterTransition(loadTransition(ENTER));
+ setReenterTransition(loadTransition(REENTER));
+ setExitTransition(loadTransition(EXIT));
+ setReturnTransition(loadTransition(RETURN));
+ setSharedElementEnterTransition(loadTransition(SHARED_ELEMENT_ENTER));
+ setSharedElementReturnTransition(loadTransition(SHARED_ELEMENT_RETURN));
+ }
+
+ public void setOnTransitionListener(OnTransitionListener listener) {
+ mOnTransitionListener = listener;
+ }
+
+ public boolean wasStartCalled(int transitionKey) {
+ return mListeners[transitionKey].transitionStarted;
+ }
+
+ public boolean wasEndCalled(int transitionKey) {
+ return mListeners[transitionKey].transitionEnded;
+ }
+
+ private Transition loadTransition(int key) {
+ final int id = mTransitionIds[key];
+ if (id == 0) {
+ return null;
+ }
+ Transition transition = TransitionInflater.from(getActivity()).inflateTransition(id);
+ transition.addListener(mListeners[key]);
+ return transition;
+ }
+
+ private void notifyTransition() {
+ if (mOnTransitionListener != null) {
+ mOnTransitionListener.onTransition(this);
+ }
+ }
+
+ private class TransitionCalledListener implements TransitionListener {
+ public boolean transitionStarted;
+ public boolean transitionEnded;
+
+ public TransitionCalledListener() {
+ }
+
+ @Override
+ public void onTransitionStart(Transition transition) {
+ transitionStarted = true;
+ notifyTransition();
+ }
+
+ @Override
+ public void onTransitionEnd(Transition transition) {
+ transitionEnded = true;
+ notifyTransition();
+ }
+
+ @Override
+ public void onTransitionCancel(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionPause(Transition transition) {
+ }
+
+ @Override
+ public void onTransitionResume(Transition transition) {
+ }
+ }
+ }
+
+ public interface OnTransitionListener {
+ void onTransition(TestFragment fragment);
+ }
+
+}
diff --git a/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
index 89a5d9f..8e28ee4 100644
--- a/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
+++ b/tests/app/app/src/android/app/stubs/LocalActivityManagerTestHelper.java
@@ -97,7 +97,7 @@
return;
}
- if (!activity.getClass().getName().equals("android.app.cts."
+ if (!activity.getClass().getName().equals("android.app.stubs."
+ "LocalActivityManagerStubActivity")) {
fail();
return;
diff --git a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
index 74baa46..cb331d1 100644
--- a/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerMemoryClassTest.java
@@ -73,8 +73,8 @@
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_TV, 48);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_HIGH, 48);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_280, 48);
- expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 48);
- expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 64);
+ expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XHIGH, 80);
+ expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_360, 80);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_400, 96);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_420, 112);
expectedMemorySizeForSmallNormalScreen.put(DisplayMetrics.DENSITY_XXHIGH, 128);
diff --git a/tests/app/src/android/app/cts/FragmentTransitionTest.java b/tests/app/src/android/app/cts/FragmentTransitionTest.java
new file mode 100644
index 0000000..7270672
--- /dev/null
+++ b/tests/app/src/android/app/cts/FragmentTransitionTest.java
@@ -0,0 +1,466 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.cts;
+
+import android.app.FragmentManager;
+import android.app.stubs.FragmentTestActivity;
+import android.app.stubs.FragmentTestActivity.OnTransitionListener;
+import android.app.stubs.FragmentTestActivity.TestFragment;
+import android.app.stubs.R;
+import android.os.Debug;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.View;
+
+public class FragmentTransitionTest extends
+ ActivityInstrumentationTestCase2<FragmentTestActivity> {
+ private TestFragment mStartFragment;
+ private TestFragment mMidFragment;
+ private TestFragment mEndFragment;
+ private FragmentTestActivity mActivity;
+
+ public FragmentTransitionTest() {
+ super(FragmentTestActivity.class);
+ }
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mStartFragment = null;
+ mMidFragment = null;
+ mEndFragment = null;
+ mActivity = getActivity();
+ }
+
+ public void testFragmentTransition() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.ENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ mStartFragment.clearNotifications();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final View sharedElement = mActivity.findViewById(R.id.hello);
+ assertEquals("source", sharedElement.getTransitionName());
+
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mEndFragment)
+ .addSharedElement(sharedElement, "destination")
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.ENTER);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.SHARED_ELEMENT_ENTER));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final View textView = mActivity.findViewById(R.id.hello);
+ assertEquals("destination", textView.getTransitionName());
+ mActivity.getFragmentManager().popBackStack();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.REENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ }
+
+ public void testFirstOutLastInTransition() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.ENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ mStartFragment.clearNotifications();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mMidFragment = new TestFragment(R.layout.checkbox_layout);
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mMidFragment)
+ .replace(R.id.content, mEndFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.ENTER);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ mStartFragment.clearNotifications();
+ mEndFragment.clearNotifications();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getFragmentManager().popBackStack();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.RETURN);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+ }
+
+ public void testPopTwo() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.ENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ mStartFragment.clearNotifications();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mMidFragment = new TestFragment(R.layout.checkbox_layout);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mMidFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mMidFragment, TestFragment.ENTER);
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mEndFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.ENTER);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertTrue(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertTrue(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ mStartFragment.clearNotifications();
+ mMidFragment.clearNotifications();
+ mEndFragment.clearNotifications();
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ FragmentManager fm = mActivity.getFragmentManager();
+ int id = fm.getBackStackEntryAt(0).getId();
+ fm.popBackStack(id, FragmentManager.POP_BACK_STACK_INCLUSIVE);
+ fm.executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.RETURN);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ assertTrue(mStartFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+ }
+
+ public void testNullTransition() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mStartFragment.clearTransitions();
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForStart(mStartFragment, TestFragment.ENTER);
+ // No transitions
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mMidFragment = new TestFragment(R.layout.checkbox_layout);
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mEndFragment.clearTransitions();
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mMidFragment)
+ .replace(R.id.content, mEndFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForStart(mEndFragment, TestFragment.ENTER);
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mStartFragment.wasEndCalled(TestFragment.REENTER));
+
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getFragmentManager().popBackStack();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForStart(mEndFragment, TestFragment.RETURN);
+ assertFalse(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mMidFragment.wasStartCalled(TestFragment.RETURN));
+
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+ }
+
+ public void testRemoveAdded() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.ENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ mStartFragment.clearNotifications();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mEndFragment)
+ .replace(R.id.content, mStartFragment)
+ .replace(R.id.content, mEndFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mEndFragment, TestFragment.ENTER);
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.ENTER));
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.EXIT));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getFragmentManager().popBackStack();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.REENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.REENTER));
+ assertTrue(mEndFragment.wasEndCalled(TestFragment.RETURN));
+ }
+
+ public void testAddRemoved() throws Throwable {
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartFragment = new TestFragment(R.layout.fragment_start);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mStartFragment)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForEnd(mStartFragment, TestFragment.ENTER);
+ assertTrue(mStartFragment.wasEndCalled(TestFragment.ENTER));
+ mStartFragment.clearNotifications();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mEndFragment = new TestFragment(R.layout.fragment_end);
+ mActivity.getFragmentManager().beginTransaction()
+ .replace(R.id.content, mEndFragment)
+ .replace(R.id.content, mStartFragment)
+ .addToBackStack(null)
+ .commit();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForStart(mStartFragment, TestFragment.ENTER);
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.EXIT));
+ assertFalse(mEndFragment.wasStartCalled(TestFragment.ENTER));
+ assertFalse(mEndFragment.wasStartCalled(TestFragment.EXIT));
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.getFragmentManager().popBackStack();
+ mActivity.getFragmentManager().executePendingTransactions();
+ }
+ });
+ waitForStart(mStartFragment, TestFragment.REENTER);
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mStartFragment.wasStartCalled(TestFragment.RETURN));
+ assertFalse(mEndFragment.wasStartCalled(TestFragment.REENTER));
+ assertFalse(mEndFragment.wasStartCalled(TestFragment.RETURN));
+ }
+
+ private boolean waitForStart(TestFragment fragment, int key) throws InterruptedException {
+ final boolean started;
+ WaitForTransition listener = new WaitForTransition(key, true);
+ fragment.setOnTransitionListener(listener);
+ final long endTime = SystemClock.uptimeMillis() + 100;
+ synchronized (listener) {
+ long waitTime;
+ while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
+ !listener.isDone()) {
+ listener.wait(waitTime);
+ }
+ started = listener.isDone();
+ }
+ fragment.setOnTransitionListener(null);
+ getInstrumentation().waitForIdleSync();
+ return started;
+ }
+
+ private boolean waitForEnd(TestFragment fragment, int key) throws InterruptedException {
+ if (!waitForStart(fragment, key)) {
+ return false;
+ }
+ final boolean ended;
+ WaitForTransition listener = new WaitForTransition(key, false);
+ fragment.setOnTransitionListener(listener);
+ final long endTime = SystemClock.uptimeMillis() + 400;
+ synchronized (listener) {
+ long waitTime;
+ while ((waitTime = endTime - SystemClock.uptimeMillis()) > 0 &&
+ !listener.isDone()) {
+ listener.wait(waitTime);
+ }
+ ended = listener.isDone();
+ }
+ fragment.setOnTransitionListener(null);
+ getInstrumentation().waitForIdleSync();
+ return ended;
+ }
+
+ private static class WaitForTransition implements OnTransitionListener {
+ final int key;
+ final boolean isStart;
+ boolean isDone;
+
+ public WaitForTransition(int key, boolean isStart) {
+ this.key = key;
+ this.isStart = isStart;
+ }
+
+ protected boolean isComplete(TestFragment fragment) {
+ if (isStart) {
+ return fragment.wasStartCalled(key);
+ } else {
+ return fragment.wasEndCalled(key);
+ }
+ }
+
+ public synchronized boolean isDone() {
+ return isDone;
+ }
+
+ @Override
+ public synchronized void onTransition(TestFragment fragment) {
+ isDone = isComplete(fragment);
+ if (isDone) {
+ notifyAll();
+ }
+ }
+ }
+
+}
diff --git a/tests/app/src/android/app/cts/InstrumentationTest.java b/tests/app/src/android/app/cts/InstrumentationTest.java
index 85b8124..5019586 100644
--- a/tests/app/src/android/app/cts/InstrumentationTest.java
+++ b/tests/app/src/android/app/cts/InstrumentationTest.java
@@ -200,7 +200,7 @@
if (mActivity.getWindow().hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
mInstrumentation.invokeMenuActionSync(mActivity, resId, 0);
mInstrumentation.waitForIdleSync();
-
+
assertEquals(resId, mActivity.getMenuID());
}
}
@@ -691,6 +691,14 @@
}
@Override
+ public void setDecorCaptionShade(int decorCaptionShade) {
+ }
+
+ @Override
+ public void setResizingCaptionDrawable(Drawable drawable) {
+ }
+
+ @Override
public int getNavigationBarColor() {
return 0;
}
diff --git a/tests/app/src/android/app/cts/NotificationTest.java b/tests/app/src/android/app/cts/NotificationTest.java
index 1384b43..9da1b25 100644
--- a/tests/app/src/android/app/cts/NotificationTest.java
+++ b/tests/app/src/android/app/cts/NotificationTest.java
@@ -162,34 +162,25 @@
.setContentTitle(CONTENT_TITLE)
.setContentText(CONTENT_TEXT)
.setContentIntent(contentIntent)
- .addTopic(new Topic("id1", "label1"))
- .addTopic(new Topic("id2", "label2"))
+ .setTopic(new Topic("id1", "label1"))
.build();
assertEquals(CONTENT_TEXT, mNotification.extras.getString(Notification.EXTRA_TEXT));
assertEquals(CONTENT_TITLE, mNotification.extras.getString(Notification.EXTRA_TITLE));
assertEquals(1, mNotification.icon);
assertEquals(contentIntent, mNotification.contentIntent);
- List<Topic> topics = Arrays.asList(mNotification.getTopics());
- assertEquals(2, topics.size());
- assertTrue(topics.contains(new Topic("id1", "label1")));
- assertTrue(topics.contains(new Topic("id2", "label2")));
- assertNotNull(mNotification.contentView);
+ assertEquals(new Topic("id1", "label1"), mNotification.getTopic());
}
- public void testWriteTopicsToParcel() {
+ public void testWriteTopicToParcel() {
mNotification = new Notification.Builder(mContext)
- .addTopic(new Topic("id1", "label1"))
- .addTopic(new Topic("id2", "label2"))
+ .setTopic(new Topic("id2", "label2"))
.build();
Parcel parcel = Parcel.obtain();
mNotification.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
// Test Notification(Parcel)
Notification result = new Notification(parcel);
- List<Topic> topics = Arrays.asList(result.getTopics());
- assertEquals(2, topics.size());
- assertTrue(topics.contains(new Topic("id1", "label1")));
- assertTrue(topics.contains(new Topic("id2", "label2")));
+ assertEquals(new Topic("id2", "label2"), result.getTopic());
mNotification = new Notification();
parcel = Parcel.obtain();
@@ -197,7 +188,7 @@
parcel.setDataPosition(0);
// Test Notification(Parcel)
result = new Notification(parcel);
- assertNull(result.getTopics());
+ assertNull(result.getTopic());
}
public void testToString() {
diff --git a/tests/app/src/android/app/cts/UiModeManagerTest.java b/tests/app/src/android/app/cts/UiModeManagerTest.java
new file mode 100644
index 0000000..71a6427
--- /dev/null
+++ b/tests/app/src/android/app/cts/UiModeManagerTest.java
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.app.cts;
+
+import android.app.UiModeManager;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
+import android.test.AndroidTestCase;
+import android.util.Log;
+
+public class UiModeManagerTest extends AndroidTestCase {
+ private static final String TAG = "UiModeManagerTest";
+
+ private UiModeManager mUiModeManager;
+ private boolean mIsAuto = false;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mUiModeManager = (UiModeManager) getContext().getSystemService(Context.UI_MODE_SERVICE);
+ assertNotNull(mUiModeManager);
+ mIsAuto = getContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
+ public void testCarMode() throws Exception {
+ if (mIsAuto) {
+ Log.i(TAG, "testCarMode automotive");
+ doTestCarModeAutomotive();
+ } else {
+ Log.i(TAG, "testCarMode generic");
+ doTestCarModeGeneric();
+ }
+ }
+
+ private void doTestCarModeAutomotive() throws Exception {
+ assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+ assertTrue(mUiModeManager.isUiModeLocked());
+ doTestLockedUiMode();
+ assertTrue(mUiModeManager.isNightModeLocked());
+ doTestLockedNightMode();
+ }
+
+ private void doTestCarModeGeneric() throws Exception {
+ if (mUiModeManager.isUiModeLocked()) {
+ doTestLockedUiMode();
+ } else {
+ doTestUnlockedUiMode();
+ }
+ if (mUiModeManager.isNightModeLocked()) {
+ doTestLockedNightMode();
+ } else {
+ doTestUnlockedNightMode();
+ }
+ }
+
+ private void doTestLockedUiMode() throws Exception {
+ mUiModeManager.enableCarMode(0);
+ assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+ mUiModeManager.disableCarMode(0);
+ assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+ }
+
+ private void doTestUnlockedUiMode() throws Exception {
+ mUiModeManager.enableCarMode(0);
+ assertEquals(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+ mUiModeManager.disableCarMode(0);
+ assertNotSame(Configuration.UI_MODE_TYPE_CAR, mUiModeManager.getCurrentModeType());
+ }
+
+ private void doTestLockedNightMode() throws Exception {
+ int currentMode = mUiModeManager.getNightMode();
+ if (currentMode == UiModeManager.MODE_NIGHT_YES) {
+ mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_NO);
+ assertEquals(currentMode, mUiModeManager.getNightMode());
+ } else {
+ mUiModeManager.setNightMode(UiModeManager.MODE_NIGHT_YES);
+ assertEquals(currentMode, mUiModeManager.getNightMode());
+ }
+ }
+
+ private void doTestUnlockedNightMode() throws Exception {
+ // day night mode should be settable regardless of car mode.
+ mUiModeManager.enableCarMode(0);
+ doTestAllNightModes();
+ mUiModeManager.disableCarMode(0);
+ doTestAllNightModes();
+ }
+
+ private void doTestAllNightModes() {
+ assertNightModeChange(UiModeManager.MODE_NIGHT_AUTO);
+ assertNightModeChange(UiModeManager.MODE_NIGHT_YES);
+ assertNightModeChange(UiModeManager.MODE_NIGHT_NO);
+ }
+
+ private void assertNightModeChange(int mode) {
+ mUiModeManager.setNightMode(mode);
+ assertEquals(mode, mUiModeManager.getNightMode());
+ }
+}
diff --git a/tests/camera/Android.mk b/tests/camera/Android.mk
new file mode 100644
index 0000000..d072975
--- /dev/null
+++ b/tests/camera/Android.mk
@@ -0,0 +1,41 @@
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH:= $(call my-dir)
+
+# CtsCameraTestCases package
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil \
+ ctstestrunner \
+ mockito-target \
+ android-ex-camera2
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_PACKAGE_NAME := CtsCameraTestCases
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+
+cts_runtime_hint := 120
+
+include $(BUILD_CTS_PACKAGE)
diff --git a/tests/camera/AndroidManifest.xml b/tests/camera/AndroidManifest.xml
new file mode 100644
index 0000000..2b39fca
--- /dev/null
+++ b/tests/camera/AndroidManifest.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.camera.cts">
+ <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+ <uses-permission android:name="android.permission.CAMERA" />
+ <uses-permission android:name="android.permission.RECORD_AUDIO" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.REORDER_TASKS" />
+ <uses-permission android:name="android.permission.WAKE_LOCK" />
+
+ <application>
+ <uses-library android:name="android.test.runner" />
+
+ <activity android:name="android.hardware.cts.CameraCtsActivity"
+ android:label="CameraCtsActivity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
+ <activity android:name="android.hardware.camera2.cts.Camera2SurfaceViewCtsActivity"
+ android:label="Camera2CtsActivity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
+ <activity android:name="android.hardware.camera2.cts.Camera2MultiViewCtsActivity"
+ android:label="Camera2MultiViewCtsActivity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize">
+ </activity>
+
+ <activity android:name="android.hardware.cts.GLSurfaceViewCtsActivity"
+ android:label="GLSurfaceViewCtsActivity"/>
+
+ <service android:name="android.hardware.multiprocess.camera.cts.ErrorLoggingService"
+ android:label="ErrorLoggingService"
+ android:process=":errorLoggingServiceProcess"
+ android:exported="false">
+ </service>
+
+ <activity android:name="android.hardware.multiprocess.camera.cts.Camera1Activity"
+ android:label="RemoteCamera1Activity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:process=":camera1ActivityProcess">
+ </activity>
+
+ <activity android:name="android.hardware.multiprocess.camera.cts.Camera2Activity"
+ android:label="RemoteCamera2Activity"
+ android:screenOrientation="landscape"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:process=":camera2ActivityProcess">
+ </activity>
+
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.camera.cts"
+ android:label="CTS tests of android camera">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener" />
+ </instrumentation>
+
+</manifest>
+
diff --git a/tests/camera/AndroidTest.xml b/tests/camera/AndroidTest.xml
new file mode 100644
index 0000000..cb19b2c
--- /dev/null
+++ b/tests/camera/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Camera test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsCameraTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.camera.cts" />
+ </test>
+</configuration>
diff --git a/tests/tests/hardware/res/layout/multi_view.xml b/tests/camera/res/layout/multi_view.xml
similarity index 100%
rename from tests/tests/hardware/res/layout/multi_view.xml
rename to tests/camera/res/layout/multi_view.xml
diff --git a/tests/tests/hardware/res/layout/surface_view.xml b/tests/camera/res/layout/surface_view.xml
similarity index 100%
rename from tests/tests/hardware/res/layout/surface_view.xml
rename to tests/camera/res/layout/surface_view.xml
diff --git a/tests/tests/hardware/res/layout/surface_view_2.xml b/tests/camera/res/layout/surface_view_2.xml
similarity index 100%
rename from tests/tests/hardware/res/layout/surface_view_2.xml
rename to tests/camera/res/layout/surface_view_2.xml
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
rename to tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
index 229185d..0476477 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
@@ -97,7 +97,6 @@
assertNotNull("Can't connect to camera manager!", mCameraManager);
RenderScriptSingleton.setContext(context);
- // TODO: call clearContext
}
@Override
@@ -117,11 +116,7 @@
@Override
protected void tearDown() throws Exception {
MaybeNull.close(mCamera);
-
- // TODO: Clean up RenderScript context in a static test run finished method.
- // Or alternatively count the # of test methods that are in this test,
- // once we reach that count, it's time to call the last tear down
-
+ RenderScriptSingleton.clearContext();
mHandlerThread.quitSafely();
mHandler = null;
super.tearDown();
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
rename to tests/camera/src/android/hardware/camera2/cts/BurstCaptureRawTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
rename to tests/camera/src/android/hardware/camera2/cts/BurstCaptureTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java b/tests/camera/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java
rename to tests/camera/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java
index 16d2301..d6350fc 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java
+++ b/tests/camera/src/android/hardware/camera2/cts/Camera2MultiViewCtsActivity.java
@@ -23,7 +23,7 @@
import android.view.TextureView;
import android.view.WindowManager;
-import com.android.cts.hardware.R;
+import android.camera.cts.R;
public class Camera2MultiViewCtsActivity extends Activity {
private final static String TAG = "Camera2MultiViewCtsActivity";
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java b/tests/camera/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
rename to tests/camera/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
index 8a217fd..6773a9b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
+++ b/tests/camera/src/android/hardware/camera2/cts/Camera2SurfaceViewCtsActivity.java
@@ -23,7 +23,7 @@
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
-import com.android.cts.hardware.R;
+import android.camera.cts.R;
public class Camera2SurfaceViewCtsActivity extends Activity implements SurfaceHolder.Callback {
private final static String TAG = "Camera2SurfaceViewCtsActivity";
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
similarity index 94%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
rename to tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
index 44fda14..3778b95 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraDeviceTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraDeviceTest.java
@@ -425,6 +425,7 @@
// method on the camera device or session.
class ChainedCaptureCallback extends CameraCaptureSession.CaptureCallback {
+ @Override
public void onCaptureCompleted(CameraCaptureSession session, CaptureRequest request,
TotalCaptureResult result) {
try {
@@ -450,6 +451,7 @@
}
}
+ @Override
public void onCaptureFailed(CameraCaptureSession session, CaptureRequest request,
CaptureFailure failure) {
try {
@@ -466,6 +468,7 @@
class ChainedSessionListener extends CameraCaptureSession.StateCallback {
private final ChainedCaptureCallback mCaptureCallback = new ChainedCaptureCallback();
+ @Override
public void onConfigured(CameraCaptureSession session) {
try {
CaptureRequest.Builder request =
@@ -486,6 +489,7 @@
}
}
+ @Override
public void onConfigureFailed(CameraCaptureSession session) {
try {
CameraDevice camera = session.getDevice();
@@ -503,6 +507,7 @@
public CameraDevice cameraDevice;
+ @Override
public void onOpened(CameraDevice camera) {
cameraDevice = camera;
@@ -525,6 +530,7 @@
}
}
+ @Override
public void onDisconnected(CameraDevice camera) {
try {
camera.close();
@@ -534,6 +540,7 @@
}
}
+ @Override
public void onError(CameraDevice camera, int error) {
try {
camera.close();
@@ -1508,7 +1515,6 @@
}
}
- // Edge enhancement and noise reduction modes
boolean supportReprocessing =
availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_YUV_REPROCESSING) ||
availableCaps.contains(REQUEST_AVAILABLE_CAPABILITIES_PRIVATE_REPROCESSING);
@@ -1522,6 +1528,7 @@
CaptureRequest.COLOR_CORRECTION_MODE_TRANSFORM_MATRIX);
}
+ // Edge enhancement, noise reduction and aberration correction modes.
mCollector.expectEquals("Edge mode must be present in request if " +
"available edge modes are present in metadata, and vice-versa.",
mStaticInfo.areKeysAvailable(CameraCharacteristics.
@@ -1530,12 +1537,10 @@
if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
List<Integer> availableEdgeModes =
Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
+ // Don't need check fast as fast or high quality must be both present or both not.
if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_HIGH_QUALITY)) {
mCollector.expectKeyValueEquals(request, EDGE_MODE,
CaptureRequest.EDGE_MODE_HIGH_QUALITY);
- } else if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
- mCollector.expectKeyValueEquals(request, EDGE_MODE,
- CaptureRequest.EDGE_MODE_FAST);
} else {
mCollector.expectKeyValueEquals(request, EDGE_MODE,
CaptureRequest.EDGE_MODE_OFF);
@@ -1551,25 +1556,86 @@
CameraCharacteristics.NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES)) {
List<Integer> availableNoiseReductionModes =
Arrays.asList(toObject(mStaticInfo.getAvailableNoiseReductionModesChecked()));
+ // Don't need check fast as fast or high quality must be both present or both not.
if (availableNoiseReductionModes
.contains(CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY)) {
mCollector.expectKeyValueEquals(
request, NOISE_REDUCTION_MODE,
CaptureRequest.NOISE_REDUCTION_MODE_HIGH_QUALITY);
- } else if (availableNoiseReductionModes
- .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
- mCollector.expectKeyValueEquals(
- request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_FAST);
} else {
mCollector.expectKeyValueEquals(
request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
}
}
+
+ boolean supportAvailableAberrationModes = mStaticInfo.areKeysAvailable(
+ CameraCharacteristics.COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES);
+ boolean supportAberrationRequestKey = mStaticInfo.areKeysAvailable(
+ CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE);
+ mCollector.expectEquals("Aberration correction mode must be present in request if " +
+ "available aberration correction reductions are present in metadata, and "
+ + "vice-versa.", supportAvailableAberrationModes, supportAberrationRequestKey);
+ if (supportAberrationRequestKey) {
+ List<Integer> availableAberrationModes = Arrays.asList(
+ toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
+ // Don't need check fast as fast or high quality must be both present or both not.
+ if (availableAberrationModes
+ .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY)) {
+ mCollector.expectKeyValueEquals(
+ request, COLOR_CORRECTION_ABERRATION_MODE,
+ CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_HIGH_QUALITY);
+ } else {
+ mCollector.expectKeyValueEquals(
+ request, COLOR_CORRECTION_ABERRATION_MODE,
+ CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
+ }
+ }
} else if (template == CameraDevice.TEMPLATE_ZERO_SHUTTER_LAG && supportReprocessing) {
mCollector.expectKeyValueEquals(request, EDGE_MODE,
CaptureRequest.EDGE_MODE_ZERO_SHUTTER_LAG);
mCollector.expectKeyValueEquals(request, NOISE_REDUCTION_MODE,
CaptureRequest.NOISE_REDUCTION_MODE_ZERO_SHUTTER_LAG);
+ } else if (template == CameraDevice.TEMPLATE_PREVIEW ||
+ template == CameraDevice.TEMPLATE_RECORD){
+ List<Integer> availableEdgeModes =
+ Arrays.asList(toObject(mStaticInfo.getAvailableEdgeModesChecked()));
+ if (availableEdgeModes.contains(CaptureRequest.EDGE_MODE_FAST)) {
+ mCollector.expectKeyValueEquals(request, EDGE_MODE,
+ CaptureRequest.EDGE_MODE_FAST);
+ } else {
+ mCollector.expectKeyValueEquals(request, EDGE_MODE,
+ CaptureRequest.EDGE_MODE_OFF);
+ }
+
+ if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
+ List<Integer> availableNoiseReductionModes =
+ Arrays.asList(toObject(
+ mStaticInfo.getAvailableNoiseReductionModesChecked()));
+ if (availableNoiseReductionModes
+ .contains(CaptureRequest.NOISE_REDUCTION_MODE_FAST)) {
+ mCollector.expectKeyValueEquals(
+ request, NOISE_REDUCTION_MODE,
+ CaptureRequest.NOISE_REDUCTION_MODE_FAST);
+ } else {
+ mCollector.expectKeyValueEquals(
+ request, NOISE_REDUCTION_MODE, CaptureRequest.NOISE_REDUCTION_MODE_OFF);
+ }
+ }
+
+ if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
+ List<Integer> availableAberrationModes = Arrays.asList(
+ toObject(mStaticInfo.getAvailableColorAberrationModesChecked()));
+ if (availableAberrationModes
+ .contains(CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST)) {
+ mCollector.expectKeyValueEquals(
+ request, COLOR_CORRECTION_ABERRATION_MODE,
+ CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_FAST);
+ } else {
+ mCollector.expectKeyValueEquals(
+ request, COLOR_CORRECTION_ABERRATION_MODE,
+ CaptureRequest.COLOR_CORRECTION_ABERRATION_MODE_OFF);
+ }
+ }
} else {
if (mStaticInfo.areKeysAvailable(EDGE_MODE)) {
mCollector.expectKeyValueNotNull(request, EDGE_MODE);
@@ -1578,6 +1644,10 @@
if (mStaticInfo.areKeysAvailable(NOISE_REDUCTION_MODE)) {
mCollector.expectKeyValueNotNull(request, NOISE_REDUCTION_MODE);
}
+
+ if (mStaticInfo.areKeysAvailable(COLOR_CORRECTION_ABERRATION_MODE)) {
+ mCollector.expectKeyValueNotNull(request, COLOR_CORRECTION_ABERRATION_MODE);
+ }
}
// Tone map and lens shading modes.
@@ -1681,6 +1751,7 @@
* @param listener The {@link #CaptureCallback} camera device used to notify callbacks.
* @param handler The handler camera device used to post callbacks.
*/
+ @Override
protected void startCapture(CaptureRequest request, boolean repeating,
CameraCaptureSession.CaptureCallback listener, Handler handler)
throws CameraAccessException {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
rename to tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 77a0c8e..67c08fe 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -149,7 +149,8 @@
assertNotNull("Can't get lens facing info", lensFacing);
if (lensFacing == CameraCharacteristics.LENS_FACING_FRONT) {
assertTrue("System doesn't have front camera feature",
- mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT) ||
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
} else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
assertTrue("System doesn't have back camera feature",
mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA));
@@ -534,7 +535,7 @@
java.util.concurrent.TimeUnit.MILLISECONDS);
assertTrue(String.format("Received unavailability notice for wrong ID " +
"(expected %s, got %s)", id, candidateId),
- id == candidateId);
+ id.equals(candidateId));
assertTrue("Availability events received unexpectedly",
availableEventQueue.size() == 0);
@@ -549,7 +550,7 @@
java.util.concurrent.TimeUnit.MILLISECONDS);
assertTrue(String.format("Received availability notice for wrong ID " +
"(expected %s, got %s)", id, candidateId),
- id == candidateId);
+ id.equals(candidateId));
assertTrue("Unavailability events received unexpectedly",
unavailableEventQueue.size() == 0);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
rename to tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
index d78b3b5..85eeb0b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -818,7 +818,8 @@
ByteBuffer buffer = null;
// JPEG doesn't have pixelstride and rowstride, treat it as 1D buffer.
// Same goes for DEPTH_POINT_CLOUD
- if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD) {
+ if (format == ImageFormat.JPEG || format == ImageFormat.DEPTH_POINT_CLOUD ||
+ format == ImageFormat.RAW_PRIVATE) {
buffer = planes[0].getBuffer();
assertNotNull("Fail to get jpeg or depth ByteBuffer", buffer);
data = new byte[buffer.remaining()];
@@ -898,6 +899,7 @@
break;
case ImageFormat.JPEG:
case ImageFormat.RAW_SENSOR:
+ case ImageFormat.RAW_PRIVATE:
case ImageFormat.DEPTH16:
case ImageFormat.DEPTH_POINT_CLOUD:
assertEquals("JPEG/RAW/depth Images should have one plane", 1, planes.length);
@@ -1320,6 +1322,9 @@
case ImageFormat.DEPTH_POINT_CLOUD:
validateDepthPointCloudData(data, width, height, format, image.getTimestamp(), filePath);
break;
+ case ImageFormat.RAW_PRIVATE:
+ validateRawPrivateData(data, width, height, image.getTimestamp(), filePath);
+ break;
default:
throw new UnsupportedOperationException("Unsupported format for validation: "
+ format);
@@ -1416,6 +1421,26 @@
return;
}
+ private static void validateRawPrivateData(byte[] rawData, int width, int height,
+ long ts, String filePath) {
+ if (VERBOSE) Log.v(TAG, "Validating private raw data");
+ // Expect each RAW pixel should occupy at least one byte and no more than 2.5 bytes
+ int expectedSizeMin = width * height;
+ int expectedSizeMax = width * height * 5 / 2;
+
+ assertTrue("Opaque RAW size " + rawData.length + "out of normal bound [" +
+ expectedSizeMin + "," + expectedSizeMax + "]",
+ expectedSizeMin <= rawData.length && rawData.length <= expectedSizeMax);
+
+ if (DEBUG && filePath != null) {
+ String fileName =
+ filePath + "/" + width + "x" + height + "_" + ts / 1e6 + ".rawPriv";
+ dumpFile(fileName, rawData);
+ }
+
+ return;
+ }
+
private static void validateDepth16Data(byte[] depthData, int width, int height, int format,
long ts, String filePath) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
similarity index 91%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
rename to tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
index dd4e3e3..a4e1917 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureRequestTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureRequestTest.java
@@ -29,18 +29,20 @@
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
+import android.hardware.camera2.params.BlackLevelPattern;
import android.hardware.camera2.params.ColorSpaceTransform;
import android.hardware.camera2.params.Face;
import android.hardware.camera2.params.LensShadingMap;
import android.hardware.camera2.params.MeteringRectangle;
import android.hardware.camera2.params.RggbChannelVector;
import android.hardware.camera2.params.TonemapCurve;
-
+import android.media.Image;
import android.util.Log;
import android.util.Range;
import android.util.Rational;
import android.util.Size;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -85,11 +87,12 @@
private static final float FOCUS_DISTANCE_ERROR_PERCENT_APPROXIMATE = 0.10f;
private static final int ANTI_FLICKERING_50HZ = 1;
private static final int ANTI_FLICKERING_60HZ = 2;
-
// 5 percent error margin for resulting crop regions
private static final float CROP_REGION_ERROR_PERCENT_DELTA = 0.05f;
// 1 percent error margin for centering the crop region
private static final float CROP_REGION_ERROR_PERCENT_CENTERED = 0.01f;
+ private static final float DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN = 0.25f;
+ private static final float DYNAMIC_VS_OPTICAL_BLK_LVL_ERROR_MARGIN = 0.1f;
// Linear tone mapping curve example.
private static final float[] TONEMAP_CURVE_LINEAR = {0, 0, 1.0f, 1.0f};
@@ -178,6 +181,32 @@
}
/**
+ * Test dynamic black/white levels if they are supported.
+ *
+ * <p>
+ * If the dynamic black and white levels are reported, test below:
+ * 1. the dynamic black and white levels shouldn't deviate from the global value too much
+ * for different sensitivities.
+ * 2. If the RAW_SENSOR and optical black regions are supported, capture RAW images and
+ * calculate the optical black level values. The reported dynamic black level should be
+ * close enough to the optical black level values.
+ * </p>
+ */
+ public void testDynamicBlackWhiteLevel() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ openDevice(id);
+ if (!mStaticInfo.isDynamicBlackLevelSupported()) {
+ continue;
+ }
+ dynamicBlackWhiteLevelTestByCamera();
+ } finally {
+ closeDevice();
+ }
+ }
+ }
+
+ /**
* Basic lens shading map request test.
* <p>
* When {@link CaptureRequest#SHADING_MODE} is set to OFF, no lens shading correction will
@@ -630,6 +659,170 @@
// TODO: add 3A state machine test.
+ /**
+ * Per camera dynamic black and white level test.
+ */
+ private void dynamicBlackWhiteLevelTestByCamera() throws Exception {
+ SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+ SimpleImageReaderListener imageListener = null;
+ CaptureRequest.Builder previewBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ CaptureRequest.Builder rawBuilder = null;
+ Size previewSize =
+ getMaxPreviewSize(mCamera.getId(), mCameraManager,
+ getPreviewSizeBound(mWindowManager, PREVIEW_SIZE_BOUND));
+ Size rawSize = null;
+ boolean canCaptureBlackRaw =
+ mStaticInfo.isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_RAW) &&
+ mStaticInfo.isOpticalBlackRegionSupported();
+ if (canCaptureBlackRaw) {
+ // Capture Raw16, then calculate the optical black, and use it to check with the dynamic
+ // black level.
+ rawBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
+ rawSize = mStaticInfo.getRawDimensChecked();
+ imageListener = new SimpleImageReaderListener();
+ prepareRawCaptureAndStartPreview(previewBuilder, rawBuilder, previewSize, rawSize,
+ resultListener, imageListener);
+ } else {
+ startPreview(previewBuilder, previewSize, resultListener);
+ }
+
+ // Capture a sequence of frames with different sensitivities and validate the black/white
+ // level values
+ int[] sensitivities = getSensitivityTestValues();
+ float[][] dynamicBlackLevels = new float[sensitivities.length][];
+ int[] dynamicWhiteLevels = new int[sensitivities.length];
+ float[][] opticalBlackLevels = new float[sensitivities.length][];
+ for (int i = 0; i < sensitivities.length; i++) {
+ CaptureResult result = null;
+ if (canCaptureBlackRaw) {
+ changeExposure(rawBuilder, DEFAULT_EXP_TIME_NS, sensitivities[i]);
+ CaptureRequest rawRequest = rawBuilder.build();
+ mSession.capture(rawRequest, resultListener, mHandler);
+ result = resultListener.getCaptureResultForRequest(rawRequest,
+ NUM_RESULTS_WAIT_TIMEOUT);
+ Image rawImage = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+
+ // Get max (area-wise) optical black region
+ Rect[] opticalBlackRegions = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+ Rect maxRegion = opticalBlackRegions[0];
+ for (Rect region : opticalBlackRegions) {
+ if (region.width() * region.height() > maxRegion.width() * maxRegion.height()) {
+ maxRegion = region;
+ }
+ }
+
+ // Get average black pixel values in the region (region is multiple of 2x2)
+ Image.Plane rawPlane = rawImage.getPlanes()[0];
+ ByteBuffer rawBuffer = rawPlane.getBuffer();
+ float[] avgBlackLevels = {0, 0, 0, 0};
+ int rowSize = rawPlane.getRowStride() * rawPlane.getPixelStride();
+ int bytePerPixel = rawPlane.getPixelStride();
+ if (VERBOSE) {
+ Log.v(TAG, "maxRegion: " + maxRegion + ", Row stride: " +
+ rawPlane.getRowStride());
+ }
+ for (int row = maxRegion.left; row < maxRegion.right; row += 2) {
+ for (int col = maxRegion.top; col < maxRegion.bottom; col += 2) {
+ int startOffset = col * rawPlane.getRowStride() + row * bytePerPixel;
+ avgBlackLevels[0] += rawBuffer.getShort(startOffset);
+ avgBlackLevels[1] += rawBuffer.getShort(startOffset + bytePerPixel);
+ startOffset += rowSize;
+ avgBlackLevels[2] += rawBuffer.getShort(startOffset);
+ avgBlackLevels[3] += rawBuffer.getShort(startOffset + bytePerPixel);
+ }
+ }
+ int numBlackBlocks = maxRegion.width() * maxRegion.height() / (2 * 2);
+ for (int m = 0; m < avgBlackLevels.length; m++) {
+ avgBlackLevels[m] /= numBlackBlocks;
+ }
+ opticalBlackLevels[i] = avgBlackLevels;
+
+ if (VERBOSE) {
+ Log.v(TAG, String.format("Optical black level results for sensitivity (%d): %s",
+ sensitivities[i], Arrays.toString(avgBlackLevels)));
+ }
+
+ rawImage.close();
+ } else {
+ changeExposure(previewBuilder, DEFAULT_EXP_TIME_NS, sensitivities[i]);
+ CaptureRequest previewRequest = previewBuilder.build();
+ mSession.capture(previewRequest, resultListener, mHandler);
+ result = resultListener.getCaptureResultForRequest(previewRequest,
+ NUM_RESULTS_WAIT_TIMEOUT);
+ }
+
+ dynamicBlackLevels[i] = getValueNotNull(result,
+ CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+ dynamicWhiteLevels[i] = getValueNotNull(result,
+ CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+ }
+
+ if (VERBOSE) {
+ Log.v(TAG, "Different sensitivities tested: " + Arrays.toString(sensitivities));
+ Log.v(TAG, "Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels));
+ Log.v(TAG, "Dynamic white level results: " + Arrays.toString(dynamicWhiteLevels));
+ if (canCaptureBlackRaw) {
+ Log.v(TAG, "Optical black level results " +
+ Arrays.deepToString(opticalBlackLevels));
+ }
+ }
+
+ // check the dynamic black level against global black level.
+ // Implicit guarantee: if the dynamic black level is supported, fixed black level must be
+ // supported as well (tested in ExtendedCameraCharacteristicsTest#testOpticalBlackRegions).
+ BlackLevelPattern blackPattern = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
+ int[] fixedBlackLevels = new int[4];
+ int fixedWhiteLevel = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
+ blackPattern.copyTo(fixedBlackLevels, 0);
+ float maxBlackDeviation = 0;
+ int maxWhiteDeviation = 0;
+ for (int i = 0; i < dynamicBlackLevels.length; i++) {
+ for (int j = 0; j < dynamicBlackLevels[i].length; j++) {
+ if (maxBlackDeviation < Math.abs(fixedBlackLevels[j] - dynamicBlackLevels[i][j])) {
+ maxBlackDeviation = Math.abs(fixedBlackLevels[j] - dynamicBlackLevels[i][j]);
+ }
+ }
+ if (maxWhiteDeviation < Math.abs(dynamicWhiteLevels[i] - fixedWhiteLevel)) {
+ maxWhiteDeviation = Math.abs(dynamicWhiteLevels[i] - fixedWhiteLevel);
+ }
+ }
+ mCollector.expectLessOrEqual("Max deviation of the dynamic black level vs fixed black level"
+ + " exceed threshold."
+ + " Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels),
+ fixedBlackLevels[0] * DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN, maxBlackDeviation);
+ mCollector.expectLessOrEqual("Max deviation of the dynamic white level exceed threshold."
+ + " Dynamic white level results: " + Arrays.toString(dynamicWhiteLevels),
+ fixedWhiteLevel * DYNAMIC_VS_FIXED_BLK_WH_LVL_ERROR_MARGIN,
+ (float)maxWhiteDeviation);
+
+ // Validate against optical black levels if it is available
+ if (canCaptureBlackRaw) {
+ maxBlackDeviation = 0;
+ for (int i = 0; i < dynamicBlackLevels.length; i++) {
+ for (int j = 0; j < dynamicBlackLevels[i].length; j++) {
+ if (maxBlackDeviation <
+ Math.abs(opticalBlackLevels[i][j] - dynamicBlackLevels[i][j])) {
+ maxBlackDeviation =
+ Math.abs(opticalBlackLevels[i][j] - dynamicBlackLevels[i][j]);
+ }
+ }
+ }
+
+ mCollector.expectLessOrEqual("Max deviation of the dynamic black level vs optical black"
+ + " exceed threshold."
+ + " Dynamic black level results: " + Arrays.deepToString(dynamicBlackLevels)
+ + " Optical black level results: " + Arrays.deepToString(opticalBlackLevels),
+ fixedBlackLevels[0] * DYNAMIC_VS_OPTICAL_BLK_LVL_ERROR_MARGIN,
+ maxBlackDeviation);
+ }
+ }
+
private void noiseReductionModeTestByCamera() throws Exception {
Size maxPrevSize = mOrderedPreviewSizes.get(0);
CaptureRequest.Builder requestBuilder =
@@ -2111,7 +2304,7 @@
* @param result Result sensitivity
*/
private void validateSensitivity(int request, int result) {
- float sensitivityDelta = (float)(request - result);
+ float sensitivityDelta = request - result;
float sensitivityErrorMargin = request * SENSITIVITY_ERROR_MARGIN_RATE;
// First, round down not up, second, need close enough.
mCollector.expectTrue("Sensitivity is invalid for AE manaul control test, request: "
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
rename to tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index 2ae29c3..199552f 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -509,6 +509,12 @@
waiverKeys.add(CaptureResult.CONTROL_AF_REGIONS);
}
+ // Keys for dynamic black/white levels
+ if (!mStaticInfo.isOpticalBlackRegionSupported()) {
+ waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+ waiverKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+ }
+
if (mStaticInfo.isHardwareLevelFull()) {
return waiverKeys;
}
@@ -775,6 +781,8 @@
resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_DATA);
resultKeys.add(CaptureResult.SENSOR_TEST_PATTERN_MODE);
resultKeys.add(CaptureResult.SENSOR_ROLLING_SHUTTER_SKEW);
+ resultKeys.add(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+ resultKeys.add(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
resultKeys.add(CaptureResult.SHADING_MODE);
resultKeys.add(CaptureResult.STATISTICS_FACE_DETECT_MODE);
resultKeys.add(CaptureResult.STATISTICS_HOT_PIXEL_MAP_MODE);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java b/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
similarity index 99%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
rename to tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
index 0da0ce7..bddbd52 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/DngCreatorTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/DngCreatorTest.java
@@ -75,6 +75,8 @@
@Override
protected void tearDown() throws Exception {
+ RenderScriptSingleton.clearContext();
+
super.tearDown();
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
similarity index 93%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
rename to tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
index 6d62067..5b21e4d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ExtendedCameraCharacteristicsTest.java
@@ -24,6 +24,7 @@
import android.hardware.camera2.CameraCharacteristics.Key;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.cts.helpers.CameraErrorCollector;
import android.hardware.camera2.params.BlackLevelPattern;
import android.hardware.camera2.params.ColorSpaceTransform;
@@ -178,9 +179,10 @@
if (activeArraySize.getWidth() >= FULLHD.getWidth() &&
activeArraySize.getHeight() >= FULLHD.getHeight()) {
- assertArrayContains(String.format(
+ assertArrayContainsAnyOf(String.format(
"Required FULLHD size not found for format %x for: ID %s",
- ImageFormat.JPEG, mIds[counter]), jpegSizes, FULLHD);
+ ImageFormat.JPEG, mIds[counter]), jpegSizes,
+ new Size[] {FULLHD, FULLHD_ALT});
}
if (activeArraySize.getWidth() >= HD.getWidth() &&
@@ -1180,6 +1182,82 @@
}
/**
+ * Sanity check of optical black regions.
+ */
+ public void testOpticalBlackRegions() {
+ int counter = 0;
+ for (CameraCharacteristics c : mCharacteristics) {
+ List<CaptureResult.Key<?>> resultKeys = c.getAvailableCaptureResultKeys();
+ boolean hasDynamicBlackLevel =
+ resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+ boolean hasDynamicWhiteLevel =
+ resultKeys.contains(CaptureResult.SENSOR_DYNAMIC_WHITE_LEVEL);
+ boolean hasFixedBlackLevel =
+ c.getKeys().contains(CameraCharacteristics.SENSOR_BLACK_LEVEL_PATTERN);
+ boolean hasFixedWhiteLevel =
+ c.getKeys().contains(CameraCharacteristics.SENSOR_INFO_WHITE_LEVEL);
+ // The black and white levels should be either all supported or none of them is
+ // supported.
+ mCollector.expectTrue("Dynamic black and white level should be all or none of them"
+ + " be supported", hasDynamicWhiteLevel == hasDynamicBlackLevel);
+ mCollector.expectTrue("Fixed black and white level should be all or none of them"
+ + " be supported", hasFixedBlackLevel == hasFixedWhiteLevel);
+ mCollector.expectTrue("Fixed black level should be supported if dynamic black"
+ + " level is supported", !hasDynamicBlackLevel || hasFixedBlackLevel);
+
+ if (c.getKeys().contains(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS)) {
+ // Regions shouldn't be null or empty.
+ Rect[] regions = CameraTestUtils.getValueNotNull(c,
+ CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+ CameraTestUtils.assertArrayNotEmpty(regions, "Optical back region arrays must not"
+ + " be empty");
+
+ // Dynamic black level should be supported if the optical black region is
+ // advertised.
+ mCollector.expectTrue("Dynamic black and white level keys should be advertised in "
+ + "available capture result key list", hasDynamicWhiteLevel);
+
+ // Range check.
+ for (Rect region : regions) {
+ mCollector.expectTrue("Camera " + mIds[counter] + ": optical black region" +
+ " shouldn't be empty!", !region.isEmpty());
+ mCollector.expectGreaterOrEqual("Optical black region left", 0/*expected*/,
+ region.left/*actual*/);
+ mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
+ region.top/*actual*/);
+ mCollector.expectTrue("Optical black region left/right/width/height must be"
+ + " even number, otherwise, the bayer CFA pattern in this region will"
+ + " be messed up",
+ region.left % 2 == 0 && region.top % 2 == 0 &&
+ region.width() % 2 == 0 && region.height() % 2 == 0);
+ mCollector.expectGreaterOrEqual("Optical black region top", 0/*expected*/,
+ region.top/*actual*/);
+ Size size = CameraTestUtils.getValueNotNull(c,
+ CameraCharacteristics.SENSOR_INFO_PIXEL_ARRAY_SIZE);
+ mCollector.expectLessOrEqual("Optical black region width",
+ size.getWidth()/*expected*/, region.width());
+ mCollector.expectLessOrEqual("Optical black region height",
+ size.getHeight()/*expected*/, region.height());
+ Rect activeArray = CameraTestUtils.getValueNotNull(c,
+ CameraCharacteristics.SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE);
+ mCollector.expectTrue("Optical black region" + region + " should be outside of"
+ + " active array " + activeArray,
+ !region.intersect(activeArray));
+ // Region need to be disjoint:
+ for (Rect region2 : regions) {
+ mCollector.expectTrue("Optical black region" + region + " should have no "
+ + "overlap with " + region2,
+ region == region2 || !region.intersect(region2));
+ }
+ }
+ } else {
+ Log.i(TAG, "Camera " + mIds[counter] + " doesn't support optical black regions,"
+ + " skip the region test");
+ }
+ counter++;
+ }
+ }
+ /**
* Create an invalid size that's close to one of the good sizes in the list, but not one of them
*/
private Size findInvalidSize(Size[] goodSizes) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/FlashlightTest.java b/tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/FlashlightTest.java
rename to tests/camera/src/android/hardware/camera2/cts/FlashlightTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
similarity index 94%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
rename to tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
index f1115c4..1e9fe55 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -41,8 +41,11 @@
import android.util.Size;
import android.view.Surface;
+import com.android.ex.camera2.blocking.BlockingSessionCallback;
+
import java.nio.ByteBuffer;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
import static android.hardware.camera2.cts.CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS;
@@ -157,6 +160,20 @@
}
}
+ public void testRawPrivate() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Testing raw capture for camera " + id);
+ openDevice(id);
+
+ bufferFormatTestByCamera(ImageFormat.RAW_PRIVATE, /*repeating*/false);
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
+
+
public void testRepeatingJpeg() throws Exception {
for (String id : mCameraIds) {
try {
@@ -182,6 +199,19 @@
}
}
+ public void testRepeatingRawPrivate() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Testing repeating raw capture for camera " + id);
+ openDevice(id);
+
+ bufferFormatTestByCamera(ImageFormat.RAW_PRIVATE, /*repeating*/true);
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
+
public void testLongProcessingRepeatingRaw() throws Exception {
for (String id : mCameraIds) {
try {
@@ -275,6 +305,8 @@
* resolution and format supported.
*/
public void testAllOutputYUVResolutions() throws Exception {
+ Integer[] sessionStates = {BlockingSessionCallback.SESSION_READY,
+ BlockingSessionCallback.SESSION_CONFIGURE_FAILED};
for (String id : mCameraIds) {
try {
Log.v(TAG, "Testing all YUV image resolutions for camera " + id);
@@ -309,6 +341,7 @@
", at least one JPEG output is required.", jpegSizes.length == 0);
Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+ Size maxPreviewSize = mOrderedPreviewSizes.get(0);
for (int format : supportedYUVFormats) {
Size[] targetCaptureSizes =
@@ -343,6 +376,27 @@
outputSurfaces.add(jpegSurface);
createSession(outputSurfaces);
+ int state = mCameraSessionListener.getStateWaiter().waitForAnyOfStates(
+ Arrays.asList(sessionStates),
+ CameraTestUtils.SESSION_CONFIGURE_TIMEOUT_MS);
+
+ if (state == BlockingSessionCallback.SESSION_CONFIGURE_FAILED) {
+ if (captureSz.getWidth() > maxPreviewSize.getWidth() ||
+ captureSz.getHeight() > maxPreviewSize.getHeight()) {
+ Log.v(TAG, "Skip testing {yuv:" + captureSz
+ + " ,jpeg:" + maxJpegSize + "} for camera "
+ + mCamera.getId() +
+ " because full size jpeg + yuv larger than "
+ + "max preview size (" + maxPreviewSize
+ + ") is not supported");
+ continue;
+ } else {
+ fail("Camera " + mCamera.getId() +
+ ":session configuration failed for {jpeg: " +
+ maxJpegSize + ", yuv: " + captureSz + "}");
+ }
+ }
+
// Warm up camera preview (mainly to give legacy devices time to do 3A).
CaptureRequest.Builder warmupRequest =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java b/tests/camera/src/android/hardware/camera2/cts/ImageWriterTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/ImageWriterTest.java
rename to tests/camera/src/android/hardware/camera2/cts/ImageWriterTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java b/tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/MultiViewTest.java
rename to tests/camera/src/android/hardware/camera2/cts/MultiViewTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java b/tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/PerformanceTest.java
rename to tests/camera/src/android/hardware/camera2/cts/PerformanceTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
similarity index 95%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
rename to tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
index de0e3d5..4acbffe 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/RecordingTest.java
@@ -104,7 +104,7 @@
super.tearDown();
}
- private void doBasicRecording() throws Exception {
+ private void doBasicRecording(boolean useVideoStab) throws Exception {
for (int i = 0; i < mCameraIds.length; i++) {
try {
Log.i(TAG, "Testing basic recording for camera " + mCameraIds[i]);
@@ -116,9 +116,17 @@
" does not support color outputs, skipping");
continue;
}
+
+ if (!mStaticInfo.isVideoStabilizationSupported() && useVideoStab) {
+ Log.i(TAG, "Camera " + mCameraIds[i] +
+ " does not support video stabilization, skipping the stabilization"
+ + " test");
+ continue;
+ }
+
initSupportedVideoSize(mCameraIds[i]);
- basicRecordingTestByCamera(mCamcorderProfileList);
+ basicRecordingTestByCamera(mCamcorderProfileList, useVideoStab);
} finally {
closeDevice();
releaseRecorder();
@@ -128,6 +136,23 @@
/**
* <p>
+ * Test basic video stabilitzation camera recording.
+ * </p>
+ * <p>
+ * This test covers the typical basic use case of camera recording with video
+ * stabilization is enabled, if video stabilization is supported.
+ * MediaRecorder is used to record the audio and video, CamcorderProfile is
+ * used to configure the MediaRecorder. It goes through the pre-defined
+ * CamcorderProfile list, test each profile configuration and validate the
+ * recorded video. Preview is set to the video size.
+ * </p>
+ */
+ public void testBasicVideoStabilizationRecording() throws Exception {
+ doBasicRecording(/*useVideoStab*/true);
+ }
+
+ /**
+ * <p>
* Test basic camera recording.
* </p>
* <p>
@@ -139,7 +164,7 @@
* </p>
*/
public void testBasicRecording() throws Exception {
- doBasicRecording();
+ doBasicRecording(/*useVideoStab*/false);
}
/**
@@ -159,7 +184,7 @@
assertNotNull("Failed to create persistent input surface!", mPersistentSurface);
try {
- doBasicRecording();
+ doBasicRecording(/*useVideoStab*/false);
} finally {
mPersistentSurface.release();
mPersistentSurface = null;
@@ -311,7 +336,7 @@
}
int camcorderProfileList[] = new int[] {minFpsProfileId, maxFpsProfileId};
- basicRecordingTestByCamera(camcorderProfileList);
+ basicRecordingTestByCamera(camcorderProfileList, /*useVideoStab*/false);
} finally {
closeDevice();
releaseRecorder();
@@ -594,11 +619,13 @@
* Test camera recording by using each available CamcorderProfile for a
* given camera. preview size is set to the video size.
*/
- private void basicRecordingTestByCamera(int[] camcorderProfileList) throws Exception {
+ private void basicRecordingTestByCamera(int[] camcorderProfileList, boolean useVideoStab)
+ throws Exception {
Size maxPreviewSize = mOrderedPreviewSizes.get(0);
List<Range<Integer> > fpsRanges = Arrays.asList(
mStaticInfo.getAeAvailableTargetFpsRangesChecked());
int cameraId = Integer.valueOf(mCamera.getId());
+ int maxVideoFrameRate = -1;
for (int profileId : camcorderProfileList) {
if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
allowedUnsupported(cameraId, profileId)) {
@@ -608,6 +635,9 @@
CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId);
Size videoSz = new Size(profile.videoFrameWidth, profile.videoFrameHeight);
Range<Integer> fpsRange = new Range(profile.videoFrameRate, profile.videoFrameRate);
+ if (maxVideoFrameRate < profile.videoFrameRate) {
+ maxVideoFrameRate = profile.videoFrameRate;
+ }
if (mStaticInfo.isHardwareLevelLegacy() &&
(videoSz.getWidth() > maxPreviewSize.getWidth() ||
videoSz.getHeight() > maxPreviewSize.getHeight())) {
@@ -639,7 +669,7 @@
// Start recording
SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
- startRecording(/* useMediaRecorder */true, resultListener);
+ startRecording(/* useMediaRecorder */true, resultListener, useVideoStab);
// Record certain duration.
SystemClock.sleep(RECORDING_DURATION_MS);
@@ -658,6 +688,11 @@
// Validation.
validateRecording(videoSz, durationMs);
}
+ if (maxVideoFrameRate != -1) {
+ // At least one CamcorderProfile is present, check FPS
+ assertTrue("At least one CamcorderProfile must support >= 24 FPS",
+ maxVideoFrameRate >= 24);
+ }
}
/**
@@ -689,7 +724,7 @@
// Start recording
SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
- startRecording(/* useMediaRecorder */true, resultListener);
+ startRecording(/* useMediaRecorder */true, resultListener, /*useVideoStab*/false);
// Record certain duration.
SystemClock.sleep(RECORDING_DURATION_MS);
@@ -911,7 +946,7 @@
CaptureRequest request = videoSnapshotRequestBuilder.build();
// Start recording
- startRecording(/* useMediaRecorder */true, resultListener);
+ startRecording(/* useMediaRecorder */true, resultListener, /*useVideoStab*/false);
long startTime = SystemClock.elapsedRealtime();
// Record certain duration.
@@ -1102,7 +1137,11 @@
}
private void startRecording(boolean useMediaRecorder,
- CameraCaptureSession.CaptureCallback listener) throws Exception {
+ CameraCaptureSession.CaptureCallback listener, boolean useVideoStab) throws Exception {
+ if (!mStaticInfo.isVideoStabilizationSupported() && useVideoStab) {
+ throw new IllegalArgumentException("Video stabilization is not supported");
+ }
+
List<Surface> outputSurfaces = new ArrayList<Surface>(2);
assertTrue("Both preview and recording surfaces should be valid",
mPreviewSurface.isValid() && mRecordingSurface.isValid());
@@ -1120,6 +1159,10 @@
// Make sure camera output frame rate is set to correct value.
Range<Integer> fpsRange = Range.create(mVideoFrameRate, mVideoFrameRate);
recordingRequestBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE, fpsRange);
+ if (useVideoStab) {
+ recordingRequestBuilder.set(CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE,
+ CaptureRequest.CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ }
recordingRequestBuilder.addTarget(mRecordingSurface);
recordingRequestBuilder.addTarget(mPreviewSurface);
mSession.setRepeatingRequest(recordingRequestBuilder.build(), listener, mHandler);
@@ -1133,7 +1176,7 @@
}
private void startRecording(boolean useMediaRecorder) throws Exception {
- startRecording(useMediaRecorder, null);
+ startRecording(useMediaRecorder, /*listener*/null, /*useVideoStab*/false);
}
private void stopCameraStreaming() throws Exception {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
rename to tests/camera/src/android/hardware/camera2/cts/ReprocessCaptureTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
rename to tests/camera/src/android/hardware/camera2/cts/RobustnessTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
rename to tests/camera/src/android/hardware/camera2/cts/StaticMetadataCollectionTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java b/tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/StaticMetadataTest.java
rename to tests/camera/src/android/hardware/camera2/cts/StaticMetadataTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
rename to tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
index 5e931fe..e7978c6 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/StillCaptureTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/StillCaptureTest.java
@@ -983,6 +983,8 @@
CaptureRequest.Builder stillRequest =
mCamera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
boolean canSetAeLock = mStaticInfo.isAeLockSupported();
+ boolean canReadSensorSettings = mStaticInfo.isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS);
if (canSetAeLock) {
stillRequest.set(CaptureRequest.CONTROL_AE_LOCK, true);
@@ -991,19 +993,20 @@
CaptureResult normalResult;
CaptureResult compensatedResult;
- // The following variables should only be read under the MANUAL_SENSOR capability guard:
+ boolean canReadExposureValueRange = mStaticInfo.areKeysAvailable(
+ CameraCharacteristics.SENSOR_INFO_SENSITIVITY_RANGE,
+ CameraCharacteristics.SENSOR_INFO_EXPOSURE_TIME_RANGE);
+ boolean canVerifyExposureValue = canReadSensorSettings && canReadExposureValueRange;
long minExposureValue = -1;
- long maxExposureTimeUs = -1;
long maxExposureValuePreview = -1;
long maxExposureValueStill = -1;
- if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_MANUAL_SENSOR)) {
+ if (canReadExposureValueRange) {
// Minimum exposure settings is mostly static while maximum exposure setting depends on
// frame rate range which in term depends on capture request.
minExposureValue = mStaticInfo.getSensitivityMinimumOrDefault() *
mStaticInfo.getExposureMinimumOrDefault() / 1000;
long maxSensitivity = mStaticInfo.getSensitivityMaximumOrDefault();
- maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000;
+ long maxExposureTimeUs = mStaticInfo.getExposureMaximumOrDefault() / 1000;
maxExposureValuePreview = getMaxExposureValue(previewRequest, maxExposureTimeUs,
maxSensitivity);
maxExposureValueStill = getMaxExposureValue(stillRequest, maxExposureTimeUs,
@@ -1024,8 +1027,7 @@
normalResult = resultListener.getCaptureResult(WAIT_FOR_RESULT_TIMEOUT_MS);
long normalExposureValue = -1;
- if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
+ if (canVerifyExposureValue) {
// get and check if current exposure value is valid
normalExposureValue = getExposureValue(normalResult);
mCollector.expectInRange("Exposure setting out of bound", normalExposureValue,
@@ -1072,8 +1074,7 @@
compensatedResult = resultListener.getCaptureResultForRequest(
request, WAIT_FOR_RESULT_TIMEOUT_MS);
- if (mStaticInfo.isCapabilitySupported(
- CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS)) {
+ if (canVerifyExposureValue) {
// Verify the exposure value compensates as requested
long compensatedExposureValue = getExposureValue(compensatedResult);
mCollector.expectInRange("Exposure setting out of bound", compensatedExposureValue,
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java b/tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
rename to tests/camera/src/android/hardware/camera2/cts/SurfaceViewPreviewTest.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/common.rs b/tests/camera/src/android/hardware/camera2/cts/common.rs
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/common.rs
rename to tests/camera/src/android/hardware/camera2/cts/common.rs
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/crop_yuvf_420_to_yuvx_444.rs b/tests/camera/src/android/hardware/camera2/cts/crop_yuvf_420_to_yuvx_444.rs
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/crop_yuvf_420_to_yuvx_444.rs
rename to tests/camera/src/android/hardware/camera2/cts/crop_yuvf_420_to_yuvx_444.rs
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/AssertHelpers.java b/tests/camera/src/android/hardware/camera2/cts/helpers/AssertHelpers.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/AssertHelpers.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/AssertHelpers.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java b/tests/camera/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/Camera2Focuser.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java b/tests/camera/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/CameraErrorCollector.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraMetadataGetter.java b/tests/camera/src/android/hardware/camera2/cts/helpers/CameraMetadataGetter.java
old mode 100755
new mode 100644
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraMetadataGetter.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/CameraMetadataGetter.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java b/tests/camera/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/CameraSessionUtils.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/InMatcher.java b/tests/camera/src/android/hardware/camera2/cts/helpers/InMatcher.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/InMatcher.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/InMatcher.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/MaybeNull.java b/tests/camera/src/android/hardware/camera2/cts/helpers/MaybeNull.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/MaybeNull.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/MaybeNull.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java b/tests/camera/src/android/hardware/camera2/cts/helpers/Preconditions.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/Preconditions.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/Preconditions.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java b/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
index 4310b3a..cb6b04c 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
+++ b/tests/camera/src/android/hardware/camera2/cts/helpers/StaticMetadata.java
@@ -1401,17 +1401,9 @@
int fpsRangeLength = fpsRanges.length;
int minFps, maxFps;
long maxFrameDuration = getMaxFrameDurationChecked();
- boolean foundConstant30Range = false;
- boolean foundPreviewStreamingRange = false;
for (int i = 0; i < fpsRangeLength; i += 1) {
minFps = fpsRanges[i].getLower();
maxFps = fpsRanges[i].getUpper();
- if (minFps == 30 && maxFps == 30) {
- foundConstant30Range = true;
- }
- if (minFps <= 15 && maxFps >= 30) {
- foundPreviewStreamingRange = true;
- }
checkTrueForKey(key, " min fps must be no larger than max fps!",
minFps > 0 && maxFps >= minFps);
long maxDuration = (long) (1e9 / minFps);
@@ -1419,10 +1411,6 @@
" the frame duration %d for min fps %d must smaller than maxFrameDuration %d",
maxDuration, minFps, maxFrameDuration), maxDuration <= maxFrameDuration);
}
- checkTrueForKey(key, String.format(" (30, 30) must be included"), foundConstant30Range);
- checkTrueForKey(key, String.format(
- " (min, max) where min <= 15 and max >= 30 must be included"),
- foundPreviewStreamingRange);
return fpsRanges;
}
@@ -1638,6 +1626,13 @@
return modes;
}
+ public boolean isVideoStabilizationSupported() {
+ Integer[] videoStabModes =
+ CameraTestUtils.toObject(getAvailableVideoStabilizationModesChecked());
+ return Arrays.asList(videoStabModes).contains(
+ CameraMetadata.CONTROL_VIDEO_STABILIZATION_MODE_ON);
+ }
+
/**
* Get availableOpticalStabilization and do the sanity check.
*
@@ -2207,6 +2202,25 @@
}
/**
+ * Check if optical black regions key is supported.
+ */
+ public boolean isOpticalBlackRegionSupported() {
+ return areKeysAvailable(CameraCharacteristics.SENSOR_OPTICAL_BLACK_REGIONS);
+ }
+
+ /**
+ * Check if the dynamic black level is supported.
+ *
+ * <p>
+ * Note that: This also indicates if the white level is supported, as dynamic black and white
+ * level must be all supported or none of them is supported.
+ * </p>
+ */
+ public boolean isDynamicBlackLevelSupported() {
+ return areKeysAvailable(CaptureResult.SENSOR_DYNAMIC_BLACK_LEVEL);
+ }
+
+ /**
* Get the value in index for a fixed-size array from a given key.
*
* <p>If the camera device is incorrectly reporting values, log a warning and return
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/helpers/UncheckedCloseable.java b/tests/camera/src/android/hardware/camera2/cts/helpers/UncheckedCloseable.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/helpers/UncheckedCloseable.java
rename to tests/camera/src/android/hardware/camera2/cts/helpers/UncheckedCloseable.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/means_yuvx_444_1d_to_single.rs b/tests/camera/src/android/hardware/camera2/cts/means_yuvx_444_1d_to_single.rs
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/means_yuvx_444_1d_to_single.rs
rename to tests/camera/src/android/hardware/camera2/cts/means_yuvx_444_1d_to_single.rs
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/means_yuvx_444_2d_to_1d.rs b/tests/camera/src/android/hardware/camera2/cts/means_yuvx_444_2d_to_1d.rs
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/means_yuvx_444_2d_to_1d.rs
rename to tests/camera/src/android/hardware/camera2/cts/means_yuvx_444_2d_to_1d.rs
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationCache.java b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationCache.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/AllocationCache.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java b/tests/camera/src/android/hardware/camera2/cts/rs/AllocationInfo.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/AllocationInfo.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/AllocationInfo.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/BitmapUtils.java b/tests/camera/src/android/hardware/camera2/cts/rs/BitmapUtils.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/BitmapUtils.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/BitmapUtils.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/BlockingInputAllocation.java b/tests/camera/src/android/hardware/camera2/cts/rs/BlockingInputAllocation.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/BlockingInputAllocation.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/BlockingInputAllocation.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java b/tests/camera/src/android/hardware/camera2/cts/rs/RawConverter.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/RawConverter.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/RawConverter.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java b/tests/camera/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java
index 8e4c8e9..211dd0d 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java
+++ b/tests/camera/src/android/hardware/camera2/cts/rs/RenderScriptSingleton.java
@@ -70,7 +70,7 @@
sCache.close();
sCache = null;
- sRS.destroy();
+ sRS.releaseAllContexts();
sRS = null;
sContext = null;
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/Script.java b/tests/camera/src/android/hardware/camera2/cts/rs/Script.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/Script.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/Script.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java b/tests/camera/src/android/hardware/camera2/cts/rs/ScriptGraph.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptGraph.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/ScriptGraph.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java b/tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvCrop.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java b/tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvMeans1d.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java b/tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvMeans2dTo1d.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvToRgb.java b/tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvToRgb.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/ScriptYuvToRgb.java
rename to tests/camera/src/android/hardware/camera2/cts/rs/ScriptYuvToRgb.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/rs/raw_converter.rs b/tests/camera/src/android/hardware/camera2/cts/rs/raw_converter.rs
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/rs/raw_converter.rs
rename to tests/camera/src/android/hardware/camera2/cts/rs/raw_converter.rs
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
rename to tests/camera/src/android/hardware/camera2/cts/testcases/Camera2AndroidTestCase.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
rename to tests/camera/src/android/hardware/camera2/cts/testcases/Camera2MultiViewTestCase.java
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java b/tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
rename to tests/camera/src/android/hardware/camera2/cts/testcases/Camera2SurfaceViewTestCase.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraCtsActivity.java b/tests/camera/src/android/hardware/cts/CameraCtsActivity.java
similarity index 97%
rename from tests/tests/hardware/src/android/hardware/cts/CameraCtsActivity.java
rename to tests/camera/src/android/hardware/cts/CameraCtsActivity.java
index 1153cac..61e283d 100644
--- a/tests/tests/hardware/src/android/hardware/cts/CameraCtsActivity.java
+++ b/tests/camera/src/android/hardware/cts/CameraCtsActivity.java
@@ -21,7 +21,7 @@
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
-import com.android.cts.hardware.R;
+import android.camera.cts.R;
public class CameraCtsActivity extends Activity {
private SurfaceView mSurfaceView;
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java b/tests/camera/src/android/hardware/cts/CameraGLTest.java
old mode 100755
new mode 100644
similarity index 99%
rename from tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java
rename to tests/camera/src/android/hardware/cts/CameraGLTest.java
index 380e47d..8b0756e
--- a/tests/tests/hardware/src/android/hardware/cts/CameraGLTest.java
+++ b/tests/camera/src/android/hardware/cts/CameraGLTest.java
@@ -171,7 +171,7 @@
if (LOGV) Log.v(TAG, "Shutdown of camera complete.");
}
- /** The camera preview callback. Stops capture after the first callback */
+ /** The camera preview callback. */
private final class PreviewCallback
implements android.hardware.Camera.PreviewCallback {
public void onPreviewFrame(byte [] data, Camera camera) {
@@ -179,7 +179,6 @@
assertNotNull(data);
Size size = camera.getParameters().getPreviewSize();
assertEquals(size.width * size.height * 3 / 2, data.length);
- mCamera.stopPreview();
mPreviewDone.open();
}
}
@@ -350,6 +349,7 @@
mCamera.setPreviewTexture(mSurfaceTexture);
noTimeout = waitForPreviewDone();
assertTrue("Timeout waiting for new preview callback!", noTimeout);
+ mCamera.stopPreview();
terminateMessageLooper();
// Check the order: setPreviewTexture->startPreview.
@@ -359,6 +359,7 @@
mCamera.startPreview();
noTimeout = waitForPreviewDone();
assertTrue("Timeout waiting for new preview callback!", noTimeout);
+ mCamera.stopPreview();
// Check the order: setting preview display to null->startPreview->
// setPreviewTexture.
@@ -368,6 +369,7 @@
mCamera.setPreviewTexture(mSurfaceTexture);
noTimeout = waitForPreviewDone();
assertTrue("Timeout waiting for new preview callback!", noTimeout);
+ mCamera.stopPreview();
terminateMessageLooper();
}
};
@@ -396,6 +398,7 @@
assertTrue("Timeout waiting for new frame from SurfaceTexture!", noTimeout);
noTimeout = waitForPreviewDone();
assertTrue("Timeout waiting for new preview callback!",noTimeout);
+ mCamera.stopPreview();
mGLView.requestRender();
terminateMessageLooper();
@@ -413,6 +416,7 @@
assertTrue("Timeout waiting for new frame from SurfaceTexture!", noTimeout);
noTimeout = waitForPreviewDone();
assertTrue("Timeout waiting for new preview callback!", noTimeout);
+ mCamera.stopPreview();
mGLView.requestRender();
@@ -424,6 +428,7 @@
mCamera.setPreviewTexture(mSurfaceTexture);
noTimeout = waitForPreviewDone();
assertTrue(noTimeout);
+ mCamera.stopPreview();
terminateMessageLooper();
}
};
diff --git a/tests/tests/hardware/src/android/hardware/cts/CameraTest.java b/tests/camera/src/android/hardware/cts/CameraTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/CameraTest.java
rename to tests/camera/src/android/hardware/cts/CameraTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/Camera_ParametersTest.java b/tests/camera/src/android/hardware/cts/Camera_ParametersTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/Camera_ParametersTest.java
rename to tests/camera/src/android/hardware/cts/Camera_ParametersTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/Camera_SizeTest.java b/tests/camera/src/android/hardware/cts/Camera_SizeTest.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/Camera_SizeTest.java
rename to tests/camera/src/android/hardware/cts/Camera_SizeTest.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/GLSurfaceViewCtsActivity.java b/tests/camera/src/android/hardware/cts/GLSurfaceViewCtsActivity.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/GLSurfaceViewCtsActivity.java
rename to tests/camera/src/android/hardware/cts/GLSurfaceViewCtsActivity.java
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/CameraUtils.java b/tests/camera/src/android/hardware/cts/helpers/CameraUtils.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/cts/helpers/CameraUtils.java
rename to tests/camera/src/android/hardware/cts/helpers/CameraUtils.java
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java
similarity index 97%
rename from tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java
rename to tests/camera/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java
index 5c27111..3908334 100644
--- a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera1Activity.java
@@ -18,7 +18,6 @@
import android.app.Activity;
import android.hardware.Camera;
-import android.hardware.multiprocess.ErrorLoggingService;
import android.os.Bundle;
import android.util.Log;
@@ -26,7 +25,7 @@
* Activity implementing basic access of the Camera1 API.
*
* <p />
- * This will log all errors to {@link android.hardware.multiprocess.ErrorLoggingService}.
+ * This will log all errors to {@link android.hardware.multiprocess.camera.cts.ErrorLoggingService}.
*/
public class Camera1Activity extends Activity {
private static final String TAG = "Camera1Activity";
@@ -90,4 +89,4 @@
mErrorServiceConnection = null;
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
similarity index 98%
rename from tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
rename to tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
index 2a78649..418eb7c 100644
--- a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/Camera2Activity.java
@@ -21,7 +21,6 @@
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
-import android.hardware.multiprocess.ErrorLoggingService;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
@@ -30,7 +29,7 @@
* Activity implementing basic access of the Camera2 API.
*
* <p />
- * This will log all errors to {@link android.hardware.multiprocess.ErrorLoggingService}.
+ * This will log all errors to {@link android.hardware.multiprocess.camera.cts.ErrorLoggingService}.
*/
public class Camera2Activity extends Activity {
private static final String TAG = "Camera2Activity";
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
similarity index 99%
rename from tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
rename to tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
index d1ca19a..9f1ae03 100644
--- a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/CameraEvictionTest.java
@@ -25,7 +25,6 @@
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.cts.CameraCtsActivity;
-import android.hardware.multiprocess.ErrorLoggingService;
import android.os.Handler;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/ErrorLoggingService.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/ErrorLoggingService.java
similarity index 99%
rename from tests/tests/hardware/src/android/hardware/multiprocess/ErrorLoggingService.java
rename to tests/camera/src/android/hardware/multiprocess/camera/cts/ErrorLoggingService.java
index 1b713ba..a45e024 100644
--- a/tests/tests/hardware/src/android/hardware/multiprocess/ErrorLoggingService.java
+++ b/tests/camera/src/android/hardware/multiprocess/camera/cts/ErrorLoggingService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.hardware.multiprocess;
+package android.hardware.multiprocess.camera.cts;
import android.app.Service;
import android.content.ComponentName;
diff --git a/tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/TestConstants.java b/tests/camera/src/android/hardware/multiprocess/camera/cts/TestConstants.java
similarity index 100%
rename from tests/tests/hardware/src/android/hardware/multiprocess/camera/cts/TestConstants.java
rename to tests/camera/src/android/hardware/multiprocess/camera/cts/TestConstants.java
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index b2ad4a8..45fa081 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -330,18 +330,31 @@
bug: 23827982
},
{
- description: "tests not yet ready",
- names: [
- "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneFalse_SpeakerphoneOffInCall",
- "android.telecom.cts.OutgoingCallTest#testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault"
- ],
- bug: 24067587
-},
-{
description: "protected broadcast not working",
names: [
"android.permission2.cts.ProtectedBroadcastsTest#testSendProtectedBroadcasts"
],
bug: 23192492
+},
+{
+ description: "restricted network is not working",
+ names: [
+ "android.net.cts.ConnectivityManagerTest#testRestrictedNetworks"
+ ],
+ bug: 25651805
+},
+{
+ description: "Read from invalid parcel not working",
+ names: [
+ "android.view.cts.MotionEventTest#testReadFromParcelWithInvalidSampleSize"
+ ],
+ bug: 25652250
+},
+{
+ description: "unit testing for MediaPreparer lives within mediastress module",
+ names: [
+ "android.mediastress.cts.preconditions.MediaPreparerTest"
+ ],
+ bug: 25850508
}
]
diff --git a/tests/leanbackjank/Android.mk b/tests/leanbackjank/Android.mk
index b3adfb1..45d194f 100644
--- a/tests/leanbackjank/Android.mk
+++ b/tests/leanbackjank/Android.mk
@@ -21,11 +21,22 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
LOCAL_SRC_FILES := $(call all-java-files-under, src) \
- ./app/src/android/cts/jank/leanback/IntentKeys.java
+ ./app/src/android/leanbackjank/app/IntentKeys.java
LOCAL_PACKAGE_NAME := CtsLeanbackJankTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner ub-uiautomator ub-janktesthelper android-support-v17-leanback
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsdeviceutil \
+ ctstestrunner \
+ ub-uiautomator \
+ ub-janktesthelper \
+ android-support-v17-leanback \
+ android-support-v4
+
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/leanbackjank/AndroidManifest.xml b/tests/leanbackjank/AndroidManifest.xml
index 1cd552d..27cdbe6 100644
--- a/tests/leanbackjank/AndroidManifest.xml
+++ b/tests/leanbackjank/AndroidManifest.xml
@@ -17,15 +17,15 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.cts.leanbackjank">
+ package="android.leanbackjank.cts">
<application>
<uses-library android:name="android.test.runner"/>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.cts.leanbackjank"
- android:label="Jank tests">
+ android:targetPackage="android.leanbackjank.cts"
+ android:label="LeanbackJank tests">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
diff --git a/tests/leanbackjank/AndroidTest.xml b/tests/leanbackjank/AndroidTest.xml
index e61c58d..a07c2eb 100644
--- a/tests/leanbackjank/AndroidTest.xml
+++ b/tests/leanbackjank/AndroidTest.xml
@@ -13,7 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="CTS Jank test config">
- <include name="common-config" />
- <option name="cts-apk-installer:test-file-name" value="CtsLeanbackJank.apk" />
+<configuration description="Config for CTS LeanbackJank test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsLeanbackJankTestCases.apk" />
+ <option name="test-file-name" value="CtsLeanbackJankApp.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.leanbackjank.cts" />
+ </test>
</configuration>
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/tests/leanbackjank/OldAndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to tests/leanbackjank/OldAndroidTest.xml
index 49d705a..1ee5722 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/tests/leanbackjank/OldAndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Config for CTS LeanbackJank Test Cases">
+ <include name="common-config" />
+ <option name="cts-apk-installer:test-file-name" value="CtsLeanbackJankApp.apk" />
+</configuration>
diff --git a/tests/leanbackjank/app/Android.mk b/tests/leanbackjank/app/Android.mk
index 5abe1a7..c2bab35 100644
--- a/tests/leanbackjank/app/Android.mk
+++ b/tests/leanbackjank/app/Android.mk
@@ -22,7 +22,10 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_PACKAGE_NAME := CtsLeanbackJank
+LOCAL_PACKAGE_NAME := CtsLeanbackJankApp
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
LOCAL_RESOURCE_DIR := \
$(TOP)/frameworks/support/v17/leanback/res \
diff --git a/tests/leanbackjank/app/AndroidManifest.xml b/tests/leanbackjank/app/AndroidManifest.xml
index 333399e..1e1ff3b 100644
--- a/tests/leanbackjank/app/AndroidManifest.xml
+++ b/tests/leanbackjank/app/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.cts.jank.leanback"
+ package="android.leanbackjank.app"
android:versionCode="1"
android:versionName="1.1" >
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java b/tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java
similarity index 88%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java
index e9c5e6e..b459aa9 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/IntentKeys.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/IntentKeys.java
@@ -1,4 +1,4 @@
-package android.cts.jank.leanback;
+package android.leanbackjank.app;
/**
* Intent key strings of the leanback jank test helper app.
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java b/tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java
similarity index 98%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java
index de6d6af..b464abf 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/Utils.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/Utils.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.jank.leanback;
+package android.leanbackjank.app;
import android.app.Activity;
import android.content.Context;
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java b/tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java
similarity index 96%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java
index fa317ed..6ea19c1 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/data/VideoProvider.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/data/VideoProvider.java
@@ -14,9 +14,9 @@
* limitations under the License.
*/
-package android.cts.jank.leanback.data;
+package android.leanbackjank.app.data;
-import android.cts.jank.leanback.model.Movie;
+import android.leanbackjank.app.model.Movie;
import java.util.ArrayList;
import java.util.HashMap;
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java b/tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java
similarity index 98%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java
index 874bb00..1b68aee 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/model/Movie.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/model/Movie.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.jank.leanback.model;
+package android.leanbackjank.app.model;
import android.os.Parcel;
import android.os.Parcelable;
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java
similarity index 96%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java
index 9f425ca..f237438 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/CardPresenter.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/CardPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.jank.leanback.presenter;
+package android.leanbackjank.app.presenter;
import android.graphics.drawable.Drawable;
import android.support.v17.leanback.widget.ImageCardView;
@@ -22,8 +22,8 @@
import android.view.ViewGroup;
import com.bumptech.glide.Glide;
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.model.Movie;
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.model.Movie;
/**
* A CardPresenter is used to generate Views and bind Objects to them on demand.
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java
similarity index 93%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java
index 4084383..1ab7e8d 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/GridItemPresenter.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/GridItemPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.jank.leanback.presenter;
+package android.leanbackjank.app.presenter;
import android.graphics.Color;
import android.support.v17.leanback.widget.Presenter;
@@ -22,8 +22,8 @@
import android.view.ViewGroup;
import android.widget.TextView;
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.ui.MainFragment;
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.ui.MainFragment;
public class GridItemPresenter extends Presenter {
private static int GRID_ITEM_WIDTH = 200;
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java
similarity index 96%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java
index 42e4c0c..32dae35 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/presenter/IconHeaderItemPresenter.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/presenter/IconHeaderItemPresenter.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.jank.leanback.presenter;
+package android.leanbackjank.app.presenter;
import android.content.Context;
import android.graphics.drawable.Drawable;
@@ -28,7 +28,7 @@
import android.widget.ImageView;
import android.widget.TextView;
-import android.cts.jank.leanback.R;
+import android.leanbackjank.app.R;
public class IconHeaderItemPresenter extends RowHeaderPresenter {
private float mUnselectedAlpha;
@@ -70,4 +70,4 @@
holder.view.setAlpha(mUnselectedAlpha + holder.getSelectLevel() *
(1.0f - mUnselectedAlpha));
}
-}
\ No newline at end of file
+}
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java
similarity index 92%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java
index fb27fa1..356c2ac 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainActivity.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainActivity.java
@@ -12,11 +12,11 @@
* the License.
*/
-package android.cts.jank.leanback.ui;
+package android.leanbackjank.app.ui;
import android.app.Activity;
import android.os.Bundle;
-import android.cts.jank.leanback.R;
+import android.leanbackjank.app.R;
/**
* MainActivity class that loads MainFragment
diff --git a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java
similarity index 93%
rename from tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java
rename to tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java
index e645f6b..2119b2f 100644
--- a/tests/leanbackjank/app/src/android/cts/jank/leanback/ui/MainFragment.java
+++ b/tests/leanbackjank/app/src/android/leanbackjank/app/ui/MainFragment.java
@@ -12,17 +12,17 @@
* the License.
*/
-package android.cts.jank.leanback.ui;
+package android.leanbackjank.app.ui;
import android.content.Intent;
import android.content.res.Resources.Theme;
-import android.cts.jank.leanback.IntentKeys;
-import android.cts.jank.leanback.R;
-import android.cts.jank.leanback.data.VideoProvider;
-import android.cts.jank.leanback.model.Movie;
-import android.cts.jank.leanback.presenter.CardPresenter;
-import android.cts.jank.leanback.presenter.GridItemPresenter;
-import android.cts.jank.leanback.presenter.IconHeaderItemPresenter;
+import android.leanbackjank.app.IntentKeys;
+import android.leanbackjank.app.R;
+import android.leanbackjank.app.data.VideoProvider;
+import android.leanbackjank.app.model.Movie;
+import android.leanbackjank.app.presenter.CardPresenter;
+import android.leanbackjank.app.presenter.GridItemPresenter;
+import android.leanbackjank.app.presenter.IconHeaderItemPresenter;
import android.os.Bundle;
import android.os.Handler;
import android.support.v17.leanback.app.BackgroundManager;
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java b/tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java
similarity index 93%
rename from tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
rename to tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java
index 241535e..c52fe09 100644
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsDeviceLeanback.java
+++ b/tests/leanbackjank/src/android/leanbackjank/cts/CtsDeviceLeanback.java
@@ -12,12 +12,12 @@
* the License.
*/
-package android.cts.leanbackjank;
+package android.leanbackjank.cts;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.PackageManager;
-import android.cts.jank.leanback.IntentKeys;
+import android.leanbackjank.app.IntentKeys;
import android.os.SystemClock;
import android.support.test.jank.GfxMonitor;
import android.support.test.jank.JankTest;
@@ -37,8 +37,8 @@
private static final int SAMPLING_DURATION_SECONDS = 3;
private static final int SAMPLING_DURATION_MILLIS =
SAMPLING_DURATION_SECONDS * MILLIS_PER_SECOND;
- private final static String APP_PACKAGE = "android.cts.jank.leanback";
- private final static String JAVA_PACKAGE = "android.cts.jank.leanback.ui";
+ private final static String APP_PACKAGE = "android.leanbackjank.app";
+ private final static String JAVA_PACKAGE = "android.leanbackjank.app.ui";
private final static String CLASS = JAVA_PACKAGE + ".MainActivity";
private boolean shouldSkip() {
diff --git a/tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java b/tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java
similarity index 98%
rename from tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java
rename to tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java
index 4de0702..77a1d1c 100644
--- a/tests/leanbackjank/src/android/cts/leanbackjank/CtsJankTestBase.java
+++ b/tests/leanbackjank/src/android/leanbackjank/cts/CtsJankTestBase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.cts.leanbackjank;
+package android.leanbackjank.cts;
import android.cts.util.DeviceReportLog;
import android.os.Bundle;
diff --git a/tests/signature/Android.mk b/tests/signature/Android.mk
index 53ba50d..d99af18 100644
--- a/tests/signature/Android.mk
+++ b/tests/signature/Android.mk
@@ -22,68 +22,34 @@
LOCAL_PACKAGE_NAME := CtsSignatureTestCases
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+cts_api_xml_rel := ../../../$(call intermediates-dir-for,APPS,CtsSignatureTestCases)/current.api
+cts_api_xml := $(LOCAL_PATH)/$(cts_api_xml_rel)
+$(cts_api_xml) : frameworks/base/api/current.txt | $(APICHECK)
+ @echo "Convert API file $@"
+ @mkdir -p $(dir $@)
+ $(hide) $(APICHECK_COMMAND) -convert2xml $< $@
+
+# Copy the current api file to CTS
+LOCAL_COMPATIBILITY_SUPPORT_FILES += $(cts_api_xml_rel):current.api
+
+# For CTS v1
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+cts_api_xml_v1 := $(CTS_TESTCASES_OUT)/current.api
+$(cts_api_xml_v1): $(cts_api_xml) | $(ACP)
+ $(call copy-file-to-new-target)
+
+$(CTS_TESTCASES_OUT)/$(LOCAL_PACKAGE_NAME).xml: $(cts_api_xml_v1)
+
LOCAL_SDK_VERSION := current
LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner
-# To be passed in on command line
-CTS_API_VERSION ?= current
-ifeq (current,$(CTS_API_VERSION))
-android_api_description := frameworks/base/api/$(CTS_API_VERSION).txt
-else
-android_api_description := $(SRC_API_DIR)/$(CTS_API_VERSION).txt
-endif
-
-# Can't call local-intermediates-dir directly here because we have to
-# include BUILD_CTS_PACKAGE first. Can't include BUILD_CTS_PACKAGE first
-# because we have to override LOCAL_RESOURCE_DIR first. Hence this
-# hack.
-intermediates.COMMON := $(call intermediates-dir-for,APPS,$(LOCAL_PACKAGE_NAME),,COMMON)
-signature_res_dir := $(intermediates.COMMON)/genres
-LOCAL_RESOURCE_DIR := $(signature_res_dir) $(LOCAL_PATH)/res
-
include $(BUILD_CTS_PACKAGE)
-generated_res_stamp := $(intermediates.COMMON)/genres.stamp
-api_ver_file := $(intermediates.COMMON)/api_ver_is_$(CTS_API_VERSION)
-
-# The api_ver_file keeps track of which api version was last built.
-# By only ever having one of these magic files in existence and making
-# sure the generated resources rule depend on it, we can ensure that
-# the proper version of the api resource gets generated.
-$(api_ver_file):
- $(hide) rm -f $(dir $@)/api_ver_is_* \
- && mkdir -p $(dir $@) && touch $@
-
-android_api_xml_description := $(intermediates.COMMON)/api.xml
-$(android_api_xml_description): $(android_api_description) | $(APICHECK)
- @ echo "Convert api file to xml: $@"
- @ mkdir -p $(dir $@)
- $(hide) $(APICHECK_COMMAND) -convert2xml $< $@
-
-# Split up config/api/1.xml by "package" and save the files as the
-# resource files of SignatureTest.
-$(generated_res_stamp): PRIVATE_PATH := $(LOCAL_PATH)
-$(generated_res_stamp): PRIVATE_MODULE := $(LOCAL_MODULE)
-$(generated_res_stamp): PRIVATE_RES_DIR := $(signature_res_dir)
-$(generated_res_stamp): PRIVATE_API_XML_DESC := $(android_api_xml_description)
-$(generated_res_stamp): $(api_ver_file)
-$(generated_res_stamp): $(android_api_xml_description)
- @ echo "Copy generated resources: $(PRIVATE_MODULE)"
- $(hide) python cts/tools/utils/android_api_description_splitter.py \
- $(PRIVATE_API_XML_DESC) $(PRIVATE_RES_DIR) package
- $(hide) touch $@
-
-$(R_file_stamp): $(generated_res_stamp)
-
-# clean up temp vars
-android_api_xml_description :=
-api_ver_file :=
-generated_res_stamp :=
-signature_res_dir :=
-android_api_description :=
-CTS_API_VERSION :=
-
# signature-hostside java library (for testing)
# ============================================================
@@ -98,4 +64,6 @@
LOCAL_MODULE_TAGS := optional
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/signature/AndroidManifest.xml b/tests/signature/AndroidManifest.xml
index e42302e..52090ce 100644
--- a/tests/signature/AndroidManifest.xml
+++ b/tests/signature/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="android.signature">
+ package="android.signature.cts">
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<application>
@@ -24,7 +24,7 @@
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="android.signature"
+ android:targetPackage="android.signature.cts"
android:label="API Signature Test"/>
</manifest>
\ No newline at end of file
diff --git a/tests/signature/AndroidTest.xml b/tests/signature/AndroidTest.xml
new file mode 100644
index 0000000..76b7b83
--- /dev/null
+++ b/tests/signature/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Signature test cases">
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsSignatureTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.signature.cts" />
+ </test>
+</configuration>
diff --git a/tests/signature/OldAndroidTest.xml b/tests/signature/OldAndroidTest.xml
new file mode 100644
index 0000000..b4338da
--- /dev/null
+++ b/tests/signature/OldAndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Signature test cases">
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="mkdir -p /data/local/tmp/signature-test" />
+ <option name="teardown-command" value="rm -rf /data/local/tmp/signature-test" />
+ </target_preparer>
+ <target_preparer class="com.android.cts.tradefed.targetprep.CtsFilePusher">
+ <option name="push" value="current.api->/data/local/tmp/signature-test/current.api" />
+ </target_preparer>
+</configuration>
diff --git a/tests/signature/src/android/signature/cts/SignatureTest.java b/tests/signature/src/android/signature/cts/SignatureTest.java
index 85b77f8..139fb30 100644
--- a/tests/signature/src/android/signature/cts/SignatureTest.java
+++ b/tests/signature/src/android/signature/cts/SignatureTest.java
@@ -17,7 +17,6 @@
package android.signature.cts;
import android.content.res.Resources;
-import android.signature.R;
import android.signature.cts.JDiffClassDescription.JDiffConstructor;
import android.signature.cts.JDiffClassDescription.JDiffField;
import android.signature.cts.JDiffClassDescription.JDiffMethod;
@@ -26,13 +25,17 @@
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
+import java.io.File;
+import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
+import java.util.Scanner;
/**
* Performs the signature check via a JUnit test.
@@ -40,6 +43,7 @@
public class SignatureTest extends AndroidTestCase {
private static final String TAG = SignatureTest.class.getSimpleName();
+ private static final String CURRENT_API_FILE = "/data/local/tmp/signature-test/current.api";
private static final String TAG_ROOT = "api";
private static final String TAG_PACKAGE = "package";
@@ -104,25 +108,21 @@
* Will check the entire API, and then report the complete list of failures
*/
public void testSignature() {
- Resources r = getContext().getResources();
- Class rClass = R.xml.class;
- logd(String.format("Class: %s", rClass.toString()));
- Field[] fs = rClass.getFields();
- for (Field f : fs) {
- logd(String.format("Field: %s", f.toString()));
- try {
- start(r.getXml(f.getInt(rClass)));
- } catch (Exception e) {
- mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
- e.getMessage());
- }
+ try {
+ XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
+ XmlPullParser parser = factory.newPullParser();
+ parser.setInput(new FileInputStream(new File(CURRENT_API_FILE)), null);
+ start(parser);
+ } catch (Exception e) {
+ mResultObserver.notifyFailure(FailureType.CAUGHT_EXCEPTION, e.getMessage(),
+ e.getMessage());
}
if (mResultObserver.mDidFail) {
fail(mResultObserver.mErrorString.toString());
}
}
- private void beginDocument(XmlPullParser parser, String firstElementName)
+ private void beginDocument(XmlPullParser parser, String firstElementName)
throws XmlPullParserException, IOException {
int type;
while ((type=parser.next()) != XmlPullParser.START_TAG
diff --git a/tests/signature-tests/Android.mk b/tests/signature/tests/Android.mk
similarity index 100%
rename from tests/signature-tests/Android.mk
rename to tests/signature/tests/Android.mk
diff --git a/tests/signature-tests/run_unit_tests.sh b/tests/signature/tests/run_unit_tests.sh
similarity index 100%
rename from tests/signature-tests/run_unit_tests.sh
rename to tests/signature/tests/run_unit_tests.sh
diff --git a/tests/signature-tests/src/android/signature/cts/tests/AllTests.java b/tests/signature/tests/src/android/signature/cts/tests/AllTests.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/AllTests.java
rename to tests/signature/tests/src/android/signature/cts/tests/AllTests.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
rename to tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/AbstractClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/AbstractClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/AbstractClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/FinalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/FinalClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/FinalClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/FinalClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalClass.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalClass.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalException.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalException.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalException.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalException.java
diff --git a/tests/signature-tests/src/android/signature/cts/tests/data/NormalInterface.java b/tests/signature/tests/src/android/signature/cts/tests/data/NormalInterface.java
similarity index 100%
rename from tests/signature-tests/src/android/signature/cts/tests/data/NormalInterface.java
rename to tests/signature/tests/src/android/signature/cts/tests/data/NormalInterface.java
diff --git a/tests/tests/accounts/Android.mk b/tests/tests/accounts/Android.mk
index 6ed35c6..4e56984 100644
--- a/tests/tests/accounts/Android.mk
+++ b/tests/tests/accounts/Android.mk
@@ -29,5 +29,10 @@
LOCAL_SDK_VERSION := current
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/accounts/AndroidManifest.xml b/tests/tests/accounts/AndroidManifest.xml
index d882690..0d4a534 100644
--- a/tests/tests/accounts/AndroidManifest.xml
+++ b/tests/tests/accounts/AndroidManifest.xml
@@ -36,6 +36,8 @@
<activity android:name="android.accounts.cts.AccountRemovalDummyActivity" >
</activity>
+ <activity android:name="android.accounts.cts.AccountAuthenticatorDummyActivity" />
+
<service android:name="MockAccountService" android:exported="true"
android:process="android.accounts.cts">
<intent-filter>
diff --git a/tests/tests/accounts/AndroidTest.xml b/tests/tests/accounts/AndroidTest.xml
index 3e29c9c..25600ef 100644
--- a/tests/tests/accounts/AndroidTest.xml
+++ b/tests/tests/accounts/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,7 +13,13 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Test module config for Account apis">
- <include name="common-config" />
- <option name="cts-apk-installer:test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
-</configuration>
+<configuration description="Config for CTS Accounts test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
+ <option name="test-file-name" value="CtsAccountManagerTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.accounts.cts" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
index c32f89f..3708d83 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/AndroidManifest.xml
@@ -41,15 +41,15 @@
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/standard_authenticator" />
</service>
-<!--
- <service android:name=".CustomAccountAuthService" android:exported="false">
+
+ <service android:name=".CustomAccountAuthService"
+ android:exported="false">
<intent-filter>
<action android:name="android.accounts.AccountAuthenticator" />
</intent-filter>
<meta-data android:name="android.accounts.AccountAuthenticator"
android:resource="@xml/custom_authenticator" />
</service>
- -->
</application>
</manifest>
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
index 3485f76..35b557a 100644
--- a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/res/xml/custom_authenticator.xml
@@ -21,7 +21,7 @@
<!-- for the Account Manager. -->
<account-authenticator xmlns:android="http://schemas.android.com/apk/res/android"
- android:accountType="android.accounts.test.custom"
+ android:accountType="android.accounts.test.custom.unaffiliated"
android:icon="@drawable/ic_cts_selected_custom_account"
android:smallIcon="@drawable/ic_cts_minitab_selected_custom_account"
android:customTokens="true"
diff --git a/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java
new file mode 100644
index 0000000..0d32e2f
--- /dev/null
+++ b/tests/tests/accounts/CtsUnaffiliatedAccountAuthenticators/src/android/accounts/cts/unaffiliated/CustomAccountAuthService.java
@@ -0,0 +1,21 @@
+package android.accounts.cts.unaffiliated;
+
+import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.CustomTestAccountAuthenticator;
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * a basic Mock Service for wrapping the CustomAccountAuthenticator.
+ */
+public class CustomAccountAuthService extends Service {
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ CustomTestAccountAuthenticator auth = new CustomTestAccountAuthenticator(this,
+ Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+ return auth.getIBinder();
+ }
+}
+
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/tests/tests/accounts/OldAndroidTest.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to tests/tests/accounts/OldAndroidTest.xml
index 49d705a..3e29c9c 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/tests/tests/accounts/OldAndroidTest.xml
@@ -1,4 +1,4 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +12,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Test module config for Account apis">
+ <include name="common-config" />
+ <option name="cts-apk-installer:test-file-name" value="CtsUnaffiliatedAccountAuthenticators.apk" />
+</configuration>
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java b/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java
new file mode 100644
index 0000000..48726a5
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/CustomTestAccountAuthenticator.java
@@ -0,0 +1,174 @@
+package android.accounts.cts.common;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * Subclass of {@link TestAccountAuthenticator} with startAddAccountSession(...)
+ * and startUpdateCredentialsSession(...) overridden but not finishSession(...)..
+ */
+public class CustomTestAccountAuthenticator extends TestAccountAuthenticator {
+
+ private final AtomicInteger mTokenCounter = new AtomicInteger(0);
+ private final String mAccountType;
+ private final Context mContext;
+
+ /**
+ * @param context
+ * @param accountType
+ */
+ public CustomTestAccountAuthenticator(Context context, String accountType) {
+ super(context, accountType);
+ mAccountType = accountType;
+ mContext = context;
+ }
+
+ /**
+ * Starts add account flow of the specified accountType to authenticate user.
+ */
+ @Override
+ public Bundle startAddAccountSession(
+ AccountAuthenticatorResponse response,
+ String accountType,
+ String authTokenType,
+ String[] requiredFeatures,
+ Bundle options) throws NetworkErrorException {
+
+ if (!mAccountType.equals(accountType)) {
+ throw new IllegalArgumentException("Request to the wrong authenticator!");
+ }
+
+ String accountName = null;
+ boolean isCallbackRequired = false;
+ Bundle sessionBundle = null;
+ if (options != null) {
+ accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+ isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+ sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+ }
+
+ Bundle result = new Bundle();
+ String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName;
+ String password = Fixtures.PREFIX_PASSWORD + accountName;
+ if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, statusToken);
+ result.putString(AccountManager.KEY_PASSWORD, password);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ statusToken);
+ eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+ sessionBundle);
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, TestAuthenticatorActivity.class);
+ intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+ String errorMsg = "Default Error Message";
+ if (options != null) {
+ errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+ errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+ }
+ result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+ }
+
+ try {
+ return (isCallbackRequired) ? null : result;
+ } finally {
+ if (isCallbackRequired) {
+ response.onResult(result);
+ }
+ }
+ }
+
+ /**
+ * Prompts user to re-authenticate to a specific account but defers updating local credentials.
+ */
+ @Override
+ public Bundle startUpdateCredentialsSession(
+ AccountAuthenticatorResponse response,
+ Account account,
+ String authTokenType,
+ Bundle options) throws NetworkErrorException {
+
+ if (!mAccountType.equals(account.type)) {
+ throw new IllegalArgumentException("Request to the wrong authenticator!");
+ }
+
+ String accountName = null;
+ boolean isCallbackRequired = false;
+ Bundle sessionBundle = null;
+ if (options != null) {
+ accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+ isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+ sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+ }
+
+ Bundle result = new Bundle();
+ String statusToken = Fixtures.PREFIX_STATUS_TOKEN + accountName;
+ String password = Fixtures.PREFIX_PASSWORD + accountName;
+ if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN, statusToken);
+ result.putString(AccountManager.KEY_PASSWORD, password);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ statusToken);
+ eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD, password);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+ sessionBundle);
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, TestAuthenticatorActivity.class);
+ intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+ String errorMsg = "Default Error Message";
+ if (options != null) {
+ errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+ errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+ }
+ result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+ }
+
+ try {
+ return (isCallbackRequired) ? null : result;
+ } finally {
+ if (isCallbackRequired) {
+ response.onResult(result);
+ }
+ }
+ }
+
+}
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
index f8636a0..b969caa 100644
--- a/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/Fixtures.java
@@ -31,9 +31,12 @@
public static final String TYPE_STANDARD_UNAFFILIATED =
"android.accounts.test.standard.unaffiliated";
+ public static final String TYPE_CUSTOM_UNAFFILIATED =
+ "android.accounts.test.custom.unaffiliated";
public static final String PREFIX_TOKEN = "token:";
public static final String PREFIX_PASSWORD = "password:";
+ public static final String PREFIX_STATUS_TOKEN = "status_token:";
public static final String SUFFIX_NAME_FIXTURE = "fixture.com";
public static final String SUFFIX_NAME_TEST = "test.com";
@@ -52,6 +55,10 @@
PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
TYPE_STANDARD_UNAFFILIATED);
+ public static final Account ACCOUNT_CUSTOM_UNAFFILIATED_FIXTURE_SUCCESS = new Account(
+ PREFIX_NAME_SUCCESS + "@" + SUFFIX_NAME_FIXTURE,
+ TYPE_CUSTOM_UNAFFILIATED);
+
public static List<String> getFixtureAccountNames() {
List<String> accountNames = new ArrayList<>(accountNamePrefixes.length);
for (String prefix : accountNamePrefixes) {
@@ -70,5 +77,7 @@
public static final String KEY_RESULT = "test:result";
public static final String KEY_TOKEN_EXPIRY = "test:token_duration";
+ public static final String KEY_ACCOUNT_SESSION_BUNDLE = "test:account_session_bundle";
+
private Fixtures() {}
}
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
new file mode 100644
index 0000000..4819ebb
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.aidl
@@ -0,0 +1,3 @@
+package android.accounts.cts.common.tx;
+
+parcelable StartAddAccountSessionTx;
diff --git a/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
new file mode 100644
index 0000000..12a11ff
--- /dev/null
+++ b/tests/tests/accounts/common/src/android/accounts/cts/common/tx/StartAddAccountSessionTx.java
@@ -0,0 +1,65 @@
+package android.accounts.cts.common.tx;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class StartAddAccountSessionTx implements Parcelable {
+
+ public static final Parcelable.Creator<StartAddAccountSessionTx> CREATOR = new Parcelable.Creator<StartAddAccountSessionTx>() {
+
+ @Override
+ public StartAddAccountSessionTx createFromParcel(Parcel in) {
+ return new StartAddAccountSessionTx(in);
+ }
+
+ @Override
+ public StartAddAccountSessionTx[] newArray(int size) {
+ return new StartAddAccountSessionTx[size];
+ }
+ };
+
+ public final String accountType;
+ public final String authTokenType;
+ public final List<String> requiredFeatures = new ArrayList<>();
+ public final Bundle options;
+ public final Bundle result;
+
+ private StartAddAccountSessionTx(Parcel in) {
+ accountType = in.readString();
+ authTokenType = in.readString();
+ in.readStringList(requiredFeatures);
+ options = in.readBundle();
+ result = in.readBundle();
+ }
+
+ public StartAddAccountSessionTx(String accountType, String authTokenType, String[] requiredFeatures,
+ Bundle options, Bundle result) {
+ this.accountType = accountType;
+ this.authTokenType = authTokenType;
+ if (requiredFeatures != null) {
+ for (String feature : requiredFeatures) {
+ this.requiredFeatures.add(feature);
+ }
+ }
+ this.options = options;
+ this.result = result;
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(accountType);
+ out.writeString(authTokenType);
+ out.writeStringList(requiredFeatures);
+ out.writeBundle(options);
+ out.writeBundle(result);
+ }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
new file mode 100644
index 0000000..76276b2
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountAuthenticatorDummyActivity.java
@@ -0,0 +1,26 @@
+package android.accounts.cts;
+
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.cts.common.Fixtures;
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+
+/**
+ * TODO: Insert description here. (generated by sandrakwan)
+ */
+public class AccountAuthenticatorDummyActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ Intent intent = getIntent();
+ AccountAuthenticatorResponse response = intent.getParcelableExtra(Fixtures.KEY_CALLBACK);
+ Intent result = intent.getParcelableExtra(Fixtures.KEY_RESULT);
+ if (response != null) {
+ response.onResult(result.getExtras());
+ }
+ setResult(RESULT_OK, result);
+ finish();
+ }
+}
\ No newline at end of file
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
index 4350191..7d7906d 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerTest.java
@@ -24,8 +24,10 @@
import android.accounts.AuthenticatorException;
import android.accounts.OnAccountsUpdateListener;
import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.Fixtures;
import android.app.Activity;
import android.content.Context;
+import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
@@ -60,6 +62,8 @@
public static final String ACCOUNT_PASSWORD = "android.accounts.cts.account.password";
+ public static final String ACCOUNT_STATUS_TOKEN = "android.accounts.cts.account.status.token";
+
public static final String AUTH_TOKEN_TYPE = "mockAuthTokenType";
public static final String AUTH_EXPIRING_TOKEN_TYPE = "mockAuthExpiringTokenType";
public static final String AUTH_TOKEN_LABEL = "mockAuthTokenLabel";
@@ -94,6 +98,29 @@
public static final Account CUSTOM_TOKEN_ACCOUNT =
new Account(ACCOUNT_NAME,ACCOUNT_TYPE_CUSTOM);
+ public static final String SESSION_DATA_NAME_1 = "session.data.name.1";
+ public static final String SESSION_DATA_NAME_2 = "session.data.name.2";
+ public static final String SESSION_DATA_NAME_3 = "session.data.name.3";
+ public static final String SESSION_DATA_VALUE_1 = "session.data.value.1";
+ public static final int SESSION_DATA_VALUE_2 = 364;
+
+ public static Bundle getSessionBundle(String accountName) {
+ Bundle bundle = new Bundle();
+ bundle.putString(SESSION_DATA_NAME_1, SESSION_DATA_VALUE_1);
+ bundle.putInt(SESSION_DATA_NAME_2, SESSION_DATA_VALUE_2);
+ // Test null value in Bundle.
+ bundle.putParcelable(SESSION_DATA_NAME_3, null);
+ bundle.putString(AccountManager.KEY_ACCOUNT_TYPE, ACCOUNT_TYPE);
+ bundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ bundle.putAll(OPTIONS_BUNDLE);
+ return bundle;
+ }
+
+ public static final String ERROR_MESSAGE = "android.accounts.cts.account.error.message";
+
+ public static final String KEY_CIPHER = "cipher";
+ public static final String KEY_MAC = "mac";
+
private static MockAccountAuthenticator mockAuthenticator;
private static final int LATCH_TIMEOUT_MS = 500;
private static AccountManager am;
@@ -1967,4 +1994,2052 @@
}
}
+ /**
+ * Tests a basic startAddAccountSession() which returns a bundle containing
+ * encrypted session bundle, account password and status token.
+ */
+ public void testStartAddAccountSession()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+ assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startAddAccountSession() with null session bundle. Only account
+ * password and status token should be included in the result as session
+ * bundle is not inspected.
+ */
+ public void testStartAddAccountSessionWithNullSessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+ assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ assertNull(resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertEquals(ACCOUNT_STATUS_TOKEN,
+ resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ /**
+ * Tests startAddAccountSession() with empty session bundle. An encrypted
+ * session bundle, account password and status token should be included in
+ * the result as session bundle is not inspected.
+ */
+ public void testStartAddAccountSessionWithEmptySessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, new Bundle());
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+ assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startAddAccountSession with authenticator activity started. When
+ * Activity is provided, AccountManager would start the resolution Intent
+ * and return the final result which contains an encrypted session bundle,
+ * account password and status token.
+ */
+ public void testStartAddAccountSessionIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateStartAddAccountSessionOptions(accountName, options);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startAddAccountSession with KEY_INTENT returned but not started
+ * automatically. When no Activity is provided and authenticator requires
+ * additional data from user, KEY_INTENT will be returned by AccountManager.
+ */
+ public void testStartAddAccountSessionWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateStartAddAccountSessionOptions(accountName, options);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ // Assert that KEY_INTENT is returned.
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+ // Assert that no other data is returned.
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ }
+
+ /**
+ * Tests startAddAccountSession error case. AuthenticatorException is
+ * expected when authenticator return
+ * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+ */
+ public void testStartAddAccountSessionError() throws IOException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+ options.putAll(OPTIONS_BUNDLE);
+
+ try {
+ startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("startAddAccountSession should throw AuthenticatorException in error case.");
+ } catch (AuthenticatorException e) {
+ }
+ }
+
+ /**
+ * Tests startAddAccountSession() with callback and handler. An encrypted
+ * session bundle, account password and status token should be included in
+ * the result. Callback should be triggered with the result regardless of a
+ * handler is provider or not.
+ */
+ public void testStartAddAccountSessionWithCallbackAndHandler()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartAddAccountSessionWithCallbackAndHandler(null /* handler */);
+ testStartAddAccountSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startAddAccountSession() with callback and handler and activity
+ * started. When Activity is provided, AccountManager would start the
+ * resolution Intent and return the final result which contains an encrypted
+ * session bundle, account password and status token. Callback should be
+ * triggered with the result regardless of a handler is provider or not.
+ */
+ public void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+ testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startAddAccountSession() with callback and handler with KEY_INTENT
+ * returned. When no Activity is provided and authenticator requires
+ * additional data from user, KEY_INTENT will be returned by AccountManager
+ * in callback regardless of a handler is provider or not.
+ */
+ public void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+ testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startAddAccountSession() error case with callback and handler.
+ * AuthenticatorException is expected when authenticator return
+ * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+ */
+ public void testStartAddAccountSessionErrorWithCallbackAndHandler()
+ throws IOException, OperationCanceledException {
+ testStartAddAccountSessionErrorWithCallbackAndHandler(null /* handler */);
+ testStartAddAccountSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+ }
+
+ private void testStartAddAccountSessionWithCallbackAndHandler(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateStartAddAccountSessionOptions(accountName, options);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartAddAccountSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateStartAddAccountSessionOptions(accountName, options);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartAddAccountSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ validateAccountAndAuthTokenType();
+ validateFeatures();
+
+ validateStartAddAccountSessionOptions(accountName, options);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ // Assert KEY_INTENT is returned.
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+ // Assert that no other data is returned.
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+ latch.countDown();
+ }
+ };
+
+ startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartAddAccountSessionErrorWithCallbackAndHandler(Handler handler)
+ throws IOException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ try {
+ bundleFuture.getResult();
+ fail("should have thrown an AuthenticatorException");
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ latch.countDown();
+ }
+ }
+ };
+
+ try {
+ startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ callback,
+ handler);
+ // AuthenticatorException should be thrown when authenticator
+ // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+ fail("should have thrown an AuthenticatorException");
+ } catch (AuthenticatorException e1) {
+ }
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private Bundle startAddAccountSession(AccountManager am, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options, Activity activity,
+ AccountManagerCallback<Bundle> callback, Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ AccountManagerFuture<Bundle> futureBundle = am.startAddAccountSession(
+ accountType,
+ authTokenType,
+ requiredFeatures,
+ options,
+ activity,
+ callback,
+ handler);
+
+ Bundle resultBundle = futureBundle.getResult();
+ assertTrue(futureBundle.isDone());
+ assertNotNull(resultBundle);
+
+ return resultBundle;
+ }
+
+ private void validateStartAddAccountSessionOptions(String accountName, Bundle options) {
+ validateOptions(options, mockAuthenticator.mOptionsStartAddAccountSession);
+ assertNotNull(mockAuthenticator.mOptionsStartAddAccountSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartAddAccountSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateSystemOptions(mockAuthenticator.mOptionsStartAddAccountSession);
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+ validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ validateOptions(null, mockAuthenticator.mOptionsFinishSession);
+ }
+
+ private void validateSessionBundleAndPasswordAndStatusTokenResult(Bundle resultBundle) {
+ Bundle sessionBundle = resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(sessionBundle);
+ // Assert that session bundle is encrypted and hence data not visible.
+ assertNull(sessionBundle.getString(SESSION_DATA_NAME_1));
+ assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertEquals(ACCOUNT_STATUS_TOKEN,
+ resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ /**
+ * Test a basic startUpdateCredentialsSession() which returns a bundle containing
+ * encrypted session bundle, account password and status token.
+ */
+ public void testStartUpdateCredentialsSession()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ null /* authTokenType */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertNull(mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() with null session bundle. Only account
+ * password and status token should be included in the result as session
+ * bundle is not inspected.
+ */
+ public void testStartUpdateCredentialsSessionWithNullSessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ assertNull(resultBundle.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertEquals(ACCOUNT_PASSWORD, resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertEquals(ACCOUNT_STATUS_TOKEN,
+ resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() with empty session bundle. An encrypted
+ * session bundle, account password and status token should be included in
+ * the result as session bundle is not inspected.
+ */
+ public void testStartUpdateCredentialsSessionWithEmptySessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, new Bundle());
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession with authenticator activity started. When
+ * Activity is provided, AccountManager would start the resolution Intent
+ * and return the final result which contains an encrypted session bundle,
+ * account password and status token.
+ */
+ public void testStartUpdateCredentialsSessionIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession with KEY_INTENT returned but not
+ * started automatically. When no Activity is provided and authenticator requires
+ * additional data from user, KEY_INTENT will be returned by AccountManager.
+ */
+ public void testStartUpdateCredentialsSessionWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ // Assert that KEY_INTENT is returned.
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+ // Assert that no other data is returned.
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession error case. AuthenticatorException is
+ * expected when authenticator return
+ * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+ */
+ public void testStartUpdateCredentialsSessionError()
+ throws IOException, OperationCanceledException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+ options.putAll(OPTIONS_BUNDLE);
+
+ try {
+ startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("startUpdateCredentialsSession should throw AuthenticatorException in error.");
+ } catch (AuthenticatorException e) {
+ }
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() with callback and handler. An encrypted
+ * session bundle, account password and status token should be included in
+ * the result. Callback should be triggered with the result regardless of a
+ * handler is provider or not.
+ */
+ public void testStartUpdateCredentialsSessionWithCallbackAndHandler()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartUpdateCredentialsSessionWithCallbackAndHandler(null /* handler */);
+ testStartUpdateCredentialsSessionWithCallbackAndHandler(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() with callback and handler and
+ * activity started. When Activity is provided, AccountManager would start the
+ * resolution Intent and return the final result which contains an encrypted
+ * session bundle, account password and status token. Callback should be
+ * triggered with the result regardless of a handler is provider or not.
+ */
+ public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+ testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() with callback and handler with
+ * KEY_INTENT returned. When no Activity is provided and authenticator requires
+ * additional data from user, KEY_INTENT will be returned by AccountManager
+ * in callback regardless of a handler is provider or not.
+ */
+ public void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+ testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession() error case with callback and
+ * handler. AuthenticatorException is expected when authenticator return
+ * {@link AccountManager#ERROR_CODE_INVALID_RESPONSE} error code.
+ */
+ public void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler()
+ throws IOException, OperationCanceledException {
+ testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(null /* handler */);
+ testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ private void testStartUpdateCredentialsSessionWithCallbackAndHandler(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ mActivity,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithIntervene(
+ Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ mActivity,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartUpdateCredentialsSessionWithCallbackAndHandlerWithReturnIntent(
+ Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(AUTH_TOKEN_TYPE, mockAuthenticator.getAuthTokenType());
+ assertEquals(ACCOUNT, mockAuthenticator.mAccount);
+
+ validateStartUpdateCredentialsSessionOptions(accountName, options);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ // Assert KEY_INTENT is returned.
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+ // Assert that no other data is returned.
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ assertNull(resultBundle.getString(AccountManager.KEY_PASSWORD));
+ assertNull(resultBundle.getString(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+ latch.countDown();
+ }
+ };
+
+ startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null,
+ callback,
+ handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testStartUpdateCredentialsSessionErrorWithCallbackAndHandler(Handler handler)
+ throws IOException, OperationCanceledException {
+ final Bundle options = new Bundle();
+ final String accountName = Fixtures.PREFIX_NAME_ERROR + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, getSessionBundle(null));
+ options.putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ options.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+ options.putAll(OPTIONS_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ try {
+ bundleFuture.getResult();
+ fail("should have thrown an AuthenticatorException");
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ latch.countDown();
+ }
+ }
+ };
+
+ try {
+ startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ mActivity,
+ callback,
+ handler);
+ // AuthenticatorException should be thrown when authenticator
+ // returns AccountManager.ERROR_CODE_INVALID_RESPONSE.
+ fail("should have thrown an AuthenticatorException");
+ } catch (AuthenticatorException e1) {
+ }
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private Bundle startUpdateCredentialsSession(AccountManager am, Account account,
+ String authTokenType, Bundle options, Activity activity,
+ AccountManagerCallback<Bundle> callback, Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ AccountManagerFuture<Bundle> futureBundle = am.startUpdateCredentialsSession(account,
+ authTokenType, options, activity, callback, handler);
+
+ Bundle resultBundle = futureBundle.getResult();
+ assertTrue(futureBundle.isDone());
+ assertNotNull(resultBundle);
+
+ return resultBundle;
+ }
+
+ private void validateStartUpdateCredentialsSessionOptions(String accountName, Bundle options) {
+ validateOptions(options, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertNotNull(mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ assertEquals(accountName, mockAuthenticator.mOptionsStartUpdateCredentialsSession
+ .getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+ validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+ }
+
+ /**
+ * Tests a basic finishSession() with session bundle created by
+ * startAddAccountSession(...). A bundle containing account name and account
+ * type is expected.
+ */
+ public void testFinishSessionWithStartAddAccountSession()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests a basic finishSession() with session bundle created by
+ * startUpdateCredentialsSession(...). A bundle containing account name and account
+ * type is expected.
+ */
+ public void testFinishSessionWithStartUpdateCredentialsSession()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startUpdateCredentialsSession(...)
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests finishSession() with null session bundle. IllegalArgumentException
+ * is expected as session bundle cannot be null.
+ */
+ public void testFinishSessionWithNullSessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ try {
+ finishSession(
+ am,
+ null /* sessionBundle */,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("Should have thrown IllegalArgumentException when sessionBundle is null");
+ } catch (IllegalArgumentException e) {
+
+ }
+ }
+
+ /**
+ * Tests finishSession() with empty session bundle. IllegalArgumentException
+ * is expected as session bundle would always contain something if it was
+ * processed properly by AccountManagerService.
+ */
+ public void testFinishSessionWithEmptySessionBundle()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ try {
+ finishSession(am,
+ new Bundle(),
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("Should have thrown IllegalArgumentException when sessionBundle is empty");
+ } catch (IllegalArgumentException e) {
+
+ }
+ }
+
+ /**
+ * Tests finishSession() with sessionBundle not encrypted by the right key.
+ * AuthenticatorException is expected if AccountManagerService failed to
+ * decrypt the session bundle because of wrong key or crypto data was
+ * tampered.
+ */
+ public void testFinishSessionWithDecryptionError()
+ throws IOException, OperationCanceledException {
+ byte[] mac = new byte[] {
+ 1, 1, 0, 0
+ };
+ byte[] cipher = new byte[] {
+ 1, 0, 0, 1, 1
+ };
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putByteArray(KEY_MAC, mac);
+ sessionBundle.putByteArray(KEY_CIPHER, cipher);
+
+ try {
+ finishSession(am,
+ sessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+ } catch (AuthenticatorException e) {
+
+ }
+ }
+
+ /**
+ * Tests finishSession() with sessionBundle invalid contents.
+ * AuthenticatorException is expected if AccountManagerService failed to
+ * decrypt the session bundle because of wrong key or crypto data was
+ * tampered.
+ */
+ public void testFinishSessionWithInvalidEncryptedContent()
+ throws IOException, OperationCanceledException {
+ byte[] mac = new byte[] {};
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putByteArray(KEY_MAC, mac);
+
+ try {
+ finishSession(am,
+ sessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("Should have thrown AuthenticatorException when failed to decrypt sessionBundle");
+ } catch (AuthenticatorException e) {
+
+ }
+ }
+
+ /**
+ * Tests a finishSession() when account type is not added to session bundle
+ * by startAddAccount(...) of authenticator. A bundle containing account
+ * name and account type should still be returned as AccountManagerSerivce
+ * will always add account type to the session bundle before encrypting it.
+ */
+ public void testFinishSessionFromStartAddAccountWithoutAccountType()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+ // Create a session bundle without account type for MockAccountAuthenticator to return
+ Bundle sessionBundle = getSessionBundle(accountName);
+ sessionBundle.remove(AccountManager.KEY_ACCOUNT_TYPE);
+
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests a finishSession() when account type is not added to session bundle
+ * by startUpdateCredentialsSession(...) of authenticator. A bundle
+ * containing account name and account type should still be returned as
+ * AccountManagerSerivce will always add account type to the session bundle
+ * before encrypting it.
+ */
+ public void testFinishSessionFromStartUpdateCredentialsSessionWithoutAccountType()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+ // Create a session bundle without account type for MockAccountAuthenticator to return
+ Bundle sessionBundle = getSessionBundle(accountName);
+ sessionBundle.remove(AccountManager.KEY_ACCOUNT_TYPE);
+
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests a finishSession() when a different account type is added to session bundle
+ * by startAddAccount(...) of authenticator. A bundle containing account
+ * name and the correct account type should be returned as AccountManagerSerivce
+ * will always overrides account type to the session bundle before encrypting it.
+ */
+ public void testFinishSessionFromStartAddAccountAccountTypeOverriden()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+ // Create a session bundle with a different account type for
+ // MockAccountAuthenticator to return
+ Bundle sessionBundle = getSessionBundle(accountName);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, correct type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests a finishSession() when a different account type is added to session bundle
+ * by startUpdateCredentialsSession(...) of authenticator. A bundle
+ * containing account name and the correct account type should be returned as
+ * AccountManagerSerivce will always override account type to the session bundle
+ * before encrypting it.
+ */
+ public void testFinishSessionFromStartUpdateCredentialsSessionAccountTypeOverriden()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+
+ // Create a session bundle with a different account type for
+ // MockAccountAuthenticator to return
+ Bundle sessionBundle = getSessionBundle(accountName);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, "randomAccountType");
+
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startUpdateCredentialsSession(
+ am,
+ ACCOUNT,
+ AUTH_TOKEN_TYPE,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, correct type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests finishSession with authenticator activity started. When additional
+ * info is needed from user for finishing the session and an Activity was
+ * provided by caller, the resolution intent will be started automatically.
+ * A bundle containing account name and type will be returned.
+ */
+ public void testFinishSessionIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(
+ am,
+ encryptedSessionBundle,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+ }
+
+ /**
+ * Tests finishSession with KEY_INTENT returned but not started
+ * automatically. When additional info is needed from user for finishing the
+ * session and no Activity was provided by caller, the resolution intent
+ * will not be started automatically. A bundle containing KEY_INTENT will be
+ * returned instead.
+ */
+ public void testFinishSessionWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ resultBundle = finishSession(am, encryptedSessionBundle, null /* activity */,
+ null /* callback */, null /* handler */);
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+ assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+ assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ }
+
+ /**
+ * Tests finishSession error case. AuthenticatorException is expected when
+ * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+ */
+ public void testFinishSessionError()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ Bundle sessionBundle = new Bundle();
+ String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+ sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+
+ try {
+ finishSession(
+ am,
+ encryptedSessionBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ fail("finishSession should throw AuthenticatorException in error case.");
+ } catch (AuthenticatorException e) {
+ }
+ }
+
+ /**
+ * Tests finishSession() with callback and handler. A bundle containing
+ * account name and type should be returned via the callback regardless of
+ * whether a handler is provided.
+ */
+ public void testFinishSessionWithCallbackAndHandler()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ testFinishSessionWithCallbackAndHandler(null /* handler */);
+ testFinishSessionWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests finishSession() with callback and handler and activity started.
+ * When additional info is needed from user for finishing the session and an
+ * Activity was provided by caller, the resolution intent will be started
+ * automatically. A bundle containing account name and type will be returned
+ * via the callback regardless of if handler is provided or now.
+ */
+ public void testFinishSessionWithCallbackAndHandlerWithIntervene()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ testFinishSessionWithCallbackAndHandlerWithIntervene(null /* handler */);
+ testFinishSessionWithCallbackAndHandlerWithIntervene(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests finishSession() with callback and handler with KEY_INTENT
+ * returned. When additional info is needed from user for finishing the
+ * session and no Activity was provided by caller, the resolution intent
+ * will not be started automatically. A bundle containing KEY_INTENT will be
+ * returned instead via callback regardless of if handler is provided or not.
+ */
+ public void testFinishSessionWithCallbackAndHandlerWithReturnIntent()
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ testFinishSessionWithCallbackAndHandlerWithReturnIntent(null /* handler */);
+ testFinishSessionWithCallbackAndHandlerWithReturnIntent(
+ new Handler(Looper.getMainLooper()));
+ }
+
+ /**
+ * Tests finishSession() error case with callback and handler.
+ * AuthenticatorException is expected when
+ * AccountManager.ERROR_CODE_INVALID_RESPONSE is returned by authenticator.
+ */
+ public void testFinishSessionErrorWithCallbackAndHandler()
+ throws IOException, OperationCanceledException, AuthenticatorException {
+
+ testFinishSessionErrorWithCallbackAndHandler(null /* handler */);
+ testFinishSessionErrorWithCallbackAndHandler(new Handler(Looper.getMainLooper()));
+ }
+
+ private void testFinishSessionWithCallbackAndHandler(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ final Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testFinishSessionWithCallbackAndHandlerWithIntervene(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ final Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert returned result containing account name, type but not auth token type.
+ validateAccountAndNoAuthTokenResult(resultBundle);
+
+ latch.countDown();
+ }
+ };
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testFinishSessionWithCallbackAndHandlerWithReturnIntent(Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+ final String accountName = Fixtures.PREFIX_NAME_INTERVENE + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ final Bundle sessionBundle = getSessionBundle(accountName);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ mActivity,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ assertNull(resultBundle.getParcelable(AccountManager.KEY_INTENT));
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ Bundle resultBundle = null;
+ try {
+ resultBundle = bundleFuture.getResult();
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ fail("should not throw an AuthenticatorException");
+ }
+
+ // Assert parameters has been passed correctly
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.getAccountType());
+
+ validateFinishSessionOptions(accountName, sessionBundle);
+
+ // Assert returned result
+ Intent returnIntent = resultBundle.getParcelable(AccountManager.KEY_INTENT);
+ assertNotNull(returnIntent);
+ assertNotNull(returnIntent.getParcelableExtra(Fixtures.KEY_RESULT));
+
+ assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_NAME));
+ assertNull(resultBundle.get(AccountManager.KEY_ACCOUNT_TYPE));
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+
+ latch.countDown();
+ }
+ };
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+ finishSession(am, encryptedSessionBundle, null, callback, handler);
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private void testFinishSessionErrorWithCallbackAndHandler(Handler handler)
+ throws IOException, OperationCanceledException, AuthenticatorException {
+ Bundle sessionBundle = new Bundle();
+ String accountNameForFinish = Fixtures.PREFIX_NAME_ERROR + "@"
+ + Fixtures.SUFFIX_NAME_FIXTURE;
+ sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountNameForFinish);
+ sessionBundle.putInt(AccountManager.KEY_ERROR_CODE,
+ AccountManager.ERROR_CODE_INVALID_RESPONSE);
+ sessionBundle.putString(AccountManager.KEY_ERROR_MESSAGE, ERROR_MESSAGE);
+
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ options.putAll(OPTIONS_BUNDLE);
+
+ // First get an encrypted session bundle from startAddAccountSession(...)
+ Bundle resultBundle = startAddAccountSession(
+ am,
+ ACCOUNT_TYPE,
+ AUTH_TOKEN_TYPE,
+ REQUIRED_FEATURES,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ // Assert returned result
+ // Assert that auth token was stripped.
+ assertNull(resultBundle.get(AccountManager.KEY_AUTHTOKEN));
+ validateSessionBundleAndPasswordAndStatusTokenResult(resultBundle);
+ Bundle encryptedSessionBundle = resultBundle
+ .getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+
+ final CountDownLatch latch = new CountDownLatch(1);
+
+ AccountManagerCallback<Bundle> callback = new AccountManagerCallback<Bundle>() {
+ @Override
+ public void run(AccountManagerFuture<Bundle> bundleFuture) {
+ try {
+ bundleFuture.getResult();
+ fail("should have thrown an AuthenticatorException");
+ } catch (OperationCanceledException e) {
+ fail("should not throw an OperationCanceledException");
+ } catch (IOException e) {
+ fail("should not throw an IOException");
+ } catch (AuthenticatorException e) {
+ latch.countDown();
+ }
+ }
+ };
+
+ // Cleanup before calling finishSession(...) with the encrypted session bundle.
+ mockAuthenticator.clearData();
+
+ try {
+ finishSession(am, encryptedSessionBundle, mActivity, callback, handler);
+ fail("should have thrown an AuthenticatorException");
+ } catch (AuthenticatorException e1) {
+ }
+
+ // Wait with timeout for the callback to do its work
+ try {
+ latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ fail("should not throw an InterruptedException");
+ }
+ }
+
+ private Bundle finishSession(AccountManager am, Bundle sessionBundle, Activity activity,
+ AccountManagerCallback<Bundle> callback, Handler handler)
+ throws IOException, AuthenticatorException, OperationCanceledException {
+
+ AccountManagerFuture<Bundle> futureBundle = am.finishSession(
+ sessionBundle,
+ activity,
+ callback,
+ handler);
+
+ Bundle resultBundle = futureBundle.getResult();
+ assertTrue(futureBundle.isDone());
+ assertNotNull(resultBundle);
+
+ return resultBundle;
+ }
+
+ private void validateFinishSessionOptions(String accountName, Bundle options) {
+ validateOptions(options, mockAuthenticator.mOptionsFinishSession);
+ assertNotNull(mockAuthenticator.mOptionsFinishSession);
+ assertEquals(ACCOUNT_TYPE, mockAuthenticator.mOptionsFinishSession
+ .getString(AccountManager.KEY_ACCOUNT_TYPE));
+ assertEquals(accountName,
+ mockAuthenticator.mOptionsFinishSession.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ validateSystemOptions(mockAuthenticator.mOptionsFinishSession);
+ validateOptions(null, mockAuthenticator.mOptionsUpdateCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsConfirmCredentials);
+ validateOptions(null, mockAuthenticator.mOptionsGetAuthToken);
+ validateOptions(null, mockAuthenticator.mOptionsAddAccount);
+ validateOptions(null, mockAuthenticator.mOptionsStartAddAccountSession);
+ validateOptions(null, mockAuthenticator.mOptionsStartUpdateCredentialsSession);
+ }
}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
index 2068f4c..0105782 100644
--- a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffiliatedAuthenticatorTests.java
@@ -23,8 +23,11 @@
import android.accounts.OperationCanceledException;
import android.accounts.cts.common.AuthenticatorContentProvider;
import android.accounts.cts.common.Fixtures;
+import android.accounts.cts.common.tx.AddAccountTx;
+import android.accounts.cts.common.tx.UpdateCredentialsTx;
import android.content.ContentProviderClient;
import android.content.ContentResolver;
+import android.os.Bundle;
import android.os.RemoteException;
import android.test.AndroidTestCase;
@@ -222,5 +225,226 @@
getContext().getPackageName());
assertEquals(0, accounts.length);
}
+
+ /**
+ * Tests startAddAccountSession default implementation. An encrypted session
+ * bundle should always be returned without password or status token.
+ */
+ public void testStartAddAccountSessionDefaultImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+ AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+ Fixtures.TYPE_STANDARD_UNAFFILIATED,
+ null /* authTokenType */,
+ null /* requiredFeatures */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Validate that auth token was stripped from result.
+ assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+ // Validate that no password nor status token is returned in the result
+ // for default implementation.
+ validateNullPasswordAndStatusToken(result);
+
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ // Validate session bundle is returned but data in the bundle is
+ // encrypted and hence not visible.
+ assertNotNull(sessionBundle);
+ assertNull(sessionBundle.getString(AccountManager.KEY_ACCOUNT_TYPE));
+ }
+
+ private void validateNullPasswordAndStatusToken(Bundle result) {
+ assertNull(result.getString(AccountManager.KEY_PASSWORD));
+ assertNull(result.getString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN));
+ }
+
+ /**
+ * Tests startUpdateCredentialsSession default implementation. An encrypted session
+ * bundle should always be returned without password or status token.
+ */
+ public void testStartUpdateCredentialsSessionDefaultImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+ AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+ Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+ null /* authTokenType */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Validate no auth token in result.
+ assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+
+ // Validate that no password nor status token is returned in the result
+ // for default implementation.
+ validateNullPasswordAndStatusToken(result);
+
+ Bundle sessionBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ // Validate session bundle is returned but data in the bundle is
+ // encrypted and hence not visible.
+ assertNotNull(sessionBundle);
+ assertNull(sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME));
+ }
+
+ /**
+ * Tests finishSession default implementation with default startAddAccountSession.
+ * Only account name and account type should be returned as a bundle.
+ */
+ public void testFinishSessionAndStartAddAccountSessionDefaultImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException,
+ RemoteException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+ // First obtain an encrypted session bundle from startAddAccountSession(...) default
+ // implementation.
+ AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+ Fixtures.TYPE_STANDARD_UNAFFILIATED,
+ null /* authTokenType */,
+ null /* requiredFeatures */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Assert that result contains a non-null session bundle.
+ Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(escrowBundle);
+
+ // Now call finishSession(...) with the session bundle we just obtained.
+ future = mAccountManager.finishSession(
+ escrowBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Validate that parameters are passed to addAccount(...) correctly in default finishSession
+ // implementation.
+ Bundle providerBundle = mProviderClient.call(
+ AuthenticatorContentProvider.METHOD_GET,
+ null /* arg */,
+ null /* extras */);
+ providerBundle.setClassLoader(AddAccountTx.class.getClassLoader());
+ AddAccountTx addAccountTx = providerBundle
+ .getParcelable(AuthenticatorContentProvider.KEY_TX);
+ assertNotNull(addAccountTx);
+
+ // Assert parameters has been passed to addAccount(...) correctly
+ assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED, addAccountTx.accountType);
+ assertNull(addAccountTx.authTokenType);
+
+ validateSystemOptions(addAccountTx.options);
+ // Validate options
+ assertNotNull(addAccountTx.options);
+ assertEquals(accountName, addAccountTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+ // Validate features.
+ assertEquals(0, addAccountTx.requiredFeatures.size());
+
+ // Assert returned result contains correct account name, account type and null auth token.
+ assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED,
+ result.get(AccountManager.KEY_ACCOUNT_TYPE));
+ assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+ }
+
+ /**
+ * Tests finishSession default implementation with default startAddAccountSession.
+ * Only account name and account type should be returned as a bundle.
+ */
+ public void testFinishSessionAndStartUpdateCredentialsSessionDefaultImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException,
+ RemoteException {
+ Bundle options = new Bundle();
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+
+ // First obtain an encrypted session bundle from startUpdateCredentialsSession(...) default
+ // implementation.
+ AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+ Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS,
+ null /* authTokenTYpe */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Assert that result contains a non-null session bundle.
+ Bundle escrowBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(escrowBundle);
+
+ // Now call finishSession(...) with the session bundle we just obtained.
+ future = mAccountManager.finishSession(
+ escrowBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ // Validate that parameters are passed to updateCredentials(...) correctly in default
+ // finishSession implementation.
+ Bundle providerBundle = mProviderClient.call(
+ AuthenticatorContentProvider.METHOD_GET,
+ null /* arg */,
+ null /* extras */);
+ providerBundle.setClassLoader(UpdateCredentialsTx.class.getClassLoader());
+ UpdateCredentialsTx updateCredentialsTx = providerBundle
+ .getParcelable(AuthenticatorContentProvider.KEY_TX);
+ assertNotNull(updateCredentialsTx);
+
+ // Assert parameters has been passed to updateCredentials(...) correctly
+ assertEquals(Fixtures.ACCOUNT_UNAFFILIATED_FIXTURE_SUCCESS, updateCredentialsTx.account);
+ assertNull(updateCredentialsTx.authTokenType);
+
+ validateSystemOptions(updateCredentialsTx.options);
+ // Validate options
+ assertNotNull(updateCredentialsTx.options);
+ assertEquals(accountName, updateCredentialsTx.options.getString(Fixtures.KEY_ACCOUNT_NAME));
+
+ // Assert returned result contains correct account name, account type and null auth token.
+ assertEquals(accountName, result.get(AccountManager.KEY_ACCOUNT_NAME));
+ assertEquals(Fixtures.TYPE_STANDARD_UNAFFILIATED,
+ result.get(AccountManager.KEY_ACCOUNT_TYPE));
+ assertNull(result.get(AccountManager.KEY_AUTHTOKEN));
+ }
+
+ private void validateSystemOptions(Bundle options) {
+ assertNotNull(options.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME));
+ assertTrue(options.containsKey(AccountManager.KEY_CALLER_UID));
+ assertTrue(options.containsKey(AccountManager.KEY_CALLER_PID));
+ }
}
diff --git a/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java
new file mode 100644
index 0000000..1329eb3
--- /dev/null
+++ b/tests/tests/accounts/src/android/accounts/cts/AccountManagerUnaffliatedCustomAuthenticatorTests.java
@@ -0,0 +1,139 @@
+
+package android.accounts.cts;
+
+import android.accounts.AccountManager;
+import android.accounts.AccountManagerFuture;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.accounts.cts.common.Fixtures;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+
+/**
+ * Tests for AccountManager and AbstractAccountAuthenticator related behavior
+ * using {@link android.accounts.cts.common.CustomTestAccountAuthenticator}
+ * instances signed with different keys than the caller. This is important to
+ * test that portion of the default implementation of the
+ * {@link AccountManager#finishSession} API when implementers of
+ * {@link android.accounts.AbstractAccountAuthenticator} override only
+ * {@link AccountManager#startAddAccountSession} and/or
+ * {@link AccountManager#startUpdateCredentialsSession} but not
+ * {@link AccountManager#finishSession}.
+ * <p>
+ * You can run those unit tests with the following command line:
+ * <p>
+ * adb shell am instrument -e debug false -w -e class
+ * android.accounts.cts.AccountManagerUnaffiliatedCustomAuthenticatorTests
+ * android.accounts.cts/android.support.test.runner.AndroidJUnitRunner
+ */
+public class AccountManagerUnaffliatedCustomAuthenticatorTests extends AndroidTestCase {
+
+ private AccountManager mAccountManager;
+
+ @Override
+ public void setUp() throws Exception {
+ // bind to the diagnostic service and set it up.
+ mAccountManager = AccountManager.get(getContext());
+ }
+
+ /**
+ * Tests finishSession default implementation with custom
+ * startAddAccountSession implementation. AuthenticatorException is expected
+ * because default implementation cannot understand custom session bundle.
+ */
+ public void testFinishSessiontWithCustomStartAddAccountSessionImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ // Creates session bundle to be returned by custom implementation of
+ // startAddAccountSession of authenticator.
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+ // First get an encrypted session bundle from custom startAddAccountSession implementation.
+ AccountManagerFuture<Bundle> future = mAccountManager.startAddAccountSession(
+ Fixtures.TYPE_CUSTOM_UNAFFILIATED,
+ null /* authTokenType */,
+ null /* requiredFeatures */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(decryptedBundle);
+
+ try {
+ // Call default implementation of finishSession of authenticator
+ // with encrypted session bundle.
+ future = mAccountManager.finishSession(
+ decryptedBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ future.getResult();
+
+ fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+ } catch (AuthenticatorException e) {
+ }
+ }
+
+ /**
+ * Tests finishSession default implementation with custom
+ * startUpdateCredentialsSession implementation. AuthenticatorException is expected
+ * because default implementation cannot understand custom session bundle.
+ */
+ public void testFinishSessionWithCustomStartUpdateCredentialsSessionImpl()
+ throws OperationCanceledException, AuthenticatorException, IOException {
+ String accountName = Fixtures.PREFIX_NAME_SUCCESS + "@" + Fixtures.SUFFIX_NAME_FIXTURE;
+ // Creates session bundle to be returned by custom implementation of
+ // startUpdateCredentialsSession of authenticator.
+ Bundle sessionBundle = new Bundle();
+ sessionBundle.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ sessionBundle.putString(AccountManager.KEY_ACCOUNT_TYPE, Fixtures.TYPE_CUSTOM_UNAFFILIATED);
+ Bundle options = new Bundle();
+ options.putString(Fixtures.KEY_ACCOUNT_NAME, accountName);
+ options.putBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+
+ // First get an encrypted session bundle from custom
+ // startUpdateCredentialsSession implementation.
+ AccountManagerFuture<Bundle> future = mAccountManager.startUpdateCredentialsSession(
+ Fixtures.ACCOUNT_CUSTOM_UNAFFILIATED_FIXTURE_SUCCESS,
+ null /* authTokenType */,
+ options,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+
+ Bundle result = future.getResult();
+ assertTrue(future.isDone());
+ assertNotNull(result);
+
+ Bundle decryptedBundle = result.getBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE);
+ assertNotNull(decryptedBundle);
+
+ try {
+ // Call default implementation of finishSession of authenticator
+ // with encrypted session bundle.
+ future = mAccountManager.finishSession(
+ decryptedBundle,
+ null /* activity */,
+ null /* callback */,
+ null /* handler */);
+ future.getResult();
+
+ fail("Should have thrown AuthenticatorException if finishSession is not overridden.");
+ } catch (AuthenticatorException e) {
+ }
+ }
+}
diff --git a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
index c1b08de..6f355fb 100644
--- a/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
+++ b/tests/tests/accounts/src/android/accounts/cts/MockAccountAuthenticator.java
@@ -21,6 +21,7 @@
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
import android.accounts.NetworkErrorException;
+import android.accounts.cts.common.Fixtures;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
@@ -55,6 +56,9 @@
public Bundle mOptionsConfirmCredentials;
public Bundle mOptionsAddAccount;
public Bundle mOptionsGetAuthToken;
+ public Bundle mOptionsStartAddAccountSession;
+ public Bundle mOptionsStartUpdateCredentialsSession;
+ public Bundle mOptionsFinishSession;
Account mAccount;
String[] mFeatures;
@@ -115,6 +119,9 @@
mOptionsAddAccount = null;
mOptionsGetAuthToken = null;
mOptionsConfirmCredentials = null;
+ mOptionsStartAddAccountSession = null;
+ mOptionsStartUpdateCredentialsSession = null;
+ mOptionsFinishSession = null;
mAccount = null;
mFeatures = null;
}
@@ -295,4 +302,210 @@
}
return result;
}
+
+ /**
+ * Starts add account flow of the specified accountType to authenticate
+ * user.
+ */
+ @Override
+ public Bundle startAddAccountSession(AccountAuthenticatorResponse response, String accountType,
+ String authTokenType, String[] requiredFeatures, Bundle options)
+ throws NetworkErrorException {
+
+ this.mResponse = response;
+ this.mAccountType = accountType;
+ this.mAuthTokenType = authTokenType;
+ this.mRequiredFeatures = requiredFeatures;
+ this.mOptionsStartAddAccountSession = options;
+
+ String accountName = null;
+ boolean isCallbackRequired = false;
+ Bundle sessionBundle = null;
+ if (options != null) {
+ accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+ isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+ sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+ }
+
+ Bundle result = new Bundle();
+ if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+ result.putString(AccountManager.KEY_PASSWORD, AccountManagerTest.ACCOUNT_PASSWORD);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+ eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+ AccountManagerTest.ACCOUNT_PASSWORD);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+ sessionBundle);
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+ String errorMsg = "Default Error Message";
+ if (options != null) {
+ errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+ errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+ }
+ result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+ }
+
+ try {
+ return (isCallbackRequired) ? null : result;
+ } finally {
+ if (isCallbackRequired) {
+ response.onResult(result);
+ }
+ }
+
+ }
+
+ /**
+ * Starts the update credentials flow to re-auth user but does not update
+ * locally stored credentials for an account.
+ */
+ @Override
+ public Bundle startUpdateCredentialsSession(AccountAuthenticatorResponse response, Account account,
+ String authTokenType, Bundle options) throws NetworkErrorException {
+
+ mResponse = response;
+ mAccount = account;
+ mAuthTokenType = authTokenType;
+ mOptionsStartUpdateCredentialsSession = options;
+
+ String accountName = null;
+ boolean isCallbackRequired = false;
+ Bundle sessionBundle = null;
+ if (options != null) {
+ accountName = options.getString(Fixtures.KEY_ACCOUNT_NAME);
+ isCallbackRequired = options.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+ sessionBundle = options.getBundle(Fixtures.KEY_ACCOUNT_SESSION_BUNDLE);
+ }
+
+ Bundle result = new Bundle();
+ if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putBundle(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE, sessionBundle);
+ result.putString(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+ result.putString(AccountManager.KEY_PASSWORD, AccountManagerTest.ACCOUNT_PASSWORD);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_STATUS_TOKEN,
+ AccountManagerTest.ACCOUNT_STATUS_TOKEN);
+ eventualActivityResultData.putExtra(AccountManager.KEY_PASSWORD,
+ AccountManagerTest.ACCOUNT_PASSWORD);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_SESSION_BUNDLE,
+ sessionBundle);
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+ String errorMsg = "Default Error Message";
+ if (options != null) {
+ errorCode = options.getInt(AccountManager.KEY_ERROR_CODE);
+ errorMsg = options.getString(AccountManager.KEY_ERROR_MESSAGE);
+ }
+ result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+ }
+
+ try {
+ return (isCallbackRequired) ? null : result;
+ } finally {
+ if (isCallbackRequired) {
+ response.onResult(result);
+ }
+ }
+ }
+
+ /**
+ * Finishes account session started by adding the account to device or updating the local
+ * credentials.
+ */
+ @Override
+ public Bundle finishSession(
+ AccountAuthenticatorResponse response,
+ String accountType,
+ Bundle sessionBundle) throws NetworkErrorException {
+
+ this.mResponse = response;
+ this.mAccountType = accountType;
+ this.mOptionsFinishSession = sessionBundle;
+
+ String accountName = null;
+ boolean isCallbackRequired = false;
+ if (sessionBundle != null) {
+ accountName = sessionBundle.getString(Fixtures.KEY_ACCOUNT_NAME);
+ isCallbackRequired = sessionBundle.getBoolean(Fixtures.KEY_CALLBACK_REQUIRED, false);
+ }
+
+ Bundle result = new Bundle();
+ if (accountName.startsWith(Fixtures.PREFIX_NAME_SUCCESS)) {
+ // fill bundle with a success result.
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, AccountManagerTest.ACCOUNT_NAME);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, AccountManagerTest.ACCOUNT_TYPE);
+ result.putString(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+ } else if (accountName.startsWith(Fixtures.PREFIX_NAME_INTERVENE)) {
+ // Specify data to be returned by the eventual activity.
+ Intent eventualActivityResultData = new Intent();
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_NAME,
+ AccountManagerTest.ACCOUNT_NAME);
+ eventualActivityResultData.putExtra(AccountManager.KEY_ACCOUNT_TYPE,
+ AccountManagerTest.ACCOUNT_TYPE);
+ eventualActivityResultData.putExtra(AccountManager.KEY_AUTHTOKEN,
+ Integer.toString(mTokenCounter.incrementAndGet()));
+
+ // Fill result with Intent.
+ Intent intent = new Intent(mContext, AccountAuthenticatorDummyActivity.class);
+ intent.putExtra(Fixtures.KEY_RESULT, eventualActivityResultData);
+ intent.putExtra(Fixtures.KEY_CALLBACK, response);
+
+ result.putParcelable(AccountManager.KEY_INTENT, intent);
+ } else {
+ // fill with error
+ int errorCode = AccountManager.ERROR_CODE_INVALID_RESPONSE;
+ String errorMsg = "Default Error Message";
+ if (sessionBundle != null) {
+ errorCode = sessionBundle.getInt(AccountManager.KEY_ERROR_CODE);
+ errorMsg = sessionBundle.getString(AccountManager.KEY_ERROR_MESSAGE);
+ }
+ result.putInt(AccountManager.KEY_ERROR_CODE, errorCode);
+ result.putString(AccountManager.KEY_ERROR_MESSAGE, errorMsg);
+ }
+
+ try {
+ return (isCallbackRequired) ? null : result;
+ } finally {
+ if (isCallbackRequired) {
+ response.onResult(result);
+ }
+ }
+ }
}
diff --git a/tests/tests/alarmclock/Android.mk b/tests/tests/alarmclock/Android.mk
index 6c30bc7..ee3e015 100644
--- a/tests/tests/alarmclock/Android.mk
+++ b/tests/tests/alarmclock/Android.mk
@@ -29,5 +29,10 @@
LOCAL_SDK_VERSION := current
+LOCAL_CTS_MODULE_CONFIG := $(LOCAL_PATH)/Old$(CTS_MODULE_TEST_CONFIG)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/alarmclock/AndroidTest.xml b/tests/tests/alarmclock/AndroidTest.xml
index aafdb61..525257e 100644
--- a/tests/tests/alarmclock/AndroidTest.xml
+++ b/tests/tests/alarmclock/AndroidTest.xml
@@ -1,3 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,10 +13,19 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Test module config for AlarmClock">
- <include name="common-config" />
- <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
- <option name="run-command:run-command"
- value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
- <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
-</configuration>
+<configuration description="Configuration for AlarmClock Tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsAlarmClockService.apk" />
+ <option name="test-file-name" value="CtsAlarmClockTestCases.apk" />
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command"
+ value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest">
+ <option name="package" value="android.alarmclock.cts" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/alarmclock/OldAndroidTest.xml b/tests/tests/alarmclock/OldAndroidTest.xml
new file mode 100644
index 0000000..aafdb61
--- /dev/null
+++ b/tests/tests/alarmclock/OldAndroidTest.xml
@@ -0,0 +1,21 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Test module config for AlarmClock">
+ <include name="common-config" />
+ <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockService.apk" />
+ <option name="run-command:run-command"
+ value="settings put secure voice_interaction_service android.alarmclock.service/.MainInteractionService" />
+ <option name="cts-apk-installer:test-file-name" value="CtsAlarmClockTestCases.apk" />
+</configuration>
diff --git a/tests/tests/alarmclock/common/Android.mk b/tests/tests/alarmclock/common/Android.mk
index d460ade..d0b7be0 100644
--- a/tests/tests/alarmclock/common/Android.mk
+++ b/tests/tests/alarmclock/common/Android.mk
@@ -27,4 +27,7 @@
LOCAL_SDK_VERSION := current
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tests/tests/alarmclock/service/Android.mk b/tests/tests/alarmclock/service/Android.mk
index 53dc564..3502582 100644
--- a/tests/tests/alarmclock/service/Android.mk
+++ b/tests/tests/alarmclock/service/Android.mk
@@ -29,4 +29,7 @@
LOCAL_SDK_VERSION := current
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
index 4c1b1f3..c21bc9c 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistStructureTest.java
@@ -80,6 +80,10 @@
}
public void testAssistStructure() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.start3pApp(TEST_CASE_TYPE);
mTestActivity.startTest(TEST_CASE_TYPE);
waitForAssistantToBeReady(mReadyLatch);
diff --git a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
index 46fb8d9..29b35c5 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistTestBase.java
@@ -19,6 +19,7 @@
import android.assist.cts.TestStartActivity;
import android.assist.common.Utils;
+import android.app.ActivityManager;
import android.app.assist.AssistContent;
import android.app.assist.AssistStructure;
import android.app.assist.AssistStructure.ViewNode;
@@ -57,6 +58,7 @@
public class AssistTestBase extends ActivityInstrumentationTestCase2<TestStartActivity> {
private static final String TAG = "AssistTestBase";
+ protected ActivityManager mActivityManager;
protected TestStartActivity mTestActivity;
protected AssistContent mAssistContent;
protected AssistStructure mAssistStructure;
@@ -123,6 +125,7 @@
intent.putExtra(Utils.TESTCASE_TYPE, testName);
setActivityIntent(intent);
mTestActivity = getActivity();
+ mActivityManager = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
}
/**
diff --git a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
index 557134b..c6ac3a6 100644
--- a/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
+++ b/tests/tests/assist/src/android/assist/cts/AssistantContentViewTest.java
@@ -83,6 +83,10 @@
}
public void testAssistantContentViewDimens() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.startTest(Utils.VERIFY_CONTENT_VIEW);
waitForAssistantToBeReady(mReadyLatch);
startSession();
diff --git a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
index 5c8aa19..ea4cd3d 100644
--- a/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
+++ b/tests/tests/assist/src/android/assist/cts/DisableContextTest.java
@@ -63,6 +63,10 @@
}
public void testContextAndScreenshotOff() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
// Both settings off
Log.i(TAG, "DisableContext: Screenshot OFF, Context OFF");
SystemUtil.runShellCommand(getInstrumentation(),
diff --git a/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
index 28b2af2..1154179 100644
--- a/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
+++ b/tests/tests/assist/src/android/assist/cts/ExtraAssistDataTest.java
@@ -66,6 +66,10 @@
}
public void testAssistContentAndAssistData() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.startTest(TEST_CASE_TYPE);
waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(TEST_CASE_TYPE);
diff --git a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
index 35f95a4..fc7c8fb 100644
--- a/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FlagSecureTest.java
@@ -77,6 +77,10 @@
}
public void testSecureActivity() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.startTest(TEST_CASE_TYPE);
waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(TEST_CASE_TYPE);
diff --git a/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
index f6b90b9..621361e 100644
--- a/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
+++ b/tests/tests/assist/src/android/assist/cts/FocusChangeTest.java
@@ -86,6 +86,10 @@
}
public void testLayerCausesUnderlyingActivityToLoseFocus() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.startTest(Utils.FOCUS_CHANGE);
waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(Utils.FOCUS_CHANGE);
diff --git a/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
index bc2ab80..25f36b7 100644
--- a/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LargeViewHierarchyTest.java
@@ -79,6 +79,10 @@
}
public void testTextView() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.start3pApp(TEST_CASE_TYPE);
mTestActivity.startTest(TEST_CASE_TYPE);
waitForAssistantToBeReady(mReadyLatch);
@@ -102,4 +106,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
index c886b74..3ed26d1 100644
--- a/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
+++ b/tests/tests/assist/src/android/assist/cts/LifecycleTest.java
@@ -98,6 +98,10 @@
}
public void testLayerDoesNotTriggerLifecycleMethods() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.startTest(Utils.LIFECYCLE);
waitForAssistantToBeReady(mReadyLatch);
mTestActivity.start3pApp(Utils.LIFECYCLE);
diff --git a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
index 45082ae..b84e334 100644
--- a/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
+++ b/tests/tests/assist/src/android/assist/cts/ScreenshotTest.java
@@ -70,6 +70,10 @@
}
public void testRedScreenshot() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
Log.i(TAG, "Starting screenshot test");
mTestActivity.startTest(TEST_CASE_TYPE);
Log.i(TAG, "start waitForAssistantToBeReady()");
@@ -81,6 +85,10 @@
}
public void testGreenScreenshot() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
Log.i(TAG, "Starting screenshot test");
mTestActivity.startTest(TEST_CASE_TYPE);
Log.i(TAG, "start waitForAssistantToBeReady()");
@@ -92,6 +100,10 @@
}
public void testBlueScreenshot() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
Log.i(TAG, "Starting screenshot test");
mTestActivity.startTest(TEST_CASE_TYPE);
Log.i(TAG, "start waitForAssistantToBeReady()");
diff --git a/tests/tests/assist/src/android/assist/cts/TextViewTest.java b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
index e4390bc..089993d 100644
--- a/tests/tests/assist/src/android/assist/cts/TextViewTest.java
+++ b/tests/tests/assist/src/android/assist/cts/TextViewTest.java
@@ -79,6 +79,10 @@
}
public void testTextView() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
mTestActivity.start3pApp(TEST_CASE_TYPE);
scrollTestApp(0, 0, true, false);
@@ -130,4 +134,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/assist/src/android/assist/cts/WebViewTest.java b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
index e367e22..4e05494 100644
--- a/tests/tests/assist/src/android/assist/cts/WebViewTest.java
+++ b/tests/tests/assist/src/android/assist/cts/WebViewTest.java
@@ -90,6 +90,10 @@
}
public void testWebView() throws Exception {
+ if (mActivityManager.isLowRamDevice()) {
+ Log.d(TAG, "Not running assist tests on low-RAM device.");
+ return;
+ }
if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
return;
}
@@ -118,4 +122,4 @@
}
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/content/Android.mk b/tests/tests/content/Android.mk
index 0b3b19f..924c639 100644
--- a/tests/tests/content/Android.mk
+++ b/tests/tests/content/Android.mk
@@ -23,7 +23,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 ctsdeviceutil ctstestrunner
# Resource unit tests use a private locale and some densities
LOCAL_AAPT_FLAGS = -c xx_YY -c cs -c small -c normal -c large -c xlarge \
diff --git a/tests/tests/content/AndroidManifest.xml b/tests/tests/content/AndroidManifest.xml
index 405ca3d..d88fdad 100644
--- a/tests/tests/content/AndroidManifest.xml
+++ b/tests/tests/content/AndroidManifest.xml
@@ -170,6 +170,13 @@
<provider android:name="android.content.cts.MockRemoteContentProvider"
android:authorities="remotectstest"
android:process=":remoteprovider" android:multiprocess="false" />
+ <provider android:name="android.support.v4.content.FileProvider"
+ android:authorities="android.content.cts.fileprovider"
+ android:grantUriPermissions="true">
+ <meta-data
+ android:name="android.support.FILE_PROVIDER_PATHS"
+ android:resource="@xml/file_paths" />
+ </provider>
<service android:name="android.content.cts.MockService" />
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/tests/tests/content/res/values-v24/strings.xml
similarity index 62%
rename from apps/CtsVerifier/res/xml/device_admin.xml
rename to tests/tests/content/res/values-v24/strings.xml
index 49d705a..b84c3a6 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/tests/tests/content/res/values-v24/strings.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,13 +14,6 @@
limitations under the License.
-->
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="version_cur">v24cur</string>
+</resources>
diff --git a/tests/tests/content/res/xml/file_paths.xml b/tests/tests/content/res/xml/file_paths.xml
new file mode 100644
index 0000000..e8d2861
--- /dev/null
+++ b/tests/tests/content/res/xml/file_paths.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 Google Inc. All Rights Reserved. -->
+
+<!-- Specify the storage area and path used in file provider. -->
+<paths xmlns:android="http://schemas.android.com/apk/res/android">
+ <files-path name="debug" path="debug/"/>
+</paths>
\ No newline at end of file
diff --git a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
index 5a2625f..588a915 100644
--- a/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
+++ b/tests/tests/content/src/android/content/cts/BroadcastReceiverTest.java
@@ -49,7 +49,7 @@
private static final String ACTION_BROADCAST_DISABLED =
"android.content.cts.BroadcastReceiverTest.BROADCAST_DISABLED";
- private static final long SEND_BROADCAST_TIMEOUT = 5000;
+ private static final long SEND_BROADCAST_TIMEOUT = 15000;
private static final long START_SERVICE_TIMEOUT = 3000;
private static final ComponentName DISABLEABLE_RECEIVER =
@@ -166,7 +166,8 @@
assertEquals(null, internalReceiver.getResultData());
assertEquals(null, internalReceiver.getResultExtras(false));
- activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+ activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
activity.unregisterReceiver(internalReceiver);
@@ -181,7 +182,8 @@
map.putString(MockReceiver.RESULT_EXTRAS_REMOVE_KEY,
MockReceiver.RESULT_EXTRAS_REMOVE_VALUE);
getInstrumentation().getContext().sendOrderedBroadcast(
- new Intent(ACTION_BROADCAST_MOCKTEST), null, internalOrderReceiver,
+ new Intent(ACTION_BROADCAST_MOCKTEST).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ null, internalOrderReceiver,
null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
@@ -212,7 +214,8 @@
// MockReceiverFirst --> MockReceiverAbort --> MockReceiver --> internalOrderReceiver.
// And MockReceiver is the receiver which will be aborted.
getInstrumentation().getContext().sendOrderedBroadcast(
- new Intent(ACTION_BROADCAST_TESTABORT), null, internalOrderReceiver,
+ new Intent(ACTION_BROADCAST_TESTABORT).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ null, internalOrderReceiver,
null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, map);
internalOrderReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
@@ -242,7 +245,8 @@
PackageManager.DONT_KILL_APP);
context.sendOrderedBroadcast(
- new Intent(ACTION_BROADCAST_DISABLED), null, lastReceiver,
+ new Intent(ACTION_BROADCAST_DISABLED).addFlags(Intent.FLAG_RECEIVER_FOREGROUND),
+ null, lastReceiver,
null, RESULT_INITIAL_CODE, RESULT_INITIAL_DATA, new Bundle());
lastReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
@@ -257,7 +261,8 @@
filter.addAction(ACTION_BROADCAST_INTERNAL);
activity.registerReceiver(internalReceiver, filter);
- activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+ activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
assertNull(internalReceiver.getIBinder());
@@ -267,7 +272,8 @@
assertTrue(msc.waitForService(START_SERVICE_TIMEOUT));
internalReceiver.reset();
- activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL));
+ activity.sendBroadcast(new Intent(ACTION_BROADCAST_INTERNAL)
+ .addFlags(Intent.FLAG_RECEIVER_FOREGROUND));
internalReceiver.waitForReceiver(SEND_BROADCAST_TIMEOUT);
assertNotNull(internalReceiver.getIBinder());
activity.unbindService(msc);
diff --git a/tests/tests/content/src/android/content/cts/ComponentNameTest.java b/tests/tests/content/src/android/content/cts/ComponentNameTest.java
index 995de5f..23a2e00 100644
--- a/tests/tests/content/src/android/content/cts/ComponentNameTest.java
+++ b/tests/tests/content/src/android/content/cts/ComponentNameTest.java
@@ -92,7 +92,7 @@
public void testGetShortClassName() {
// set the expected value, test normal value
String actual = getComponentName().getShortClassName();
- assertEquals("android.content.cts.ComponentNameTest", actual);
+ assertEquals(".ComponentNameTest", actual);
// Test class name which can be abbreviated
ComponentName componentName = new ComponentName("com.android.view",
@@ -135,7 +135,7 @@
public void testFlattenToShortString() {
// Test normal
String actual = getComponentName().flattenToShortString();
- assertEquals("android.content.cts/android.content.cts.ComponentNameTest", actual);
+ assertEquals("android.content.cts/.ComponentNameTest", actual);
// Test long class name
final ComponentName componentName = new ComponentName("com.android.view",
@@ -152,12 +152,12 @@
// new the ComponentName instances, both are the same.
final ComponentName componentName1 = getComponentName();
ComponentName componentName2 = new ComponentName(componentName1.getPackageName(),
- componentName1.getShortClassName());
+ componentName1.getClassName());
assertTrue(componentName1.equals(componentName2));
// new the ComponentName instances, are not the same.
componentName2 = new ComponentName(componentName1.getPackageName(),
- componentName1.getShortClassName() + "different name");
+ componentName1.getClassName() + "different name");
assertFalse(componentName1.equals(componentName2));
}
diff --git a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
index 4a27435..28e248e 100644
--- a/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
+++ b/tests/tests/content/src/android/content/cts/ContextWrapperTest.java
@@ -157,6 +157,7 @@
registerBroadcastReceiver(lowPriorityReceiver, filterLowPriority);
final Intent broadcastIntent = new Intent(ResultReceiver.MOCK_ACTION);
+ broadcastIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
mContextWrapper.sendOrderedBroadcast(broadcastIntent, null);
new PollingCheck(BROADCAST_TIMEOUT) {
@Override
@@ -186,8 +187,10 @@
Bundle bundle = new Bundle();
bundle.putString(KEY_KEPT, VALUE_KEPT);
bundle.putString(KEY_REMOVED, VALUE_REMOVED);
- mContextWrapper.sendOrderedBroadcast(new Intent(ResultReceiver.MOCK_ACTION),
- null, broadcastReceiver, null, 1, INTIAL_RESULT, bundle);
+ Intent intent = new Intent(ResultReceiver.MOCK_ACTION);
+ intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
+ mContextWrapper.sendOrderedBroadcast(intent, null, broadcastReceiver, null, 1,
+ INTIAL_RESULT, bundle);
synchronized (mLockObj) {
try {
@@ -216,13 +219,13 @@
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver, MOCK_ACTION2);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION2);
assertFalse(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1)
broadcastReceiver.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver, MOCK_ACTION1);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION1);
assertTrue(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
@@ -235,13 +238,13 @@
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver2.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver2, MOCK_ACTION2);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION2);
assertFalse(broadcastReceiver2.hadReceivedBroadCast1());
assertFalse(broadcastReceiver2.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1), but the receiver is unregistered.
broadcastReceiver2.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver2, MOCK_ACTION1);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION1);
assertFalse(broadcastReceiver2.hadReceivedBroadCast1());
assertFalse(broadcastReceiver2.hadReceivedBroadCast2());
}
@@ -256,13 +259,13 @@
// Test unwanted intent(action = MOCK_ACTION2)
broadcastReceiver.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver, MOCK_ACTION2);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION2);
assertFalse(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
// Send wanted intent(action = MOCK_ACTION1)
broadcastReceiver.reset();
- waitForFilteredIntent(mContextWrapper, broadcastReceiver, MOCK_ACTION1);
+ waitForFilteredIntent(mContextWrapper, MOCK_ACTION1);
assertTrue(broadcastReceiver.hadReceivedBroadCast1());
assertFalse(broadcastReceiver.hadReceivedBroadCast2());
@@ -792,9 +795,9 @@
waitForCondition(con);
}
- private void waitForFilteredIntent(ContextWrapper contextWrapper,
- final FilteredReceiver receiver, final String action) throws InterruptedException {
- contextWrapper.sendOrderedBroadcast(new Intent(action), null);
+ private void waitForFilteredIntent(ContextWrapper contextWrapper, final String action)
+ throws InterruptedException {
+ contextWrapper.sendBroadcast(new Intent(action), null);
synchronized (mLockObj) {
mLockObj.wait(BROADCAST_TIMEOUT);
@@ -849,7 +852,6 @@
private class FilteredReceiver extends BroadcastReceiver {
private boolean mHadReceivedBroadCast1 = false;
-
private boolean mHadReceivedBroadCast2 = false;
public void onReceive(Context context, Intent intent) {
diff --git a/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
index 4e3ddf0..b4fcb31 100644
--- a/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
+++ b/tests/tests/content/src/android/content/cts/SharedPreferencesTest.java
@@ -18,8 +18,9 @@
import android.app.QueuedWork;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
import android.os.StrictMode;
import android.preference.PreferenceManager;
import android.test.AndroidTestCase;
@@ -39,7 +40,6 @@
private static final String TAG = "SharedPreferencesTest";
private Context mContext;
- private ContextWrapper mContextWrapper;
private File mPrefsFile;
@@ -47,15 +47,17 @@
protected void setUp() throws Exception {
super.setUp();
mContext = getContext();
- mContextWrapper = new ContextWrapper(mContext);
SharedPreferences prefs = getPrefs();
prefs.edit().clear().commit();
-
- // Duplicated from ContextImpl.java. Not ideal, but there wasn't a better
- // way to reach into Context{Wrapper,Impl} to ask where this file lives.
- mPrefsFile = new File("/data/data/android.content.cts/shared_prefs",
- "android.content.cts_preferences.xml");
+ try {
+ ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
+ mContext.getPackageName(), 0);
+ mPrefsFile = new File(applicationInfo.dataDir,
+ "shared_prefs/android.content.cts_preferences.xml");
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalStateException(e);
+ }
mPrefsFile.delete();
}
diff --git a/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java b/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
index 2461099..4e07312 100644
--- a/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ProviderInfoTest.java
@@ -21,9 +21,12 @@
import android.content.pm.PackageManager;
import android.content.pm.ProviderInfo;
import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.res.XmlResourceParser;
import android.os.Parcel;
import android.test.AndroidTestCase;
+import libcore.io.IoUtils;
+
import java.util.Iterator;
import java.util.List;
@@ -50,6 +53,19 @@
}
}
+ public void testProviderMetaData() {
+ final ProviderInfo info = getContext().getPackageManager()
+ .resolveContentProvider("android.content.cts.fileprovider",
+ PackageManager.GET_META_DATA);
+ final XmlResourceParser in = info.loadXmlMetaData(
+ getContext().getPackageManager(), "android.support.FILE_PROVIDER_PATHS");
+ try {
+ assertNotNull(in);
+ } finally {
+ IoUtils.closeQuietly(in);
+ }
+ }
+
private void checkProviderInfoMethods(ProviderInfo providerInfo, Parcel p) {
// Test toString, describeContents
assertNotNull(providerInfo.toString());
diff --git a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
index d4b6c63..c1ee6c4 100644
--- a/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ConfigurationTest.java
@@ -419,6 +419,16 @@
assertEquals(LocaleList.forLanguageTags("fr,en"), config.getLocales());
}
+ public void testSetTo_nullLocale() {
+ Configuration config1 = new Configuration();
+ Configuration config2 = new Configuration();
+ assertEquals(null, config2.locale);
+
+ config1.setLocale(Locale.FRENCH);
+ config1.setTo(config2);
+ assertEquals(null, config1.locale);
+ }
+
public void testSetTo_localeFixUp() {
Configuration config1 = new Configuration();
Configuration config2 = new Configuration();
diff --git a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
index 3931e6d..edf1d4b 100644
--- a/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
+++ b/tests/tests/content/src/android/content/res/cts/ResourcesTest.java
@@ -217,32 +217,59 @@
assertEquals(0xff00ff00, color);
}
+ public Resources createNewResources() {
+ final DisplayMetrics dm = new DisplayMetrics();
+ dm.setToDefaults();
+ final Configuration cfg = new Configuration();
+ cfg.setToDefaults();
+ return new Resources(new AssetManager(), dm, cfg);
+ }
+
public void testUpdateConfiguration() {
- final Configuration cfg = mResources.getConfiguration();
+ Resources res = createNewResources();
+ final Configuration cfg = new Configuration(res.getConfiguration());
assertTrue(cfg.fontScale != 5);
cfg.fontScale = 5;
- mResources.updateConfiguration(cfg, null);
- Configuration cfgNew = mResources.getConfiguration();
- assertEquals(5.0f, cfgNew.fontScale, 0.001f);
+ res.updateConfiguration(cfg, null);
+ assertEquals(5.0f, res.getConfiguration().fontScale, 0.001f);
}
public void testUpdateConfiguration_emptyLocaleIsOverridden() {
- final Configuration cfg = mResources.getConfiguration();
- cfg.setLocales(null);
+ Resources res = createNewResources();
+ res.getConfiguration().setLocales(null);
+ assertTrue(res.getConfiguration().getLocales().isEmpty());
+
+ final Configuration cfg = new Configuration();
+ cfg.setToDefaults();
assertTrue(cfg.getLocales().isEmpty());
- mResources.updateConfiguration(cfg, null);
- Configuration cfgNew = mResources.getConfiguration();
- assertEquals(LocaleList.getDefault(), cfgNew.getLocales());
+ res.updateConfiguration(cfg, null);
+ assertEquals(LocaleList.getDefault(), res.getConfiguration().getLocales());
}
public void testUpdateConfiguration_copyLocales() {
- final Configuration cfg = mResources.getConfiguration();
+ Resources res = createNewResources();
+ final Configuration cfg = new Configuration(res.getConfiguration());
+
cfg.setLocales(LocaleList.forLanguageTags("az-Arab,ru"));
- mResources.updateConfiguration(cfg, null);
- Configuration cfgNew = mResources.getConfiguration();
- assertEquals(LocaleList.forLanguageTags("az-Arab,ru"), cfgNew.getLocales());
+
+ res.updateConfiguration(cfg, null);
+ assertEquals(LocaleList.forLanguageTags("az-Arab,ru"), res.getConfiguration().getLocales());
+ }
+
+ public void testUpdateConfiguration_emptyAfterUpdate() {
+ Resources res = createNewResources();
+ final Configuration cfg = new Configuration(res.getConfiguration());
+ cfg.setLocales(LocaleList.forLanguageTags("az-Arab"));
+
+ res.updateConfiguration(cfg, null);
+ assertEquals(LocaleList.forLanguageTags("az-Arab"), res.getConfiguration().getLocales());
+
+ res.getConfiguration().setLocales(null);
+ cfg.setLocales(null);
+ res.updateConfiguration(cfg, null);
+ assertEquals(LocaleList.getDefault(), res.getConfiguration().getLocales());
}
public void testGetDimensionPixelSize() {
diff --git a/tests/tests/graphics/assets/bombfont.ttf b/tests/tests/graphics/assets/bombfont.ttf
new file mode 100644
index 0000000..66a89f8
--- /dev/null
+++ b/tests/tests/graphics/assets/bombfont.ttf
Binary files differ
diff --git a/tests/tests/graphics/assets/bombfont.ttx b/tests/tests/graphics/assets/bombfont.ttx
new file mode 100644
index 0000000..bf544da
--- /dev/null
+++ b/tests/tests/graphics/assets/bombfont.ttx
@@ -0,0 +1,241 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<ttFont sfntVersion="\x00\x01\x00\x00" ttLibVersion="3.0">
+
+ <GlyphOrder>
+ <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
+ <GlyphID id="0" name=".notdef"/>
+ <GlyphID id="1" name="a"/>
+ <GlyphID id="2" name="b"/>
+ <GlyphID id="3" name="c"/>
+ <GlyphID id="4" name="d"/>
+ <GlyphID id="5" name="e"/>
+ <GlyphID id="6" name="BombEmoji"/>
+ </GlyphOrder>
+
+ <head>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="1.0"/>
+ <fontRevision value="1.0"/>
+ <checkSumAdjustment value="0xaf28220f"/>
+ <magicNumber value="0x5f0f3cf5"/>
+ <flags value="00000000 00000011"/>
+ <unitsPerEm value="1000"/>
+ <created value="Wed Sep 9 08:01:17 2015"/>
+ <modified value="Tue Dec 8 03:58:55 2015"/>
+ <xMin value="0"/>
+ <yMin value="0"/>
+ <xMax value="0"/>
+ <yMax value="0"/>
+ <macStyle value="00000000 00000000"/>
+ <lowestRecPPEM value="7"/>
+ <fontDirectionHint value="2"/>
+ <indexToLocFormat value="0"/>
+ <glyphDataFormat value="0"/>
+ </head>
+
+ <hhea>
+ <tableVersion value="1.0"/>
+ <ascent value="1000"/>
+ <descent value="-200"/>
+ <lineGap value="0"/>
+ <advanceWidthMax value="500"/>
+ <minLeftSideBearing value="0"/>
+ <minRightSideBearing value="0"/>
+ <xMaxExtent value="0"/>
+ <caretSlopeRise value="1"/>
+ <caretSlopeRun value="0"/>
+ <caretOffset value="0"/>
+ <reserved0 value="0"/>
+ <reserved1 value="0"/>
+ <reserved2 value="0"/>
+ <reserved3 value="0"/>
+ <metricDataFormat value="0"/>
+ <numberOfHMetrics value="1"/>
+ </hhea>
+
+ <maxp>
+ <!-- Most of this table will be recalculated by the compiler -->
+ <tableVersion value="0x10000"/>
+ <numGlyphs value="7"/>
+ <maxPoints value="0"/>
+ <maxContours value="0"/>
+ <maxCompositePoints value="0"/>
+ <maxCompositeContours value="0"/>
+ <maxZones value="2"/>
+ <maxTwilightPoints value="12"/>
+ <maxStorage value="28"/>
+ <maxFunctionDefs value="119"/>
+ <maxInstructionDefs value="0"/>
+ <maxStackElements value="61"/>
+ <maxSizeOfInstructions value="2967"/>
+ <maxComponentElements value="0"/>
+ <maxComponentDepth value="0"/>
+ </maxp>
+
+ <OS_2>
+ <!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
+ will be recalculated by the compiler -->
+ <version value="3"/>
+ <xAvgCharWidth value="594"/>
+ <usWeightClass value="400"/>
+ <usWidthClass value="5"/>
+ <fsType value="00000000 00001000"/>
+ <ySubscriptXSize value="650"/>
+ <ySubscriptYSize value="600"/>
+ <ySubscriptXOffset value="0"/>
+ <ySubscriptYOffset value="75"/>
+ <ySuperscriptXSize value="650"/>
+ <ySuperscriptYSize value="600"/>
+ <ySuperscriptXOffset value="0"/>
+ <ySuperscriptYOffset value="350"/>
+ <yStrikeoutSize value="50"/>
+ <yStrikeoutPosition value="300"/>
+ <sFamilyClass value="0"/>
+ <panose>
+ <bFamilyType value="0"/>
+ <bSerifStyle value="0"/>
+ <bWeight value="5"/>
+ <bProportion value="0"/>
+ <bContrast value="0"/>
+ <bStrokeVariation value="0"/>
+ <bArmStyle value="0"/>
+ <bLetterForm value="0"/>
+ <bMidline value="0"/>
+ <bXHeight value="0"/>
+ </panose>
+ <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
+ <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
+ <achVendID value="UKWN"/>
+ <fsSelection value="00000000 01000000"/>
+ <usFirstCharIndex value="97"/>
+ <usLastCharIndex value="65535"/>
+ <sTypoAscender value="800"/>
+ <sTypoDescender value="-200"/>
+ <sTypoLineGap value="200"/>
+ <usWinAscent value="1000"/>
+ <usWinDescent value="200"/>
+ <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
+ <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
+ <sxHeight value="500"/>
+ <sCapHeight value="700"/>
+ <usDefaultChar value="0"/>
+ <usBreakChar value="32"/>
+ <usMaxContext value="0"/>
+ </OS_2>
+
+ <hmtx>
+ <mtx name=".notdef" width="500" lsb="93"/>
+ <mtx name="BombEmoji" width="500" lsb="93"/>
+ <mtx name="a" width="500" lsb="93"/>
+ <mtx name="b" width="500" lsb="93"/>
+ <mtx name="c" width="500" lsb="93"/>
+ <mtx name="d" width="500" lsb="93"/>
+ <mtx name="e" width="500" lsb="93"/>
+ </hmtx>
+
+ <cmap ERROR="decompilation error" raw="True">
+ <!-- An error occurred during the decompilation of this table -->
+ <hexdata>
+ 00000002 00030001 00000014 00030001
+ 00000034 00040020 00000004 00040001
+ 00000065 ffff0000 0061ffff ffa00001
+ 00000000 000c0000 00000028 00000000
+ 80000002 00000061 00000065 00000001
+ 0001f4a3 0001f4a3 00000006
+ </hexdata>
+ </cmap>
+
+ <loca>
+ <!-- The 'loca' table will be calculated by the compiler -->
+ </loca>
+
+ <glyf>
+
+ <!-- The xMin, yMin, xMax and yMax values
+ will be recalculated by the compiler. -->
+
+ <TTGlyph name=".notdef"/><!-- contains no outline data -->
+
+ <TTGlyph name="BombEmoji"/><!-- contains no outline data -->
+
+ <TTGlyph name="a"/><!-- contains no outline data -->
+
+ <TTGlyph name="b"/><!-- contains no outline data -->
+
+ <TTGlyph name="c"/><!-- contains no outline data -->
+
+ <TTGlyph name="d"/><!-- contains no outline data -->
+
+ <TTGlyph name="e"/><!-- contains no outline data -->
+
+ </glyf>
+
+ <name>
+ <namerecord nameID="1" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="2" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="6" platformID="1" platEncID="0" langID="0x0" unicode="True">
+ SampleFontTest-Regular
+ </namerecord>
+ <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
+ Regular
+ </namerecord>
+ <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
+ SampleFont Test
+ </namerecord>
+ <namerecord nameID="6" platformID="3" platEncID="1" langID="0x409">
+ SampleFontTest-Regular
+ </namerecord>
+ </name>
+
+ <post>
+ <formatType value="2.0"/>
+ <italicAngle value="0.0"/>
+ <underlinePosition value="-166"/>
+ <underlineThickness value="20"/>
+ <isFixedPitch value="0"/>
+ <minMemType42 value="0"/>
+ <maxMemType42 value="0"/>
+ <minMemType1 value="0"/>
+ <maxMemType1 value="0"/>
+ <psNames>
+ <!-- This file uses unique glyph names based on the information
+ found in the 'post' table. Since these names might not be unique,
+ we have to invent artificial names in case of clashes. In order to
+ be able to retain the original information, we need a name to
+ ps name mapping for those cases where they differ. That's what
+ you see below.
+ -->
+ </psNames>
+ <extraNames>
+ <!-- following are the name that are not taken from the standard Mac glyph order -->
+ <psName name="BombEmoji"/>
+ </extraNames>
+ </post>
+
+</ttFont>
diff --git a/tests/tests/graphics/res/drawable/gradient_drawable_density.xml b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
new file mode 100644
index 0000000..ad3a3be
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/gradient_drawable_density.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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"
+ android:shape="ring"
+ android:innerRadius="10dp"
+ android:thickness="4dp">
+ <gradient
+ android:gradientRadius="10dp" />
+ <corners
+ android:topLeftRadius="8dp"
+ android:topRightRadius="9dp"
+ android:bottomLeftRadius="10dp"
+ android:bottomRightRadius="11dp" />
+ <padding
+ android:left="11dp"
+ android:top="12dp"
+ android:right="13dp"
+ android:bottom="14dp" />
+ <stroke
+ android:color="@android:color/black"
+ android:dashGap="4dp"
+ android:dashWidth="4dp"
+ android:width="2dp" />
+ <size
+ android:width="200dp"
+ android:height="200dp" />
+</shape>
diff --git a/tests/tests/graphics/res/drawable/inset_color.xml b/tests/tests/graphics/res/drawable/inset_color.xml
new file mode 100644
index 0000000..55cdf22
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/inset_color.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@android:color/white"
+ android:inset="10dp" />
+
diff --git a/tests/tests/graphics/res/drawable/inset_density.xml b/tests/tests/graphics/res/drawable/inset_density.xml
new file mode 100644
index 0000000..7e0823e
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/inset_density.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/inset_testimage"
+ android:insetLeft="16dp" />
diff --git a/tests/tests/graphics/res/drawable/inset_mutate.xml b/tests/tests/graphics/res/drawable/inset_mutate.xml
index ba613e9..feeeda1 100644
--- a/tests/tests/graphics/res/drawable/inset_mutate.xml
+++ b/tests/tests/graphics/res/drawable/inset_mutate.xml
@@ -16,4 +16,4 @@
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:drawable="@drawable/inset_mutate_testimage" />
+ android:drawable="@drawable/inset_testimage" />
diff --git a/tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg b/tests/tests/graphics/res/drawable/inset_testimage.jpg
similarity index 100%
rename from tests/tests/graphics/res/drawable/inset_mutate_testimage.jpg
rename to tests/tests/graphics/res/drawable/inset_testimage.jpg
Binary files differ
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_density.xml b/tests/tests/graphics/res/drawable/layer_drawable_density.xml
new file mode 100644
index 0000000..3012539
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_density.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<layer-list
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingTop="8dp"
+ android:paddingBottom="8dp"
+ android:paddingLeft="8dp"
+ android:paddingRight="8dp"
+ android:paddingMode="nest">
+ <item
+ android:left="16dp"
+ android:right="16dp"
+ android:top="16dp"
+ android:bottom="16dp"
+ android:width="32dp"
+ android:height="32dp">
+ <color
+ android:color="@android:color/black" />
+ </item>
+</layer-list>
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml
new file mode 100644
index 0000000..0a8cd98
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:left="5dp"
+ android:right="5dp"
+ android:top="5dp"
+ android:bottom="5dp"
+ android:drawable="@android:color/black" />
+</layer-list>
diff --git a/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml
new file mode 100644
index 0000000..a590f90
--- /dev/null
+++ b/tests/tests/graphics/res/drawable/layer_drawable_intrinsic_mixed.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:left="2dp"
+ android:right="2dp"
+ android:top="2dp"
+ android:bottom="2dp"
+ android:drawable="@drawable/size_48x48" />
+ <item android:left="100dp"
+ android:right="100dp"
+ android:top="100dp"
+ android:bottom="100dp"
+ android:drawable="@android:color/black" />
+</layer-list>
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
index 29770c6..2b05f99 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapFactoryTest.java
@@ -64,12 +64,10 @@
private static int HEIGHTS[] = new int[] { 960, 480, 240, 240, 480 };
// Configurations for BitmapFactory.Options
- private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565,
- Config.ARGB_4444};
+ private static Config[] COLOR_CONFIGS = new Config[] {Config.ARGB_8888, Config.RGB_565};
private static int[] COLOR_TOLS = new int[] {16, 49, 576};
- private static Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888,
- Config.ARGB_4444};
+ private static Config[] COLOR_CONFIGS_RGBA = new Config[] {Config.ARGB_8888};
private static int[] COLOR_TOLS_RGBA = new int[] {72, 124};
private static int[] RAW_COLORS = new int[] {
diff --git a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
index 3f6d896..328d9ed 100644
--- a/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/BitmapRegionDecoderTest.java
@@ -304,6 +304,83 @@
}
}
+ // The documentation for BitmapRegionDecoder guarantees that, when reusing a
+ // bitmap, "the provided Bitmap's width, height, and Bitmap.Config will not
+ // be changed". If the inBitmap is too small, decoded content will be
+ // clipped into inBitmap. Here we test that:
+ // (1) If inBitmap is specified, it is always used.
+ // (2) The width, height, and Config of inBitmap are never changed.
+ // (3) All of the pixels decoded into inBitmap exactly match the pixels
+ // of a decode where inBitmap is NULL.
+ public void testInBitmapReuse() throws IOException {
+ Options defaultOpts = new BitmapFactory.Options();
+ Options reuseOpts = new BitmapFactory.Options();
+ Rect subset = new Rect(0, 0, TILE_SIZE, TILE_SIZE);
+
+ for (int i = 0; i < NUM_TEST_IMAGES; i++) {
+ InputStream is = obtainInputStream(RES_IDS[i]);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
+ for (int j = 0; j < SAMPLESIZES.length; j++) {
+ int sampleSize = SAMPLESIZES[j];
+ defaultOpts.inSampleSize = sampleSize;
+ reuseOpts.inSampleSize = sampleSize;
+
+ // We don't need to worry about rounding here because sampleSize
+ // divides evenly into TILE_SIZE.
+ assertEquals(0, TILE_SIZE % sampleSize);
+ int scaledDim = TILE_SIZE / sampleSize;
+ int chunkSize = scaledDim / 2;
+ for (int k = 0; k < COLOR_CONFIGS.length; k++) {
+ Config config = COLOR_CONFIGS[k];
+ defaultOpts.inPreferredConfig = config;
+ reuseOpts.inPreferredConfig = config;
+
+ // For both the width and the height of inBitmap, we test three
+ // interesting cases:
+ // (1) inBitmap dimension is smaller than scaledDim. The decoded
+ // pixels that fit inside inBitmap should exactly match the
+ // corresponding decoded pixels from the same region decode,
+ // performed without an inBitmap. The pixels that do not fit
+ // inside inBitmap should be clipped.
+ // (2) inBitmap dimension matches scaledDim. After the decode,
+ // the pixels and dimensions of inBitmap should exactly match
+ // those of the result bitmap of the same region decode,
+ // performed without an inBitmap.
+ // (3) inBitmap dimension is larger than scaledDim. After the
+ // decode, inBitmap should contain decoded pixels for the
+ // entire region, exactly matching the decoded pixels
+ // produced when inBitmap is not specified. The additional
+ // pixels in inBitmap are left the same as before the decode.
+ for (int w = chunkSize; w <= 3 * chunkSize; w += chunkSize) {
+ for (int h = chunkSize; h <= 3 * chunkSize; h += chunkSize) {
+ // Decode reusing inBitmap.
+ reuseOpts.inBitmap = Bitmap.createBitmap(w, h, config);
+ Bitmap reuseResult = decoder.decodeRegion(subset, reuseOpts);
+ assertSame(reuseOpts.inBitmap, reuseResult);
+ assertEquals(reuseResult.getWidth(), w);
+ assertEquals(reuseResult.getHeight(), h);
+ assertEquals(reuseResult.getConfig(), config);
+
+ // Decode into a new bitmap.
+ Bitmap defaultResult = decoder.decodeRegion(subset, defaultOpts);
+ assertEquals(defaultResult.getWidth(), scaledDim);
+ assertEquals(defaultResult.getHeight(), scaledDim);
+
+ // Ensure that the decoded pixels of reuseResult and defaultResult
+ // are identical.
+ int cropWidth = Math.min(w, scaledDim);
+ int cropHeight = Math.min(h, scaledDim);
+ Rect crop = new Rect(0 ,0, cropWidth, cropHeight);
+ Bitmap reuseCropped = cropBitmap(reuseResult, crop);
+ Bitmap defaultCropped = cropBitmap(defaultResult, crop);
+ compareBitmaps(reuseCropped, defaultCropped, 0, true);
+ }
+ }
+ }
+ }
+ }
+ }
+
private void compareRegionByRegion(BitmapRegionDecoder decoder,
Options opts, int mseMargin, Bitmap wholeImage) {
int width = decoder.getWidth();
diff --git a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
index 701ca13..dee217b 100644
--- a/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/CanvasTest.java
@@ -348,6 +348,117 @@
verifySaveFlagsSequence(flags);
}
+ // This test exercises the saveLayer flag that preserves the clip
+ // state across the matching restore call boundary. This is a vanilla
+ // test and doesn't exercise any interaction between the clip stack
+ // and SkCanvas' deferred save/restore system.
+ public void testSaveFlags9() {
+ Rect clip0 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip0));
+
+ mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+
+ // All clip elements should be preserved after restore
+ mCanvas.clipRect(0, 0, BITMAP_WIDTH / 2, BITMAP_HEIGHT);
+ Path path = new Path();
+ path.addOval(0.25f * BITMAP_WIDTH, 0.25f * BITMAP_HEIGHT,
+ 0.75f * BITMAP_WIDTH, 0.75f * BITMAP_HEIGHT,
+ Path.Direction.CW);
+ mCanvas.clipPath(path);
+ mCanvas.clipRect(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT / 2);
+
+ Rect clip1 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip1));
+ assertTrue(clip1 != clip0);
+ assertTrue(clip0.contains(clip1));
+
+ mCanvas.restore();
+
+ Rect clip2 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip2));
+ assertEquals(clip2, clip1);
+ }
+
+ // This test exercises the saveLayer MATRIX_SAVE_FLAG flag and its
+ // interaction with the clip stack and SkCanvas deferred save/restore
+ // system.
+ public void testSaveFlags10() {
+ RectF rect1 = new RectF(0, 0, BITMAP_WIDTH / 2, BITMAP_HEIGHT);
+ RectF rect2 = new RectF(0, 0, BITMAP_WIDTH, BITMAP_HEIGHT / 2);
+ Path path = new Path();
+ path.addOval(0.25f * BITMAP_WIDTH, 0.25f * BITMAP_HEIGHT,
+ 0.75f * BITMAP_WIDTH, 0.75f * BITMAP_HEIGHT,
+ Path.Direction.CW);
+
+ Rect clip0 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip0));
+
+ // Exercise various Canvas lazy-save interactions.
+ mCanvas.save();
+ mCanvas.save();
+ mCanvas.clipRect(rect1);
+ mCanvas.clipPath(path);
+
+ Rect clip1 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip1));
+ assertTrue(clip1 != clip0);
+
+ mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+ mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+ mCanvas.clipRect(rect2);
+ mCanvas.clipPath(path);
+
+ Rect clip2 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip2));
+ assertTrue(clip2 != clip1);
+ assertTrue(clip2 != clip0);
+
+ mCanvas.save();
+ mCanvas.translate(10, 5);
+ mCanvas.save(Canvas.MATRIX_SAVE_FLAG);
+ // An uncommitted save/restore frame: exercises
+ // the partial save emulation, ensuring there
+ // are no side effects.
+ Rect clip3 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip3));
+ clip3.offset(10, 5); // adjust for local offset
+ assertEquals(clip3, clip2);
+ mCanvas.restore();
+
+ Rect clip4 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip4));
+ clip4.offset(10, 5); // adjust for local offset
+ assertEquals(clip4, clip2);
+ mCanvas.restore();
+
+ Rect clip5 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip5));
+ assertEquals(clip5, clip2);
+ mCanvas.restore();
+
+ // clip2 survives the preceding restore
+ Rect clip6 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip6));
+ assertEquals(clip6, clip2);
+ mCanvas.restore();
+
+ // clip2 also survives the preceding restore
+ Rect clip7 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip7));
+ assertEquals(clip7, clip2);
+ mCanvas.restore();
+
+ // clip1 does _not_ survive the preceding restore
+ Rect clip8 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip8));
+ assertEquals(clip8, clip0);
+ mCanvas.restore();
+
+ Rect clip9 = new Rect();
+ assertTrue(mCanvas.getClipBounds(clip9));
+ assertEquals(clip9, clip0);
+ }
+
public void testSaveLayer1() {
final Paint p = new Paint();
final RectF rF = new RectF(0, 10, 31, 0);
diff --git a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
index 5932e64..7b0277c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/TypefaceTest.java
@@ -17,6 +17,7 @@
package android.graphics.cts;
+import android.graphics.Paint;
import android.graphics.Typeface;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
@@ -180,4 +181,15 @@
fOutput.close();
return (file.getPath());
}
+
+ public void testInvalidCmapFont() {
+ Typeface typeface = Typeface.createFromAsset(getContext().getAssets(), "bombfont.ttf");
+ assertNotNull(typeface);
+ Paint p = new Paint();
+ final String testString = "abcde";
+ float widthDefaultTypeface = p.measureText(testString);
+ p.setTypeface(typeface);
+ float widthCustomTypeface = p.measureText(testString);
+ assertEquals(widthDefaultTypeface, widthCustomTypeface, 0.01f);
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
index 612c6a2..9b11cf7 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/BitmapDrawableTest.java
@@ -316,29 +316,48 @@
InputStream source = mContext.getResources().openRawResource(R.drawable.size_48x48);
bitmapDrawable = new BitmapDrawable(source);
- bitmapDrawable.setTargetDensity(mContext.getResources().getDisplayMetrics().densityDpi);
+ bitmapDrawable.setTargetDensity(bitmapDrawable.getBitmap().getDensity());
assertEquals(48, bitmapDrawable.getIntrinsicWidth());
assertEquals(48, bitmapDrawable.getIntrinsicHeight());
}
@SuppressWarnings("deprecation")
public void testSetTargetDensity() {
- BitmapDrawable bitmapDrawable = new BitmapDrawable();
+ int sourceWidth, targetWidth;
+ int sourceHeight, targetHeight;
+ int sourceDensity, targetDensity;
+ BitmapDrawable bitmapDrawable;
+ Bitmap bitmap;
- Bitmap bitmap = Bitmap.createBitmap(200, 300, Config.RGB_565);
+ sourceWidth = 200;
+ sourceHeight = 300;
+ bitmap = Bitmap.createBitmap(sourceWidth, sourceHeight, Config.RGB_565);
Canvas canvas = new Canvas(bitmap);
bitmapDrawable = new BitmapDrawable(bitmap);
- bitmapDrawable.setTargetDensity(canvas.getDensity());
- assertEquals(200, bitmapDrawable.getIntrinsicWidth());
- assertEquals(300, bitmapDrawable.getIntrinsicHeight());
+ sourceDensity = bitmap.getDensity();
+ targetDensity = canvas.getDensity();
+ bitmapDrawable.setTargetDensity(targetDensity);
+ targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceWidth, sourceDensity, targetDensity);
+ targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceHeight, sourceDensity, targetDensity);
+ assertEquals(targetWidth, bitmapDrawable.getIntrinsicWidth());
+ assertEquals(targetHeight, bitmapDrawable.getIntrinsicHeight());
- DisplayMetrics disMetrics = new DisplayMetrics();
- disMetrics = getInstrumentation().getTargetContext().getResources().getDisplayMetrics();
+ sourceWidth = 48;
+ sourceHeight = 48;
InputStream source = mContext.getResources().openRawResource(R.drawable.size_48x48);
bitmapDrawable = new BitmapDrawable(source);
- bitmapDrawable.setTargetDensity(disMetrics.densityDpi);
- assertEquals(48, bitmapDrawable.getIntrinsicWidth());
- assertEquals(48, bitmapDrawable.getIntrinsicHeight());
+ bitmap = bitmapDrawable.getBitmap();
+ sourceDensity = bitmap.getDensity();
+ targetDensity = sourceDensity * 2;
+ bitmapDrawable.setTargetDensity(targetDensity);
+ targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceWidth, sourceDensity, targetDensity);
+ targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceHeight, sourceDensity, targetDensity);
+ assertEquals(targetWidth, bitmapDrawable.getIntrinsicWidth());
+ assertEquals(targetHeight, bitmapDrawable.getIntrinsicHeight());
}
@SuppressWarnings("deprecation")
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
index a0fa634..ae28eca 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/DrawableTestUtils.java
@@ -16,15 +16,17 @@
package android.graphics.drawable.cts;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import android.util.Xml;
import java.io.IOException;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
/**
* The useful methods for graphics.drawable test.
*/
@@ -85,4 +87,41 @@
}
return attrs;
}
+
+ public static XmlResourceParser getResourceParser(Resources res, int resId)
+ throws XmlPullParserException, IOException {
+ final XmlResourceParser parser = res.getXml(resId);
+ int type;
+ while ((type = parser.next()) != XmlPullParser.START_TAG
+ && type != XmlPullParser.END_DOCUMENT) {
+ // Empty loop
+ }
+ return parser;
+ }
+
+ public static void setResourcesDensity(Resources res, int densityDpi) {
+ final Configuration config = new Configuration();
+ config.setTo(res.getConfiguration());
+ config.densityDpi = densityDpi;
+ res.updateConfiguration(config, null);
+ }
+
+ /**
+ * Implements scaling as used by the Bitmap class. Resulting values are
+ * rounded up (as distinct from resource scaling, which truncates or rounds
+ * to the nearest pixel).
+ *
+ * @param size the pixel size to scale
+ * @param sdensity the source density that corresponds to the size
+ * @param tdensity the target density
+ * @return the pixel size scaled for the target density
+ */
+ public static int scaleBitmapFromDensity(int size, int sdensity, int tdensity) {
+ if (sdensity == 0 || tdensity == 0 || sdensity == tdensity) {
+ return size;
+ }
+
+ // Scale by tdensity / sdensity, rounding up.
+ return ((size * tdensity) + (sdensity >> 1)) / sdensity;
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
index 1cecd5d..c80ae4b 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/GradientDrawableTest.java
@@ -16,6 +16,8 @@
package android.graphics.drawable.cts;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
import android.graphics.cts.R;
import org.xmlpull.v1.XmlPullParser;
@@ -320,4 +322,70 @@
assertEquals(50, d3.getIntrinsicHeight());
assertEquals(40, d3.getIntrinsicWidth());
}
+
+ public void testPreloadDensity() throws XmlPullParserException, IOException {
+ final Resources res = getContext().getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+ final Rect tempPadding = new Rect();
+
+ // Capture initial state at default density.
+ final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+ res, R.drawable.gradient_drawable_density);
+ final GradientDrawable preloadedDrawable = new GradientDrawable();
+ preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+ final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+ final int origWidth = preloadedDrawable.getIntrinsicWidth();
+ final int origHeight = preloadedDrawable.getIntrinsicHeight();
+ final Rect origPadding = new Rect();
+ preloadedDrawable.getPadding(origPadding);
+
+ // Set density to half of original. Unlike offsets, which are
+ // truncated, dimensions are rounded to the nearest pixel.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+ final GradientDrawable halfDrawable =
+ (GradientDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+ assertTrue(halfDrawable.getPadding(tempPadding));
+ assertEquals((int) (origPadding.left / 2f), tempPadding.left);
+
+ // Set density to double original.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+ final GradientDrawable doubleDrawable =
+ (GradientDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(origWidth * 2, doubleDrawable.getIntrinsicWidth());
+ assertEquals(origHeight * 2, doubleDrawable.getIntrinsicHeight());
+ assertTrue(doubleDrawable.getPadding(tempPadding));
+ assertEquals(origPadding.left * 2, tempPadding.left);
+
+ // Restore original density.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ final GradientDrawable origDrawable =
+ (GradientDrawable) preloadedConstantState.newDrawable();
+ assertEquals(origWidth, origDrawable.getIntrinsicWidth());
+ assertEquals(origHeight, origDrawable.getIntrinsicHeight());
+ assertTrue(origDrawable.getPadding(tempPadding));
+ assertEquals(origPadding, tempPadding);
+
+ // Some precision is lost when scaling the half-density
+ // drawable back up to the original density.
+ final Rect sloppyOrigPadding = new Rect();
+ sloppyOrigPadding.left = 2 * Math.round(origPadding.left / 2f);
+ sloppyOrigPadding.top = 2 * Math.round(origPadding.top / 2f);
+ sloppyOrigPadding.right = 2 * Math.round(origPadding.right / 2f);
+ sloppyOrigPadding.bottom = 2 * Math.round(origPadding.bottom / 2f);
+
+ // Ensure theme density is applied correctly.
+ final Theme t = res.newTheme();
+ halfDrawable.applyTheme(t);
+ assertEquals(2 * Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(2 * Math.round(origHeight / 2f), halfDrawable.getIntrinsicHeight());
+ assertTrue(halfDrawable.getPadding(tempPadding));
+ assertEquals(sloppyOrigPadding, tempPadding);
+ doubleDrawable.applyTheme(t);
+ assertEquals(origWidth, doubleDrawable.getIntrinsicWidth());
+ assertEquals(origHeight, doubleDrawable.getIntrinsicHeight());
+ assertTrue(doubleDrawable.getPadding(tempPadding));
+ assertEquals(origPadding, tempPadding);
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
index cc5381d..fb10db6 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/InsetDrawableTest.java
@@ -16,23 +16,25 @@
package android.graphics.drawable.cts;
-import android.graphics.cts.R;
-
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.cts.R;
import android.graphics.drawable.Drawable;
-import android.graphics.drawable.InsetDrawable;
import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.InsetDrawable;
import android.test.AndroidTestCase;
import android.util.AttributeSet;
import android.util.StateSet;
import android.util.Xml;
+import android.view.InflateException;
import java.io.IOException;
import java.util.Arrays;
@@ -57,23 +59,25 @@
try {
insetDrawable.inflate(r, parser, attrs);
- fail("There should be a XmlPullParserException thrown out.");
- } catch (XmlPullParserException e) {
+ fail("There should be an InflateException thrown out.");
+ } catch (InflateException e) {
// expected, test success
} catch (IOException e) {
fail("There should not be an IOException thrown out.");
+ } catch (XmlPullParserException e) {
+ fail("There should not be a XmlPullParserException thrown out.");
}
// input null as params
try {
insetDrawable.inflate(null, null, null);
fail("There should be a NullPointerException thrown out.");
- } catch (XmlPullParserException e) {
- fail("There should not be a XmlPullParserException thrown out.");
- } catch (IOException e) {
- fail("There should not be an IOException thrown out.");
} catch (NullPointerException e) {
// expected, test success
+ } catch (IOException e) {
+ fail("There should not be an IOException thrown out.");
+ } catch (XmlPullParserException e) {
+ fail("There should not be a XmlPullParserException thrown out.");
}
}
@@ -283,28 +287,48 @@
Drawable d = mContext.getDrawable(R.drawable.pass);
InsetDrawable insetDrawable = new InsetDrawable(d, 0);
- int expected = d.getIntrinsicWidth(); /* 31 */
+ int expected = d.getIntrinsicWidth();
assertEquals(expected, insetDrawable.getIntrinsicWidth());
d = mContext.getDrawable(R.drawable.scenery);
insetDrawable = new InsetDrawable(d, 0);
- expected = d.getIntrinsicWidth(); /* 170 */
+ expected = d.getIntrinsicWidth();
assertEquals(expected, insetDrawable.getIntrinsicWidth());
+
+ d = mContext.getDrawable(R.drawable.scenery);
+ insetDrawable = new InsetDrawable(d, 20);
+
+ expected = d.getIntrinsicWidth() + 40;
+ assertEquals(expected, insetDrawable.getIntrinsicWidth());
+
+ d = mContext.getDrawable(R.drawable.inset_color);
+ expected = -1;
+ assertEquals(expected, d.getIntrinsicWidth());
}
public void testGetIntrinsicHeight() {
Drawable d = mContext.getDrawable(R.drawable.pass);
InsetDrawable insetDrawable = new InsetDrawable(d, 0);
- int expected = d.getIntrinsicHeight(); /* 31 */
+ int expected = d.getIntrinsicHeight();
assertEquals(expected, insetDrawable.getIntrinsicHeight());
d = mContext.getDrawable(R.drawable.scenery);
insetDrawable = new InsetDrawable(d, 0);
- expected = d.getIntrinsicHeight(); /* 107 */
+ expected = d.getIntrinsicHeight();
assertEquals(expected, insetDrawable.getIntrinsicHeight());
+
+ d = mContext.getDrawable(R.drawable.scenery);
+ insetDrawable = new InsetDrawable(d, 20);
+
+ expected = d.getIntrinsicHeight() + 40;
+ assertEquals(expected, insetDrawable.getIntrinsicHeight());
+
+ d = mContext.getDrawable(R.drawable.inset_color);
+ expected = -1;
+ assertEquals(expected, d.getIntrinsicHeight());
}
public void testGetConstantState() {
@@ -333,6 +357,51 @@
assertEquals("Did not modify post-mutate() instance", 255, post.getDrawable().getAlpha());
}
+ public void testPreloadDensity() throws XmlPullParserException, IOException {
+ final Resources res = getContext().getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+
+ // Capture initial state at default density.
+ final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+ res, R.drawable.inset_density);
+ final InsetDrawable preloadedDrawable = new InsetDrawable(null, 0);
+ preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+ final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+ final int origInsetHoriz = preloadedDrawable.getIntrinsicWidth()
+ - preloadedDrawable.getDrawable().getIntrinsicWidth();
+
+ // Set density to half of original. Unlike offsets, which are
+ // truncated, dimensions are rounded to the nearest pixel.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+ final InsetDrawable halfDrawable =
+ (InsetDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(Math.round(origInsetHoriz / 2f), halfDrawable.getIntrinsicWidth()
+ - halfDrawable.getDrawable().getIntrinsicWidth());
+
+ // Set density to double original.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+ final InsetDrawable doubleDrawable =
+ (InsetDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(origInsetHoriz * 2, doubleDrawable.getIntrinsicWidth()
+ - doubleDrawable.getDrawable().getIntrinsicWidth());
+
+ // Restore original density.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ final InsetDrawable origDrawable =
+ (InsetDrawable) preloadedConstantState.newDrawable();
+ assertEquals(origInsetHoriz, origDrawable.getIntrinsicWidth()
+ - origDrawable.getDrawable().getIntrinsicWidth());
+
+ // Ensure theme density is applied correctly.
+ final Theme t = res.newTheme();
+ halfDrawable.applyTheme(t);
+ assertEquals(origInsetHoriz, halfDrawable.getIntrinsicWidth()
+ - halfDrawable.getDrawable().getIntrinsicWidth());
+ doubleDrawable.applyTheme(t);
+ assertEquals(origInsetHoriz, doubleDrawable.getIntrinsicWidth()
+ - doubleDrawable.getDrawable().getIntrinsicWidth());
+ }
+
private class MockInsetDrawable extends InsetDrawable {
public MockInsetDrawable(Drawable drawable, int inset) {
super(drawable, inset);
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
index 9ea0227..4b17587 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/LayerDrawableTest.java
@@ -16,19 +16,18 @@
package android.graphics.drawable.cts;
-import android.view.Gravity;
-import android.graphics.cts.R;
-
+import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
-import java.io.IOException;
-
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.cts.R;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
@@ -41,8 +40,12 @@
import android.test.AndroidTestCase;
import android.util.AttributeSet;
import android.util.StateSet;
+import android.util.Xml;
+import android.view.Gravity;
import android.view.View;
+import java.io.IOException;
+
public class LayerDrawableTest extends AndroidTestCase {
@SuppressWarnings("deprecation")
@@ -258,7 +261,12 @@
@SuppressWarnings("deprecation")
public void testSetLayerInset() {
- Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ MockDrawable firstLayer = new MockDrawable();
+ firstLayer.setIntrinsicSize(10, 10);
+ MockDrawable secondLayer = new MockDrawable();
+ secondLayer.setIntrinsicSize(-1, -1);
+
+ Drawable[] array = new Drawable[] { firstLayer, secondLayer };
LayerDrawable layerDrawable = new LayerDrawable(array);
// set inset for layer 0
@@ -272,15 +280,12 @@
assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
layerDrawable.getIntrinsicHeight());
- // set bigger inset for layer 1
- left += 10;
- top += 10;
- right += 10;
- bottom += 10;
- layerDrawable.setLayerInset(1, left, top, right, bottom);
- assertEquals(layerDrawable.getDrawable(1).getIntrinsicWidth() + left + right,
+ // The drawable at index 0 has no intrinsic width or height, so it
+ // won't be counted for the overall intrinsic width or height.
+ layerDrawable.setLayerInset(1, 10, 10, 10, 10);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + left + right,
layerDrawable.getIntrinsicWidth());
- assertEquals(layerDrawable.getDrawable(1).getIntrinsicHeight() + top + bottom,
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
layerDrawable.getIntrinsicHeight());
try {
@@ -735,11 +740,13 @@
}
public void testGetIntrinsicWidth() {
- MockDrawable mockDrawable1 = new MockDrawable();
- MockDrawable mockDrawable2 = new MockDrawable();
- Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
+ MockDrawable largeMockDrawable = new MockDrawable();
+ largeMockDrawable.setIntrinsicSize(10, 10);
+ MockDrawable smallMockDrawable = new MockDrawable();
+ smallMockDrawable.setIntrinsicSize(1, 1);
+ Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
LayerDrawable layerDrawable = new LayerDrawable(array);
- assertEquals(mockDrawable1.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
+ assertEquals(largeMockDrawable.getIntrinsicWidth(), layerDrawable.getIntrinsicWidth());
Rect inset1 = new Rect(1, 2, 3, 4);
Rect inset2 = new Rect(2, 4, 6, 7);
@@ -747,26 +754,28 @@
Rect padding2 = new Rect(21, 32, 43, 54);
layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
- mockDrawable1.setPadding(padding1);
- mockDrawable2.setPadding(padding2);
+ largeMockDrawable.setPadding(padding1);
+ smallMockDrawable.setPadding(padding2);
layerDrawable.getPadding(new Rect());
- assertEquals(mockDrawable2.getIntrinsicWidth() + inset2.left
+ assertEquals(smallMockDrawable.getIntrinsicWidth() + inset2.left
+ inset2.right + padding1.left + padding1.right,
layerDrawable.getIntrinsicWidth());
inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
- assertEquals(mockDrawable1.getIntrinsicWidth() + inset1.left + inset1.right,
+ assertEquals(largeMockDrawable.getIntrinsicWidth() + inset1.left + inset1.right,
layerDrawable.getIntrinsicWidth());
}
public void testGetIntrinsicHeight() {
- MockDrawable mockDrawable1 = new MockDrawable();
- MockDrawable mockDrawable2 = new MockDrawable();
- Drawable[] array = new Drawable[] { mockDrawable1, mockDrawable2 };
+ MockDrawable largeMockDrawable = new MockDrawable();
+ largeMockDrawable.setIntrinsicSize(10, 10);
+ MockDrawable smallMockDrawable = new MockDrawable();
+ smallMockDrawable.setIntrinsicSize(1, 1);
+ Drawable[] array = new Drawable[] { largeMockDrawable, smallMockDrawable };
LayerDrawable layerDrawable = new LayerDrawable(array);
- assertEquals(mockDrawable1.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
+ assertEquals(largeMockDrawable.getIntrinsicHeight(), layerDrawable.getIntrinsicHeight());
Rect inset1 = new Rect(1, 2, 3, 4);
Rect inset2 = new Rect(2, 4, 6, 7);
@@ -774,17 +783,17 @@
Rect padding2 = new Rect(21, 32, 43, 54);
layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
layerDrawable.setLayerInset(1, inset2.left, inset2.top, inset2.right, inset2.bottom);
- mockDrawable1.setPadding(padding1);
- mockDrawable2.setPadding(padding2);
+ largeMockDrawable.setPadding(padding1);
+ smallMockDrawable.setPadding(padding2);
layerDrawable.getPadding(new Rect());
- assertEquals(mockDrawable2.getIntrinsicHeight() + inset2.top
+ assertEquals(smallMockDrawable.getIntrinsicHeight() + inset2.top
+ inset2.bottom + padding1.top + padding1.bottom,
layerDrawable.getIntrinsicHeight());
inset1 = new Rect(inset2.left + padding1.left + 1, inset2.top + padding1.top + 1,
inset2.right + padding1.right + 1, inset2.bottom + padding1.bottom + 1);
layerDrawable.setLayerInset(0, inset1.left, inset1.top, inset1.right, inset1.bottom);
- assertEquals(mockDrawable1.getIntrinsicHeight() + inset1.top + inset1.bottom,
+ assertEquals(largeMockDrawable.getIntrinsicHeight() + inset1.top + inset1.bottom,
layerDrawable.getIntrinsicHeight());
}
@@ -1071,10 +1080,14 @@
@SuppressWarnings("deprecation")
public void testSetLayerInsetRelative() {
- Drawable[] array = new Drawable[] { new BitmapDrawable(), new ColorDrawable(Color.BLUE) };
+ MockDrawable firstLayer = new MockDrawable();
+ firstLayer.setIntrinsicSize(10, 10);
+ MockDrawable secondLayer = new MockDrawable();
+ secondLayer.setIntrinsicSize(-1, -1);
+
+ Drawable[] array = new Drawable[] { firstLayer, secondLayer };
LayerDrawable layerDrawable = new LayerDrawable(array);
- // set inset for layer 0
int start = 10;
int top = 20;
int end = 30;
@@ -1084,25 +1097,21 @@
layerDrawable.getIntrinsicWidth());
assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
layerDrawable.getIntrinsicHeight());
- assertEquals(10, layerDrawable.getLayerInsetStart(0));
- assertEquals(20, layerDrawable.getLayerInsetTop(0));
- assertEquals(30, layerDrawable.getLayerInsetEnd(0));
- assertEquals(40, layerDrawable.getLayerInsetBottom(0));
+ assertEquals(start, layerDrawable.getLayerInsetStart(0));
+ assertEquals(top, layerDrawable.getLayerInsetTop(0));
+ assertEquals(end, layerDrawable.getLayerInsetEnd(0));
+ assertEquals(bottom, layerDrawable.getLayerInsetBottom(0));
assertEquals(0, layerDrawable.getLayerInsetLeft(0));
assertEquals(0, layerDrawable.getLayerInsetRight(0));
- // set bigger inset for layer 1
- start += 10;
- top += 10;
- end += 10;
- bottom += 10;
- layerDrawable.setLayerInsetRelative(1, start, top, end, bottom);
- assertEquals(layerDrawable.getDrawable(1).getIntrinsicWidth() + start + end,
+ // The drawable at index 1 has no intrinsic width or height, so it
+ // won't be counted for the overall intrinsic width or height.
+ layerDrawable.setLayerInsetRelative(1, 10, 10, 10, 10);
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicWidth() + start + end,
layerDrawable.getIntrinsicWidth());
- assertEquals(layerDrawable.getDrawable(1).getIntrinsicHeight() + top + bottom,
+ assertEquals(layerDrawable.getDrawable(0).getIntrinsicHeight() + top + bottom,
layerDrawable.getIntrinsicHeight());
-
try {
layerDrawable.setLayerInsetRelative(-1, start, top, end, bottom);
fail("Should throw IndexOutOfBoundsException");
@@ -1405,7 +1414,29 @@
}
}
+ public void testChildIntrinsicSize() {
+ LayerDrawable dr;
+ // Ensure that a child with no intrinsic size correctly reports bounds.
+ dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic);
+ assertEquals(-1, dr.getIntrinsicWidth());
+ assertEquals(-1, dr.getIntrinsicHeight());
+
+ // Check when creating the drawble from code.
+ dr = new LayerDrawable(new Drawable[] { new ColorDrawable(Color.RED) });
+ dr.setLayerInset(0, 10, 10, 10, 10);
+ assertEquals(-1, dr.getIntrinsicWidth());
+ assertEquals(-1, dr.getIntrinsicHeight());
+
+ // Ensure mixed children report bounds correctly as well.
+ dr = (LayerDrawable) getContext().getDrawable(R.drawable.layer_drawable_intrinsic_mixed);
+ int width = dr.getLayerInsetLeft(0) + dr.getLayerInsetRight(0)
+ + dr.getDrawable(0).getIntrinsicWidth();
+ int height = dr.getLayerInsetTop(0) + dr.getLayerInsetBottom(0)
+ + dr.getDrawable(0).getIntrinsicHeight();
+ assertEquals(width, dr.getIntrinsicWidth());
+ assertEquals(height, dr.getIntrinsicHeight());
+ }
private static class MockDrawable extends Drawable {
private boolean mCalledSetDither = false;
@@ -1423,6 +1454,9 @@
private int mOpacity = PixelFormat.OPAQUE;
+ private int mIntrinsicWidth = -1;
+ private int mIntrinsicHeight = -1;
+
private boolean mDither = false;
Rect mPadding = null;
@@ -1469,6 +1503,21 @@
mCalledSetDither = true;
}
+ public void setIntrinsicSize(int width, int height) {
+ mIntrinsicWidth = width;
+ mIntrinsicHeight = height;
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mIntrinsicWidth;
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mIntrinsicHeight;
+ }
+
public boolean hasCalledSetDither() {
return mCalledSetDither;
}
@@ -1610,4 +1659,103 @@
assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
assertEquals(50, ((BitmapDrawable) d3.getDrawable(0)).getPaint().getAlpha());
}
+
+ public void testPreloadDensity() throws XmlPullParserException, IOException {
+ final Resources res = getContext().getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+
+ // Capture initial state at default density.
+ final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+ res, R.drawable.layer_drawable_density);
+ final LayerDrawable preloadedDrawable = new LayerDrawable(new Drawable[0]);
+ preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+ final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+ final int initialWidth = preloadedDrawable.getIntrinsicWidth();
+ final int initialLeftPadding = preloadedDrawable.getLeftPadding();
+ final int initialRightPadding = preloadedDrawable.getRightPadding();
+ final int initialBottomPadding = preloadedDrawable.getBottomPadding();
+ final int initialTopPadding = preloadedDrawable.getTopPadding();
+ final int initialLayerInsetLeft = preloadedDrawable.getLayerInsetLeft(0);
+ final int initialLayerInsetRight = preloadedDrawable.getLayerInsetRight(0);
+ final int initialLayerInsetTop = preloadedDrawable.getLayerInsetTop(0);
+ final int initialLayerInsetBottom = preloadedDrawable.getLayerInsetBottom(0);
+ final int initialLayerWidth = preloadedDrawable.getLayerWidth(0);
+ final int initialLayerHeight = preloadedDrawable.getLayerHeight(0);
+
+ // Set density to half of original. Unlike offsets, which are
+ // truncated, dimensions are rounded to the nearest pixel.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+ final LayerDrawable halfDrawable =
+ (LayerDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(Math.round(initialWidth / 2f), halfDrawable.getIntrinsicWidth());
+ assertEquals(Math.round(initialLeftPadding / 2f), halfDrawable.getLeftPadding());
+ assertEquals(Math.round(initialRightPadding / 2f), halfDrawable.getRightPadding());
+ assertEquals(Math.round(initialBottomPadding / 2f), halfDrawable.getBottomPadding());
+ assertEquals(Math.round(initialTopPadding / 2f), halfDrawable.getTopPadding());
+ assertEquals(Math.round(initialLayerInsetLeft / 2f),halfDrawable.getLayerInsetLeft(0));
+ assertEquals(Math.round(initialLayerInsetRight / 2f), halfDrawable.getLayerInsetRight(0));
+ assertEquals(Math.round(initialLayerInsetTop / 2f), halfDrawable.getLayerInsetTop(0));
+ assertEquals(Math.round(initialLayerInsetBottom / 2f), halfDrawable.getLayerInsetBottom(0));
+ assertEquals(Math.round(initialLayerWidth / 2f), halfDrawable.getLayerWidth(0));
+ assertEquals(Math.round(initialLayerHeight / 2f), halfDrawable.getLayerHeight(0));
+
+ // Set density to double original.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+ final LayerDrawable doubleDrawable =
+ (LayerDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(initialWidth * 2, doubleDrawable.getIntrinsicWidth());
+ assertEquals(initialLeftPadding * 2, doubleDrawable.getLeftPadding());
+ assertEquals(initialRightPadding * 2, doubleDrawable.getRightPadding());
+ assertEquals(initialBottomPadding * 2, doubleDrawable.getBottomPadding());
+ assertEquals(initialTopPadding * 2, doubleDrawable.getTopPadding());
+ assertEquals(initialLayerInsetLeft * 2, doubleDrawable.getLayerInsetLeft(0));
+ assertEquals(initialLayerInsetRight * 2, doubleDrawable.getLayerInsetRight(0));
+ assertEquals(initialLayerInsetTop * 2, doubleDrawable.getLayerInsetTop(0));
+ assertEquals(initialLayerInsetBottom * 2, doubleDrawable.getLayerInsetBottom(0));
+ assertEquals(initialLayerWidth * 2, doubleDrawable.getLayerWidth(0));
+ assertEquals(initialLayerHeight * 2, doubleDrawable.getLayerHeight(0));
+
+ // Restore original configuration and metrics.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ final LayerDrawable origDrawable =
+ (LayerDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(initialWidth, origDrawable.getIntrinsicWidth());
+ assertEquals(initialLeftPadding, origDrawable.getLeftPadding());
+ assertEquals(initialRightPadding, origDrawable.getRightPadding());
+ assertEquals(initialBottomPadding, origDrawable.getBottomPadding());
+ assertEquals(initialTopPadding, origDrawable.getTopPadding());
+ assertEquals(initialLayerInsetLeft, origDrawable.getLayerInsetLeft(0));
+ assertEquals(initialLayerInsetRight, origDrawable.getLayerInsetRight(0));
+ assertEquals(initialLayerInsetTop, origDrawable.getLayerInsetTop(0));
+ assertEquals(initialLayerInsetBottom, origDrawable.getLayerInsetBottom(0));
+ assertEquals(initialLayerWidth, origDrawable.getLayerWidth(0));
+ assertEquals(initialLayerHeight, origDrawable.getLayerHeight(0));
+
+ // Ensure theme density is applied correctly.
+ final Theme t = res.newTheme();
+ halfDrawable.applyTheme(t);
+ assertEquals(initialWidth, halfDrawable.getIntrinsicWidth());
+ assertEquals(initialLeftPadding, halfDrawable.getLeftPadding());
+ assertEquals(initialRightPadding, halfDrawable.getRightPadding());
+ assertEquals(initialBottomPadding, halfDrawable.getBottomPadding());
+ assertEquals(initialTopPadding, halfDrawable.getTopPadding());
+ assertEquals(initialLayerInsetLeft, halfDrawable.getLayerInsetLeft(0));
+ assertEquals(initialLayerInsetRight, halfDrawable.getLayerInsetRight(0));
+ assertEquals(initialLayerInsetTop, halfDrawable.getLayerInsetTop(0));
+ assertEquals(initialLayerInsetBottom, halfDrawable.getLayerInsetBottom(0));
+ assertEquals(initialLayerWidth, halfDrawable.getLayerWidth(0));
+ assertEquals(initialLayerHeight, halfDrawable.getLayerHeight(0));
+ doubleDrawable.applyTheme(t);
+ assertEquals(initialWidth, doubleDrawable.getIntrinsicWidth());
+ assertEquals(initialLeftPadding, doubleDrawable.getLeftPadding());
+ assertEquals(initialRightPadding, doubleDrawable.getRightPadding());
+ assertEquals(initialBottomPadding, doubleDrawable.getBottomPadding());
+ assertEquals(initialTopPadding, doubleDrawable.getTopPadding());
+ assertEquals(initialLayerInsetLeft, doubleDrawable.getLayerInsetLeft(0));
+ assertEquals(initialLayerInsetRight, doubleDrawable.getLayerInsetRight(0));
+ assertEquals(initialLayerInsetTop, doubleDrawable.getLayerInsetTop(0));
+ assertEquals(initialLayerInsetBottom, doubleDrawable.getLayerInsetBottom(0));
+ assertEquals(initialLayerWidth, doubleDrawable.getLayerWidth(0));
+ assertEquals(initialLayerHeight, doubleDrawable.getLayerHeight(0));
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
index e7ab091..ba54b0c 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/NinePatchDrawableTest.java
@@ -311,15 +311,23 @@
}
public void testInflate() throws XmlPullParserException, IOException {
- final int width = 80;
- final int height = 120;
- final int[] COLOR = new int[width * height];
- Bitmap bitmap = Bitmap.createBitmap(COLOR, width, height, Bitmap.Config.RGB_565);
- NinePatchDrawable ninePatchDrawable =
- new NinePatchDrawable(mResources, bitmap, new byte[1000], null, "TESTNAME");
+ int sourceWidth = 80;
+ int sourceHeight = 120;
+ int[] colors = new int[sourceWidth * sourceHeight];
+ Bitmap bitmap = Bitmap.createBitmap(
+ colors, sourceWidth, sourceHeight, Bitmap.Config.RGB_565);
+ NinePatchDrawable ninePatchDrawable = new NinePatchDrawable(
+ mResources, bitmap, new byte[1000], null, "TESTNAME");
- assertEquals(height, ninePatchDrawable.getIntrinsicHeight());
- assertEquals(width, ninePatchDrawable.getIntrinsicWidth());
+ int sourceDensity = bitmap.getDensity();
+ int targetDensity = mResources.getDisplayMetrics().densityDpi;
+ int targetWidth = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceWidth, sourceDensity, targetDensity);
+ int targetHeight = DrawableTestUtils.scaleBitmapFromDensity(
+ sourceHeight, sourceDensity, targetDensity);
+ assertEquals(targetWidth, ninePatchDrawable.getIntrinsicWidth());
+ assertEquals(targetHeight, ninePatchDrawable.getIntrinsicHeight());
+
XmlResourceParser parser = mResources.getXml(R.drawable.ninepatchdrawable);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
@@ -329,8 +337,8 @@
ninePatchDrawable.inflate(mResources, parser, attrs);
assertTrue(ninePatchDrawable.getPaint().isDither());
- assertTrue(height != ninePatchDrawable.getIntrinsicHeight());
- assertTrue(width != ninePatchDrawable.getIntrinsicWidth());
+ assertTrue(sourceHeight != ninePatchDrawable.getIntrinsicHeight());
+ assertTrue(sourceWidth != ninePatchDrawable.getIntrinsicWidth());
}
public void testMutate() {
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
index 2949e9e..ab4fc0a 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/RippleDrawableTest.java
@@ -16,12 +16,20 @@
package android.graphics.drawable.cts;
-import android.graphics.cts.R;
+import org.xmlpull.v1.XmlPullParserException;
import android.content.res.ColorStateList;
-import android.graphics.drawable.RippleDrawable;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.XmlResourceParser;
import android.graphics.Color;
+import android.graphics.cts.R;
+import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.RippleDrawable;
import android.test.AndroidTestCase;
+import android.util.Xml;
+
+import java.io.IOException;
public class RippleDrawableTest extends AndroidTestCase {
public void testConstructor() {
@@ -41,4 +49,44 @@
(RippleDrawable) getContext().getDrawable(R.drawable.rippledrawable_radius);
assertEquals(10, drawable.getRadius());
}
+
+ public void testPreloadDensity() throws XmlPullParserException, IOException {
+ final Resources res = getContext().getResources();
+ final int densityDpi = res.getConfiguration().densityDpi;
+
+ // Capture initial state at default density.
+ final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+ res, R.drawable.rippledrawable_radius);
+ final RippleDrawable preloadedDrawable = new RippleDrawable(
+ ColorStateList.valueOf(Color.BLACK), null, null);
+ preloadedDrawable.inflate(res, parser, Xml.asAttributeSet(parser));
+ final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
+ final int initialRadius = preloadedDrawable.getRadius();
+
+ // Set density to half of original. Unlike offsets, which are
+ // truncated, dimensions are rounded to the nearest pixel.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
+ final RippleDrawable halfDrawable =
+ (RippleDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(Math.round(initialRadius / 2f), halfDrawable.getRadius());
+
+ // Set density to double original.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
+ final RippleDrawable doubleDrawable =
+ (RippleDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(initialRadius * 2, doubleDrawable.getRadius());
+
+ // Restore original density.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
+ final RippleDrawable origDrawable =
+ (RippleDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(initialRadius, origDrawable.getRadius());
+
+ // Ensure theme density is applied correctly.
+ final Theme t = res.newTheme();
+ halfDrawable.applyTheme(t);
+ assertEquals(initialRadius, halfDrawable.getRadius());
+ doubleDrawable.applyTheme(t);
+ assertEquals(initialRadius, doubleDrawable.getRadius());
+ }
}
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
index 81b5ee7..e1f37b3 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ScaleDrawableTest.java
@@ -435,8 +435,7 @@
XmlResourceParser parser = res.getXml(R.xml.scaledrawable);
AttributeSet attrs = DrawableTestUtils.getAttributeSet(parser, "scale_allattrs");
scaleDrawable.inflate(res, parser, attrs);
- int bitmapSize = (int) Math.ceil(48.0 *
- res.getDisplayMetrics().densityDpi / DisplayMetrics.DENSITY_DEFAULT);
+ final int bitmapSize = Math.round(48f * res.getDisplayMetrics().density);
assertEquals(bitmapSize, scaleDrawable.getIntrinsicWidth());
assertEquals(bitmapSize, scaleDrawable.getIntrinsicHeight());
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
index 6598601..8944d63 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/VectorDrawableTest.java
@@ -16,7 +16,9 @@
package android.graphics.drawable.cts;
-import android.content.res.Configuration;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.XmlResourceParser;
@@ -26,19 +28,14 @@
import android.graphics.Color;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
-import android.graphics.drawable.VectorDrawable;
+import android.graphics.cts.R;
import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.VectorDrawable;
import android.test.AndroidTestCase;
import android.util.AttributeSet;
-import android.util.DisplayMetrics;
import android.util.Log;
import android.util.Xml;
-import android.graphics.cts.R;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
@@ -369,67 +366,41 @@
}
public void testPreloadDensity() throws XmlPullParserException, IOException {
- final Configuration origConfig = new Configuration();
- origConfig.setTo(mResources.getConfiguration());
- final DisplayMetrics origMetrics = new DisplayMetrics();
- origMetrics.setTo(mResources.getDisplayMetrics());
+ final Resources res = mResources;
+ final int densityDpi = res.getConfiguration().densityDpi;
- final Configuration halfConfig = new Configuration();
- halfConfig.setTo(origConfig);
- final DisplayMetrics halfMetrics = new DisplayMetrics();
- halfMetrics.setTo(origMetrics);
- halfConfig.densityDpi /= 2;
- halfMetrics.densityDpi /= 2;
- halfMetrics.density *= 2;
-
- final Configuration doubleConfig = new Configuration();
- doubleConfig.setTo(origConfig);
- final DisplayMetrics doubleMetrics = new DisplayMetrics();
- doubleMetrics.setTo(origMetrics);
- doubleConfig.densityDpi *= 2;
- doubleMetrics.densityDpi *= 2;
- doubleMetrics.density /= 2;
-
- final XmlResourceParser parser = getResourceParser(R.drawable.vector_density);
+ // Capture initial state at default density.
+ final XmlResourceParser parser = DrawableTestUtils.getResourceParser(
+ res, R.drawable.vector_density);
final VectorDrawable preloadedDrawable = new VectorDrawable();
preloadedDrawable.inflate(mResources, parser, Xml.asAttributeSet(parser));
final ConstantState preloadedConstantState = preloadedDrawable.getConstantState();
final int origWidth = preloadedDrawable.getIntrinsicWidth();
- // Set density to half of original.
- mResources.updateConfiguration(halfConfig, halfMetrics);
+ // Set density to half of original. Unlike offsets, which are
+ // truncated, dimensions are rounded to the nearest pixel.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi / 2);
final VectorDrawable halfDrawable =
- (VectorDrawable) preloadedConstantState.newDrawable(mResources);
- assertEquals(origWidth / 2, halfDrawable.getIntrinsicWidth());
+ (VectorDrawable) preloadedConstantState.newDrawable(res);
+ assertEquals(Math.round(origWidth / 2f), halfDrawable.getIntrinsicWidth());
// Set density to double original.
- mResources.updateConfiguration(doubleConfig, doubleMetrics);
+ DrawableTestUtils.setResourcesDensity(res, densityDpi * 2);
final VectorDrawable doubleDrawable =
- (VectorDrawable) preloadedConstantState.newDrawable(mResources);
+ (VectorDrawable) preloadedConstantState.newDrawable(res);
assertEquals(origWidth * 2, doubleDrawable.getIntrinsicWidth());
- // Restore original configuration and metrics.
- mResources.updateConfiguration(origConfig, origMetrics);
+ // Restore original density.
+ DrawableTestUtils.setResourcesDensity(res, densityDpi);
final VectorDrawable origDrawable =
(VectorDrawable) preloadedConstantState.newDrawable();
assertEquals(origWidth, origDrawable.getIntrinsicWidth());
// Ensure theme density is applied correctly.
- final Theme t = mResources.newTheme();
+ final Theme t = res.newTheme();
halfDrawable.applyTheme(t);
assertEquals(origWidth, halfDrawable.getIntrinsicWidth());
doubleDrawable.applyTheme(t);
assertEquals(origWidth, doubleDrawable.getIntrinsicWidth());
}
-
- private XmlResourceParser getResourceParser(int resId)
- throws XmlPullParserException, IOException {
- final XmlResourceParser parser = getContext().getResources().getXml(resId);
- int type;
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- // Empty loop
- }
- return parser;
- }
}
diff --git a/tests/tests/hardware/Android.mk b/tests/tests/hardware/Android.mk
index 950d61c..2f8d6ef 100644
--- a/tests/tests/hardware/Android.mk
+++ b/tests/tests/hardware/Android.mk
@@ -22,6 +22,11 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util
LOCAL_SDK_VERSION := current
@@ -45,6 +50,11 @@
LOCAL_MODULE_TAGS := tests
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil compatibility-device-util ctstestrunner mockito-target android-ex-camera2
LOCAL_SRC_FILES := $(call all-java-files-under, src) $(call all-renderscript-files-under, src)
diff --git a/tests/tests/hardware/AndroidTest.xml b/tests/tests/hardware/AndroidTest.xml
new file mode 100644
index 0000000..a970b95
--- /dev/null
+++ b/tests/tests/hardware/AndroidTest.xml
@@ -0,0 +1,31 @@
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Hardware test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsHardwareTestCases.apk" />
+ </target_preparer>
+ <!-- Put SensorService in restricted mode so that only CTS tests will be able to get access to
+ sensors -->
+ <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+ <option name="run-command" value="dumpsys sensorservice restrict .cts." />
+ <option name="teardown-command" value="dumpsys sensorservice enable" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.cts.hardware" />
+ </test>
+
+</configuration>
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
index 4c6362a..328b5cd 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingFifoTest.java
@@ -114,7 +114,7 @@
sensor,
false,
sensor.getMinDelay(),
- Integer.MAX_VALUE);
+ Integer.MAX_VALUE /*maxReportLatencyUs*/);
TestSensorOperation op = TestSensorOperation.createOperation(environment,
sensor.getFifoReservedEventCount() * 2);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
index 7f7d4eb..4d4f3d3 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorBatchingTests.java
@@ -22,6 +22,7 @@
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.sensoroperations.TestSensorOperation;
+import android.hardware.cts.helpers.sensorverification.EventBasicVerification;
import android.hardware.cts.helpers.sensorverification.ISensorVerification;
import java.util.concurrent.TimeUnit;
@@ -44,7 +45,7 @@
public class SensorBatchingTests extends SensorTestCase {
private static final String TAG = "SensorBatchingTests";
- private static final int BATCHING_10S = 10;
+ private static final int BATCHING_PERIOD = 10; // sec
private static final int RATE_50HZ = 20000;
private static final int RATE_FASTEST = SensorManager.SENSOR_DELAY_FASTEST;
@@ -52,202 +53,202 @@
* An arbitrary 'padding' time slot to wait for events after batching latency expires.
* This allows for the test to wait for event arrivals after batching was expected.
*/
- private static final int BATCHING_PADDING_TIME_S = 2;
+ private static final int BATCHING_PADDING_TIME_S = (int) Math.ceil(BATCHING_PERIOD * 0.1f + 2);
public void testAccelerometer_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_FASTEST, BATCHING_PERIOD);
}
public void testAccelerometer_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_50HZ, BATCHING_PERIOD);
}
public void testAccelerometer_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_FASTEST, BATCHING_PERIOD);
}
public void testAccelerometer_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ACCELEROMETER, RATE_50HZ, BATCHING_PERIOD);
}
public void testMagneticField_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_FASTEST, BATCHING_PERIOD);
}
public void testMagneticField_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_50HZ, BATCHING_PERIOD);
}
public void testMagneticField_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_FASTEST, BATCHING_PERIOD);
}
public void testMagneticField_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD, RATE_50HZ, BATCHING_PERIOD);
}
@SuppressWarnings("deprecation")
public void testOrientation_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ORIENTATION, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ORIENTATION, RATE_FASTEST, BATCHING_PERIOD);
}
@SuppressWarnings("deprecation")
public void testOrientation_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ORIENTATION, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ORIENTATION, RATE_50HZ, BATCHING_PERIOD);
}
@SuppressWarnings("deprecation")
public void testOrientation_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ORIENTATION, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ORIENTATION, RATE_FASTEST, BATCHING_PERIOD);
}
@SuppressWarnings("deprecation")
public void testOrientation_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ORIENTATION, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ORIENTATION, RATE_50HZ, BATCHING_PERIOD);
}
public void testGyroscope_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GYROSCOPE, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GYROSCOPE, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGyroscope_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GYROSCOPE, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GYROSCOPE, RATE_50HZ, BATCHING_PERIOD);
}
public void testGyroscope_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GYROSCOPE, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GYROSCOPE, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_PERIOD);
}
public void testGyroscope_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GYROSCOPE, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GYROSCOPE, RATE_50HZ, BATCHING_PERIOD);
}
public void testPressure_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_PRESSURE, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_PRESSURE, RATE_FASTEST, BATCHING_PERIOD);
}
public void testPressure_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_PRESSURE, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_PRESSURE, RATE_50HZ, BATCHING_PERIOD);
}
public void testPressure_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_PRESSURE, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_PRESSURE, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_PERIOD);
}
public void testPressure_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_PRESSURE, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_PRESSURE, RATE_50HZ, BATCHING_PERIOD);
}
public void testGravity_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GRAVITY, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GRAVITY, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGravity_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GRAVITY, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GRAVITY, RATE_50HZ, BATCHING_PERIOD);
}
public void testGravity_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GRAVITY, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GRAVITY, SensorManager.SENSOR_DELAY_FASTEST, BATCHING_PERIOD);
}
public void testGravity_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GRAVITY, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GRAVITY, RATE_50HZ, BATCHING_PERIOD);
}
public void testRotationVector_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testRotationVector_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
public void testRotationVector_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testRotationVector_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
public void testMagneticFieldUncalibrated_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_FASTEST, BATCHING_PERIOD);
}
public void testMagneticFieldUncalibrated_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_50HZ, BATCHING_PERIOD);
}
public void testMagneticFieldUncalibrated_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_FASTEST, BATCHING_PERIOD);
}
public void testMagneticFieldUncalibrated_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_MAGNETIC_FIELD_UNCALIBRATED, RATE_50HZ, BATCHING_PERIOD);
}
public void testGameRotationVector_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGameRotationVector_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
public void testGameRotationVector_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGameRotationVector_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GAME_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
public void testGyroscopeUncalibrated_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGyroscopeUncalibrated_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_50HZ, BATCHING_PERIOD);
}
public void testGyroscopeUncalibrated_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGyroscopeUncalibrated_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GYROSCOPE_UNCALIBRATED, RATE_50HZ, BATCHING_PERIOD);
}
public void testLinearAcceleration_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_FASTEST, BATCHING_PERIOD);
}
public void testLinearAcceleration_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_50HZ, BATCHING_PERIOD);
}
public void testLinearAcceleration_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_FASTEST, BATCHING_PERIOD);
}
public void testLinearAcceleration_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_LINEAR_ACCELERATION, RATE_50HZ, BATCHING_PERIOD);
}
public void testGeomagneticRotationVector_fastest_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGeomagneticRotationVector_50hz_batching() throws Throwable {
- runBatchingSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runBatchingSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
public void testGeomagneticRotationVector_fastest_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_FASTEST, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_FASTEST, BATCHING_PERIOD);
}
public void testGeomagneticRotationVector_50hz_flush() throws Throwable {
- runFlushSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_50HZ, BATCHING_10S);
+ runFlushSensorTest(Sensor.TYPE_GEOMAGNETIC_ROTATION_VECTOR, RATE_50HZ, BATCHING_PERIOD);
}
private void runBatchingSensorTest(int sensorType, int rateUs, int maxBatchReportLatencySec)
@@ -264,6 +265,12 @@
TestSensorOperation operation =
TestSensorOperation.createOperation(environment, testDurationSec, TimeUnit.SECONDS);
+ operation.addVerification(
+ EventBasicVerification.getDefault(
+ environment, TimeUnit.SECONDS.toMicros(testDurationSec)
+ )
+ );
+
executeTest(environment, operation, false /* flushExpected */);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index cffafdc..2bbf053 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -168,8 +168,8 @@
}
sensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ORIENTATION);
- // orientation sensor is required if the device can physically implement it
- if (hasCompass && hasAccelerometer) {
+ // Note: orientation sensor is deprecated.
+ if (sensor != null) {
assertEquals(Sensor.TYPE_ORIENTATION, sensor.getType());
assertSensorValues(sensor);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
index 413639a..ad9b0cd 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -50,6 +50,8 @@
"event_time_synchronization_count";
public static final String EVENT_TIME_SYNCHRONIZATION_POSITIONS_KEY =
"event_time_synchronization_positions";
+ public static final String EVENT_COUNT_KEY = "event_count";
+ public static final String WRONG_SENSOR_KEY = "wrong_sensor_observed";
public static final String FREQUENCY_KEY = "frequency";
public static final String JITTER_95_PERCENTILE_PERCENT_KEY = "jitter_95_percentile_percent";
public static final String MEAN_KEY = "mean";
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 11fdc93..67dca68 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -31,6 +31,7 @@
import android.hardware.cts.helpers.TestSensorManager;
import android.hardware.cts.helpers.SuspendStateMonitor;
import android.hardware.cts.helpers.reporting.ISensorTestNode;
+import android.hardware.cts.helpers.sensorverification.EventBasicVerification;
import android.hardware.cts.helpers.sensorverification.EventGapVerification;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
@@ -145,9 +146,9 @@
for (ISensorVerification verification : mVerifications) {
failed |= evaluateResults(collectedEvents, verification, sb);
}
+
if (failed) {
trySaveCollectedEvents(parent, listener);
-
String msg = SensorCtsHelper
.formatAssertionMessage("VerifySensorOperation", mEnvironment, sb.toString());
getStats().addValue(SensorStats.ERROR, msg);
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
new file mode 100644
index 0000000..c27cba1
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerification.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.cts.helpers.sensorverification;
+
+import junit.framework.Assert;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.os.SystemClock;
+
+import java.util.concurrent.TimeUnit;
+
+/**
+ * A {@link ISensorVerification} which verifies if the collected sensor events have any obvious
+ * problems, such as no sample, wrong sensor type, etc.
+ */
+public class EventBasicVerification extends AbstractSensorVerification {
+
+ public static final String PASSED_KEY = "event_basic_passed";
+ private static final long ALLOWED_SENSOR_DELIVERING_DELAY_US =
+ TimeUnit.MILLISECONDS.toMicros(1000);
+
+ private final long mExpectedMinNumEvent;
+ private final Object mSensor;
+ private long mNumEvent;
+ private boolean mWrongSensorObserved;
+
+ /**
+ * Constructs an instance of {@link EventBasicVerification}.
+ *
+ * @param maximumSynchronizationErrorNs The valid threshold for timestamp synchronization.
+ * @param reportLatencyNs The latency on which batching events are received
+ */
+ public EventBasicVerification(
+ long expectedMinNumEvent,
+ Sensor sensor) {
+ mExpectedMinNumEvent = expectedMinNumEvent;
+ mSensor = sensor;
+
+ mNumEvent = 0;
+ mWrongSensorObserved = false;
+ }
+
+ /**
+ * Gets a default {@link EventBasicVerification}.
+ *
+ * @param environment The test environment
+ * @return The verification or null if the verification is not supported in the given
+ * environment.
+ */
+ public static EventBasicVerification getDefault(
+ TestSensorEnvironment environment,
+ long testDurationUs) {
+
+ long minTestDurationUs;
+ long batchUs = environment.getMaxReportLatencyUs();
+ long sampleUs = environment.getExpectedSamplingPeriodUs();
+ if (batchUs > 0) {
+ // test duration deduct allowed delivering latency and portion of time to deliver batch
+ // (which will be 10% of the batching time)
+ long effectiveTime = testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US - batchUs/10;
+
+ // allow part of last batch to be partially delivered (>80%)
+ minTestDurationUs = Math.max(
+ effectiveTime/batchUs * batchUs - batchUs/5,
+ environment.getExpectedSamplingPeriodUs());
+ } else {
+ minTestDurationUs =
+ Math.max(testDurationUs - ALLOWED_SENSOR_DELIVERING_DELAY_US,
+ environment.getExpectedSamplingPeriodUs());
+ }
+
+ long expectedMinNumEvent = minTestDurationUs / environment.getExpectedSamplingPeriodUs();
+ return new EventBasicVerification(expectedMinNumEvent, environment.getSensor());
+ }
+
+ @Override
+ public void verify(TestSensorEnvironment environment, SensorStats stats) {
+ verify(stats);
+ }
+
+ /* visible to unit test */
+ void verify(SensorStats stats) {
+
+ stats.addValue(SensorStats.EVENT_COUNT_KEY, mNumEvent);
+ stats.addValue(SensorStats.WRONG_SENSOR_KEY, mWrongSensorObserved);
+
+ boolean enoughSample = mNumEvent >= mExpectedMinNumEvent;
+ boolean noWrongSensor = !mWrongSensorObserved;
+
+ boolean success = enoughSample && noWrongSensor;
+ stats.addValue(PASSED_KEY, success);
+
+ if (!success) {
+ Assert.fail(String.format("Failed due to (%s%s)",
+ enoughSample?"":"insufficient events, ",
+ noWrongSensor?"":"wrong sensor observed, "));
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public EventBasicVerification clone() {
+ return new EventBasicVerification( mExpectedMinNumEvent, (Sensor)mSensor );
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ protected void addSensorEventInternal(TestSensorEvent event) {
+ if (event.sensor == mSensor) {
+ ++mNumEvent;
+ } else {
+ mWrongSensorObserved = true;
+ }
+ }
+
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java
new file mode 100644
index 0000000..34be3c4
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventBasicVerificationTest.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hardware.cts.helpers.sensorverification;
+
+import junit.framework.TestCase;
+import android.content.Context;
+import android.hardware.Sensor;
+import android.hardware.SensorManager;
+import android.hardware.cts.helpers.SensorStats;
+import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
+import android.test.AndroidTestCase;
+
+import java.util.ArrayList;
+import java.util.Collection;
+
+/**
+ * Tests for {@link EventBasicVerification}.
+ */
+public class EventBasicVerificationTest extends AndroidTestCase {
+
+ /**
+ * Test {@link EventBasicVerification#verify(TestSensorEnvironment, SensorStats)}.
+ */
+ public void testVerify() {
+
+ /* Sensor contents is not used in this verification, use Object as mock */
+ SensorManager mgr = (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE);
+
+ Sensor sensor1 = null;
+
+ // accelerometer is the most likely sensor to exist
+ Sensor sensor2 = mgr.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
+
+ SensorStats stats;
+
+ EventBasicVerification verification;
+
+ // case 1
+ verification = getVerification(10, sensor1, sensor1, new float[20][3]);
+ stats = new SensorStats();
+
+ verification.verify(stats);
+ assertEquals(true, stats.getValue(EventBasicVerification.PASSED_KEY));
+ assertEquals(20, (long) stats.getValue(SensorStats.EVENT_COUNT_KEY));
+ assertEquals(false, stats.getValue(SensorStats.WRONG_SENSOR_KEY));
+
+ // case 2
+ verification = getVerification(10, sensor1, sensor1, new float[5][3]);
+ stats = new SensorStats();
+
+ try {
+ verification.verify(stats);
+ fail("Expect an AssertionError due to insufficient samples");
+ } catch (AssertionError e) {
+ //Expected
+ }
+ assertEquals(false, stats.getValue(EventBasicVerification.PASSED_KEY));
+ assertEquals(5, (long) stats.getValue(SensorStats.EVENT_COUNT_KEY));
+ assertEquals(false, stats.getValue(SensorStats.WRONG_SENSOR_KEY));
+
+ // case 3
+ if (sensor1 != sensor2) {
+ // if we cannot even get a second sensor then do not bother this test.
+ verification = getVerification(10, sensor1, sensor2, new float[15][3]);
+ stats = new SensorStats();
+
+ try {
+ verification.verify(stats);
+ fail("Expect an AssertionError due to wrong sensor event");
+ } catch (AssertionError e) {
+ //Expected
+ }
+ assertEquals(false, stats.getValue(EventBasicVerification.PASSED_KEY));
+ // zero here because wrong sensor is used.
+ assertEquals(0, (long) stats.getValue(SensorStats.EVENT_COUNT_KEY));
+ assertEquals(true, stats.getValue(SensorStats.WRONG_SENSOR_KEY));
+ }
+ }
+
+ private static EventBasicVerification getVerification(
+ int expectedMinNumEvent, Sensor sensor, Sensor eventSensor, float[] ... values) {
+
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
+ for (float[] value : values) {
+ events.add(new TestSensorEvent(eventSensor, 0, 0, value));
+ }
+ EventBasicVerification verification =
+ new EventBasicVerification(expectedMinNumEvent, sensor);
+ verification.addSensorEvents(events);
+ return verification;
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
index 76f1594..c64810b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerification.java
@@ -28,15 +28,16 @@
// Number of events to truncate (discard) from the initial events received
private static final int TRUNCATE_EVENTS_COUNT = 1;
- // Number of event gaps to tolerate is the minimum of 1% of total events received or 10.
- private static final int EVENT_GAP_TOLERANCE_COUNT = 10;
- private static final double EVENT_GAP_TOLERANCE_PERCENT = 0.01;
+ // Number of event gaps to tolerate is 2% of total number of events received rounded up to next
+ // integer or 20, whichever is smaller.
+ private static final int EVENT_GAP_THRESHOLD_MAX = 20;
+ private static final double EVENT_GAP_TOLERANCE = 0.02;
private final int mExpectedDelayUs;
private final List<IndexedEventPair> mEventGaps = new LinkedList<IndexedEventPair>();
private TestSensorEvent mPreviousEvent = null;
- private int mIndex = 0;
+ private int mEventCount = 0;
/**
* Construct a {@link EventGapVerification}
@@ -72,14 +73,16 @@
}
final int count = mEventGaps.size();
- // Ensure that eventGapTolerance is at least 1.
- int eventGapTolerance = (int)Math.max(1, Math.min(EVENT_GAP_TOLERANCE_COUNT,
- EVENT_GAP_TOLERANCE_PERCENT * mIndex));
- stats.addValue(PASSED_KEY, count <= eventGapTolerance);
+ // Ensure the threshold is rounded up.
+ double eventGapThreshold =
+ Math.ceil(Math.min(EVENT_GAP_THRESHOLD_MAX, mEventCount * EVENT_GAP_TOLERANCE));
+ boolean pass = count <= eventGapThreshold;
+
+ stats.addValue(PASSED_KEY, pass);
stats.addValue(SensorStats.EVENT_GAP_COUNT_KEY, count);
stats.addValue(SensorStats.EVENT_GAP_POSITIONS_KEY, getIndexArray(mEventGaps));
- if (count > eventGapTolerance) {
+ if (!pass) {
StringBuilder sb = new StringBuilder();
sb.append(count).append(" events gaps: ");
for (int i = 0; i < Math.min(count, TRUNCATE_MESSAGE_LENGTH); i++) {
@@ -109,16 +112,16 @@
*/
@Override
protected void addSensorEventInternal(TestSensorEvent event) {
- if (mIndex >= TRUNCATE_EVENTS_COUNT) {
+ if (mEventCount >= TRUNCATE_EVENTS_COUNT) {
if (mPreviousEvent != null) {
long deltaNs = event.timestamp - mPreviousEvent.timestamp;
long deltaUs = TimeUnit.MICROSECONDS.convert(deltaNs, TimeUnit.NANOSECONDS);
if (deltaUs > mExpectedDelayUs * THRESHOLD) {
- mEventGaps.add(new IndexedEventPair(mIndex, event, mPreviousEvent));
+ mEventGaps.add(new IndexedEventPair(mEventCount, event, mPreviousEvent));
}
}
mPreviousEvent = event;
}
- mIndex++;
+ mEventCount++;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
index 15ff5c0..65d6fa5 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventTimestampSynchronizationVerification.java
@@ -38,7 +38,8 @@
// number of indices to print in assertion message before truncating
private static final int TRUNCATE_MESSAGE_LENGTH = 3;
- private static final long DEFAULT_THRESHOLD_NS = TimeUnit.MILLISECONDS.toNanos(500);
+ private static final long DEFAULT_THRESHOLD_NS = TimeUnit.MILLISECONDS.toNanos(1000);
+ private static final float ALLOWED_LATENCY_ERROR = 0.1f; //10%
private final ArrayList<TestSensorEvent> mCollectedEvents = new ArrayList<TestSensorEvent>();
@@ -87,9 +88,11 @@
}
// Add an additional filter delay which is a function of the samplingPeriod.
long filterDelayUs = (long)(2.5 * maximumExpectedSamplingPeriodUs);
+
long expectedSyncLatencyNs = TimeUnit.MICROSECONDS.toNanos(reportLatencyUs + filterDelayUs);
- return new EventTimestampSynchronizationVerification(DEFAULT_THRESHOLD_NS,
- expectedSyncLatencyNs);
+ return new EventTimestampSynchronizationVerification(
+ (long) (DEFAULT_THRESHOLD_NS + ALLOWED_LATENCY_ERROR * reportLatencyUs * 1000),
+ expectedSyncLatencyNs);
}
@Override
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
index 09bbdc8..51811a7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FifoLengthVerification.java
@@ -105,7 +105,7 @@
// Any event that arrives within before 0.5*expectedReportLatency is considered
// to be in the same batch of events, else it is considered as the beginning of a new
// batch.
- if (timestampDiff < 0.5 * mExpectedReportLatencyUs/1000) {
+ if (timestampDiff < mExpectedReportLatencyUs/1000/2) {
batchCount++;
} else {
endofbatch = true;
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 57a7474..1efcb7f 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -16,6 +16,8 @@
package android.keystore.cts;
+import android.app.KeyguardManager;
+import android.content.Context;
import android.security.KeyPairGeneratorSpec;
import android.security.KeyStoreParameter;
import android.security.keystore.KeyProperties;
@@ -1334,6 +1336,14 @@
}
public void testKeyStore_SetEntry_PrivateKeyEntry_Params_Unencrypted_Failure() throws Exception {
+ // This test asserts that Android Keystore refuses to create/import keys encrypted at rest
+ // using the secure lock screen credential. The test assumes that the secure lock screen is
+ // not set up.
+ KeyguardManager keyguardManager =
+ (KeyguardManager) getContext().getSystemService(Context.KEYGUARD_SERVICE);
+ assertNotNull(keyguardManager);
+ assertFalse("Secure lock screen must not be configured", keyguardManager.isDeviceSecure());
+
mKeyStore.load(null, null);
KeyFactory keyFact = KeyFactory.getInstance("RSA");
diff --git a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
index 197adc2..66e8093 100644
--- a/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
+++ b/tests/tests/keystore/src/android/keystore/cts/BlockCipherTestBase.java
@@ -30,6 +30,7 @@
import java.security.Key;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
import java.security.Provider;
import java.security.SecureRandom;
import java.security.Security;
@@ -50,6 +51,8 @@
abstract class BlockCipherTestBase extends AndroidTestCase {
+ private static final String EXPECTED_PROVIDER_NAME = TestUtils.EXPECTED_CRYPTO_OP_PROVIDER_NAME;
+
private KeyStore mAndroidKeyStore;
private int mNextKeyId;
@@ -121,7 +124,7 @@
public void testGetProvider() throws Exception {
createCipher();
- Provider expectedProvider = Security.getProvider("AndroidKeyStoreBCWorkaround");
+ Provider expectedProvider = Security.getProvider(EXPECTED_PROVIDER_NAME);
assertSame(expectedProvider, mCipher.getProvider());
}
@@ -1247,8 +1250,8 @@
}
protected void createCipher() throws NoSuchAlgorithmException,
- NoSuchPaddingException {
- mCipher = Cipher.getInstance(getTransformation());
+ NoSuchPaddingException, NoSuchProviderException {
+ mCipher = Cipher.getInstance(getTransformation(), EXPECTED_PROVIDER_NAME);
}
private String getKeyAlgorithm() {
diff --git a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
index 2459ac9..60a48e0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/CipherTest.java
@@ -441,12 +441,24 @@
if (!"SHA-1".equalsIgnoreCase(
((MGF1ParameterSpec) spec.getMGFParameters())
.getDigestAlgorithm())) {
+ // Create a new instance of Cipher because Bouncy Castle's RSA Cipher
+ // caches AlgorithmParameters returned by Cipher.getParameters and does
+ // not invalidate the cache when reinitialized with different
+ // parameters.
+ cipher = Cipher.getInstance(algorithm, encryptionProvider);
cipher.init(Cipher.ENCRYPT_MODE, encryptionKey, new OAEPParameterSpec(
spec.getDigestAlgorithm(),
"MGF1",
MGF1ParameterSpec.SHA1,
PSource.PSpecified.DEFAULT));
params = cipher.getParameters();
+ OAEPParameterSpec newSpec =
+ params.getParameterSpec(OAEPParameterSpec.class);
+ assertEquals(spec.getDigestAlgorithm(), newSpec.getDigestAlgorithm());
+ assertEquals(
+ "SHA-1",
+ ((MGF1ParameterSpec) newSpec.getMGFParameters())
+ .getDigestAlgorithm());
}
}
diff --git a/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
index 9424b74..d31f2e4 100644
--- a/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/RSASignatureTest.java
@@ -163,7 +163,7 @@
R.raw.rsa_key6_768_pkcs8, R.raw.rsa_key6_768_cert, importParams),
TestUtils.importIntoAndroidKeyStore("testRSA1024", context,
R.raw.rsa_key3_1024_pkcs8, R.raw.rsa_key3_1024_cert, importParams),
- TestUtils.importIntoAndroidKeyStore("testRSA2024", context,
+ TestUtils.importIntoAndroidKeyStore("testRSA2048", context,
R.raw.rsa_key8_2048_pkcs8, R.raw.rsa_key8_2048_cert, importParams),
TestUtils.importIntoAndroidKeyStore("testRSA3072", context,
R.raw.rsa_key7_3072_pksc8, R.raw.rsa_key7_3072_cert, importParams),
diff --git a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
index dab892c..4fa8899 100644
--- a/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/SignatureTest.java
@@ -562,8 +562,7 @@
}
}
- // TODO: Re-enable this test once Signature.initSign passes SecureRandom to SPI (Bug 22485587).
- public void DISABLED_testEntropyConsumption() throws Exception {
+ public void testEntropyConsumption() throws Exception {
// Assert that signature generation consumes the correct amount of entropy from the provided
// SecureRandom. There is no need to check that Signature.verify does not consume entropy
// because Signature.initVerify does not take a SecureRandom.
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index 85b8869..2c87005 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -744,7 +744,8 @@
if (KeyProperties.SIGNATURE_PADDING_RSA_PKCS1.equalsIgnoreCase(paddingScheme)) {
paddingOverheadBytes = 30;
} else if (KeyProperties.SIGNATURE_PADDING_RSA_PSS.equalsIgnoreCase(paddingScheme)) {
- paddingOverheadBytes = 22;
+ int saltSizeBytes = (digestOutputSizeBits + 7) / 8;
+ paddingOverheadBytes = saltSizeBytes + 1;
} else {
throw new IllegalArgumentException(
"Unsupported signature padding scheme: " + paddingScheme);
diff --git a/tests/tests/location/AndroidTest.xml b/tests/tests/location/AndroidTest.xml
index 8fdcc76..37a6a38 100644
--- a/tests/tests/location/AndroidTest.xml
+++ b/tests/tests/location/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Location test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLocationTestCases.apk" />
@@ -21,4 +22,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.location.cts" />
</test>
-</configuration>
\ No newline at end of file
+
+</configuration>
diff --git a/tests/tests/location2/AndroidTest.xml b/tests/tests/location2/AndroidTest.xml
index 9a9379d..5829249 100644
--- a/tests/tests/location2/AndroidTest.xml
+++ b/tests/tests/location2/AndroidTest.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<configuration description="Config for CTS Location test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsLocation2TestCases.apk" />
@@ -21,4 +22,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.location2.cts" />
</test>
-</configuration>
\ No newline at end of file
+
+</configuration>
diff --git a/tests/tests/media/libaudiojni/sl-utils.cpp b/tests/tests/media/libaudiojni/sl-utils.cpp
index 1aa89ba..4dbb08d 100644
--- a/tests/tests/media/libaudiojni/sl-utils.cpp
+++ b/tests/tests/media/libaudiojni/sl-utils.cpp
@@ -91,8 +91,10 @@
static SLObjectItf createEngine() {
static SLEngineOption EngineOption[] = {
+ {
(SLuint32) SL_ENGINEOPTION_THREADSAFE,
(SLuint32) SL_BOOLEAN_TRUE
+ },
};
// create engine in thread-safe mode
SLObjectItf engine;
diff --git a/tests/tests/media/src/android/media/cts/AudioRecordTest.java b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
index d503144..84c676f 100644
--- a/tests/tests/media/src/android/media/cts/AudioRecordTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioRecordTest.java
@@ -16,6 +16,8 @@
package android.media.cts;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.cts.util.CtsAndroidTestCase;
import android.media.AudioFormat;
@@ -280,6 +282,9 @@
// Audit modes work best with non-blocking mode
public void testAudioRecordAuditByteBufferResamplerStereoFloat() throws Exception {
+ if (isLowRamDevice()) {
+ return; // skip. FIXME: reenable when AF memory allocation is updated.
+ }
doTest("AuditByteBufferResamplerStereoFloat",
false /*localRecord*/, true /*customHandler*/,
2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
@@ -299,6 +304,9 @@
// Audit buffers can run out of space with high sample rate,
// so keep the channels and pcm encoding low
public void testAudioRecordAuditChannelIndex2() throws Exception {
+ if (isLowRamDevice()) {
+ return; // skip. FIXME: reenable when AF memory allocation is updated.
+ }
doTest("AuditChannelIndex2", true /*localRecord*/, true /*customHandler*/,
2 /*periodsPerSecond*/, 0 /*markerPeriodsPerSecond*/,
false /*useByteBuffer*/, false /*blocking*/,
@@ -877,6 +885,8 @@
// valid events, issuing right after stop completes. Except for those events,
// no other events should show up after stop.
// This behavior may change in the future but we account for it here in testing.
+ final long SLEEP_AFTER_STOP_FOR_EVENTS_MS = 30;
+ Thread.sleep(SLEEP_AFTER_STOP_FOR_EVENTS_MS);
listener.stop();
// clean up
@@ -1011,10 +1021,10 @@
assertEquals(AudioRecord.SUCCESS,
mAudioRecord.setNotificationMarkerPosition(mMarkerPosition));
} else {
- // stop() is not sufficient to end all notifications
- // as is not synchronous with the event handling thread
- // so we comment out the line below.
- // fail("onMarkerReached called when not active");
+ // see comment on stop()
+ final long delta = System.currentTimeMillis() - mStopTime;
+ Log.d(TAG, "onMarkerReached called " + delta + " ms after stop");
+ fail("onMarkerReached called when not active");
}
}
@@ -1023,8 +1033,10 @@
int position = getPosition();
mOnPeriodicNotificationCalled.add(position);
} else {
- // see above comments about stop
- // fail("onPeriodicNotification called when not active");
+ // see comment on stop()
+ final long delta = System.currentTimeMillis() - mStopTime;
+ Log.d(TAG, "onPeriodicNotification called " + delta + " ms after stop");
+ fail("onPeriodicNotification called when not active");
}
}
@@ -1035,7 +1047,10 @@
}
public synchronized void stop() {
+ // the listener should be stopped some time after AudioRecord is stopped
+ // as some messages may not yet be posted.
mIsTestActive = false;
+ mStopTime = System.currentTimeMillis();
}
public ArrayList<Integer> getMarkerList() {
@@ -1060,6 +1075,7 @@
}
private long mStartTime;
+ private long mStopTime;
private int mSampleRate;
private boolean mIsTestActive = true;
private AudioRecord mAudioRecord;
@@ -1071,4 +1087,9 @@
return getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_MICROPHONE);
}
+
+ private boolean isLowRamDevice() {
+ return ((ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE))
+ .isLowRamDevice();
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index 92f69ea..a2d6cfb 100644
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -16,6 +16,8 @@
package android.media.cts;
+import android.app.ActivityManager;
+import android.content.Context;
import android.content.pm.PackageManager;
import android.cts.util.CtsAndroidTestCase;
import android.media.AudioAttributes;
@@ -1563,11 +1565,17 @@
final int TEST_MODE = AudioTrack.MODE_STREAM;
final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
final float TEST_SWEEP = 0; // sine wave only
+ final boolean TEST_IS_LOW_RAM_DEVICE = isLowRamDevice();
for (int TEST_FORMAT : TEST_FORMAT_ARRAY) {
double frequency = 400; // frequency changes for each test
for (int TEST_SR : TEST_SR_ARRAY) {
for (int TEST_CONF : TEST_CONF_ARRAY) {
+ final int channelCount = Integer.bitCount(TEST_CONF);
+ if (TEST_IS_LOW_RAM_DEVICE
+ && (TEST_SR > 96000 || channelCount > 4)) {
+ continue; // ignore. FIXME: reenable when AF memory allocation is updated.
+ }
// -------- initialization --------------
final int minBufferSize = AudioTrack.getMinBufferSize(TEST_SR,
TEST_CONF, TEST_FORMAT); // in bytes
@@ -1576,7 +1584,6 @@
assertTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
// compute parameters for the source signal data.
- final int channelCount = Integer.bitCount(TEST_CONF);
AudioFormat format = track.getFormat();
assertEquals(TEST_NAME, TEST_SR, format.getSampleRate());
assertEquals(TEST_NAME, TEST_CONF, format.getChannelMask());
@@ -1893,6 +1900,11 @@
.hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
}
+ private boolean isLowRamDevice() {
+ return ((ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE))
+ .isLowRamDevice();
+ }
+
public void testGetTimestamp() throws Exception {
if (!hasAudioOutput()) {
Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
@@ -2092,6 +2104,12 @@
}
public void testVariableSpeedPlayback() throws Exception {
+ if (!hasAudioOutput()) {
+ Log.w(TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+ + "audio output HAL");
+ return;
+ }
+
final String TEST_NAME = "testVariableSpeedPlayback";
final int TEST_FORMAT = AudioFormat.ENCODING_PCM_FLOAT; // required for test
final int TEST_MODE = AudioTrack.MODE_STATIC; // required for test
diff --git a/tests/tests/media/src/android/media/cts/CodecState.java b/tests/tests/media/src/android/media/cts/CodecState.java
index 6fdbd86..de0bdf8 100644
--- a/tests/tests/media/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/src/android/media/cts/CodecState.java
@@ -220,8 +220,12 @@
mSawInputEOS = true;
// FIX-ME: in tunneled mode we currently use input EOS as output EOS indicator
// we should stream duration
- if (mTunneled && !mIsAudio) {
- mSawOutputEOS = true;
+ if (mTunneled) {
+ if (!mIsAudio) {
+ mSawOutputEOS = true;
+ } else if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ }
}
return false;
}
@@ -260,6 +264,10 @@
index, 0 /* offset */, 0 /* sampleSize */,
0 /* sampleTime */, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
+ if (mTunneled && mAudioTrack != null) {
+ mAudioTrack.stop();
+ }
+
mAvailableInputBufferIndices.removeFirst();
}
@@ -271,7 +279,9 @@
// b/9250789
Log.d(TAG, "CodecState::onOutputFormatChanged " + mime);
+ mIsAudio = false;
if (mime.startsWith("audio/")) {
+ mIsAudio = true;
int sampleRate =
mOutputFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
@@ -315,6 +325,9 @@
mSawOutputEOS = true;
+ if (mAudioTrack != null && !mTunneled) {
+ mAudioTrack.stop();
+ }
return false;
}
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
index 40934f5..99f9759 100644
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
@@ -16,6 +16,7 @@
package android.media.cts;
+import android.cts.util.MediaUtils;
import android.graphics.ImageFormat;
import android.media.Image;
import android.media.MediaCodec;
@@ -284,6 +285,10 @@
@Override
public void run() {
+ if (mTest.shouldSkip()) {
+ return;
+ }
+
InputSurface inputSurface = null;
try {
if (!mUsePersistentInput) {
@@ -339,6 +344,22 @@
mAllowBT709 = allowBT709;
}
+ private boolean shouldSkip() {
+ if (!MediaUtils.hasEncoder(mMimeType)) {
+ return true;
+ }
+
+ MediaFormat format = MediaFormat.createVideoFormat(mMimeType, mWidth, mHeight);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate);
+ format.setInteger(MediaFormat.KEY_FRAME_RATE, FRAME_RATE);
+ format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
+ if (!MediaUtils.checkEncoderForFormat(format)) {
+ return true;
+ }
+
+ return false;
+ }
+
/**
* Tests encoding and subsequently decoding video from frames generated into a buffer.
* <p>
@@ -348,6 +369,10 @@
* See http://b.android.com/37769 for a discussion of input format pitfalls.
*/
private void encodeDecodeVideoFromBuffer(boolean toSurface) throws Exception {
+ if (shouldSkip()) {
+ return;
+ }
+
MediaCodec encoder = null;
MediaCodec decoder = null;
@@ -365,6 +390,12 @@
return;
}
if (VERBOSE) Log.d(TAG, "found codec: " + codec);
+
+ String codec_decoder = mcl.findDecoderForFormat(format);
+ if (codec_decoder == null) {
+ Log.e(TAG, "Unable to find an appropriate codec for " + format);
+ return;
+ }
// Create a MediaCodec for the desired codec, then configure it as an encoder with
// our desired properties.
@@ -386,7 +417,7 @@
// Create a MediaCodec for the decoder, just based on the MIME type. The various
// format details will be passed through the csd-0 meta-data later on.
- decoder = MediaCodec.createDecoderByType(mMimeType);
+ decoder = MediaCodec.createByCodecName(codec_decoder);
if (VERBOSE) Log.d(TAG, "got decoder: " + decoder.getName());
doEncodeDecodeVideoFromBuffer(encoder, colorFormat, decoder, toSurface);
@@ -447,7 +478,12 @@
// Create a MediaCodec for the decoder, just based on the MIME type. The various
// format details will be passed through the csd-0 meta-data later on.
- decoder = MediaCodec.createDecoderByType(mMimeType);
+ String codec_decoder = mcl.findDecoderForFormat(format);
+ if (codec_decoder == null) {
+ Log.e(TAG, "Unable to find an appropriate codec for " + format);
+ return;
+ }
+ decoder = MediaCodec.createByCodecName(codec_decoder);
if (VERBOSE) Log.d(TAG, "got decoder: " + decoder.getName());
decoder.configure(format, outputSurface.getSurface(), null, 0);
decoder.start();
@@ -550,7 +586,8 @@
ByteBuffer[] encoderOutputBuffers = encoder.getOutputBuffers();
ByteBuffer[] decoderInputBuffers = null;
ByteBuffer[] decoderOutputBuffers = null;
- MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo decoderInfo = new MediaCodec.BufferInfo();
+ MediaCodec.BufferInfo encoderInfo = new MediaCodec.BufferInfo();
MediaFormat decoderOutputFormat = null;
int generateIndex = 0;
int checkIndex = 0;
@@ -589,9 +626,11 @@
boolean inputDone = false;
boolean encoderDone = false;
boolean outputDone = false;
+ int encoderStatus = -1;
while (!outputDone) {
if (VERBOSE) Log.d(TAG, "loop");
+
// If we're not done submitting frames, generate a new one and submit it. By
// doing this on every loop we're working to ensure that the encoder always has
// work to do.
@@ -637,7 +676,10 @@
//
// Once we get EOS from the encoder, we don't need to do this anymore.
if (!encoderDone) {
- int encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
+ MediaCodec.BufferInfo info = encoderInfo;
+ if (encoderStatus < 0) {
+ encoderStatus = encoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
+ }
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
if (VERBOSE) Log.d(TAG, "no output from encoder available");
@@ -661,18 +703,7 @@
encodedData.position(info.offset);
encodedData.limit(info.offset + info.size);
- encodedSize += info.size;
- if (outputStream != null) {
- byte[] data = new byte[info.size];
- encodedData.get(data);
- encodedData.position(info.offset);
- try {
- outputStream.write(data);
- } catch (IOException ioe) {
- Log.w(TAG, "failed writing debug data to file");
- throw new RuntimeException(ioe);
- }
- }
+ boolean releaseBuffer = false;
if (!decoderConfigured) {
// Codec config info. Only expected on first packet. One way to
// handle this is to manually stuff the data into the MediaFormat
@@ -694,21 +725,41 @@
if (VERBOSE) Log.d(TAG, "decoder configured (" + info.size + " bytes)");
}
if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
- // Get a decoder input buffer, blocking until it's available.
+ // Get a decoder input buffer
assertTrue(decoderConfigured);
- int inputBufIndex = decoder.dequeueInputBuffer(-1);
- ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex];
- inputBuf.clear();
- inputBuf.put(encodedData);
- decoder.queueInputBuffer(inputBufIndex, 0, info.size,
- info.presentationTimeUs, info.flags);
+ int inputBufIndex = decoder.dequeueInputBuffer(TIMEOUT_USEC);
+ if (inputBufIndex >= 0) {
+ ByteBuffer inputBuf = decoderInputBuffers[inputBufIndex];
+ inputBuf.clear();
+ inputBuf.put(encodedData);
+ decoder.queueInputBuffer(inputBufIndex, 0, info.size,
+ info.presentationTimeUs, info.flags);
- encoderDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
- if (VERBOSE) Log.d(TAG, "passed " + info.size + " bytes to decoder"
- + (encoderDone ? " (EOS)" : ""));
+ encoderDone = (info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0;
+ if (VERBOSE) Log.d(TAG, "passed " + info.size + " bytes to decoder"
+ + (encoderDone ? " (EOS)" : ""));
+ releaseBuffer = true;
+ }
+ } else {
+ releaseBuffer = true;
+ }
+ if (releaseBuffer) {
+ encodedSize += info.size;
+ if (outputStream != null) {
+ byte[] data = new byte[info.size];
+ encodedData.position(info.offset);
+ encodedData.get(data);
+ try {
+ outputStream.write(data);
+ } catch (IOException ioe) {
+ Log.w(TAG, "failed writing debug data to file");
+ throw new RuntimeException(ioe);
+ }
+ }
+ encoder.releaseOutputBuffer(encoderStatus, false);
+ encoderStatus = -1;
}
- encoder.releaseOutputBuffer(encoderStatus, false);
}
}
@@ -719,6 +770,7 @@
// If we're decoding to a Surface, we'll get notified here as usual but the
// ByteBuffer references will be null. The data is sent to Surface instead.
if (decoderConfigured) {
+ MediaCodec.BufferInfo info = decoderInfo;
int decoderStatus = decoder.dequeueOutputBuffer(info, TIMEOUT_USEC);
if (decoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
// no output available yet
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java b/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
index 2473078..f5856ed 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCencPlayer.java
@@ -54,7 +54,7 @@
private boolean mEncryptedAudio;
private boolean mEncryptedVideo;
- private boolean mThreadStarted = false;
+ private volatile boolean mThreadStarted = false;
private byte[] mSessionId;
private CodecState mAudioTrackState;
private int mMediaFormatHeight;
@@ -304,7 +304,7 @@
CodecState state;
if (isVideo) {
state = new CodecState((MediaTimeProvider)this, mVideoExtractor,
- trackIndex, format, codec, true, false,
+ trackIndex, format, codec, true, false,
AudioManager.AUDIO_SESSION_ID_GENERATE);
mVideoCodecStates.put(Integer.valueOf(trackIndex), state);
} else {
diff --git a/tests/tests/media/src/android/media/cts/MediaSyncTest.java b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
index 29e5709..e211682 100644
--- a/tests/tests/media/src/android/media/cts/MediaSyncTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSyncTest.java
@@ -18,6 +18,7 @@
import android.media.cts.R;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.Resources;
import android.cts.util.MediaUtils;
@@ -155,6 +156,11 @@
}
}
+ private boolean hasAudioOutput() {
+ return mActivity.getPackageManager()
+ .hasSystemFeature(PackageManager.FEATURE_AUDIO_OUTPUT);
+ }
+
/**
* Tests setPlaybackParams is handled correctly for wrong rate.
*/
@@ -337,6 +343,12 @@
* Tests playing back video successfully.
*/
public void testPlayAudio() throws InterruptedException {
+ if (!hasAudioOutput()) {
+ Log.w(LOG_TAG,"AUDIO_OUTPUT feature not found. This system might not have a valid "
+ + "audio output HAL");
+ return;
+ }
+
playAV(INPUT_RESOURCE_ID, 5000 /* lastBufferTimestampMs */,
true /* audio */, false /* video */, 10000 /* timeOutMs */);
}
diff --git a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
index 3847252..4a4e807 100644
--- a/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
+++ b/tests/tests/media/src/android/media/cts/NonBlockingAudioTrack.java
@@ -43,6 +43,7 @@
private int mSampleRate;
private int mNumBytesQueued = 0;
private LinkedList<QueueElement> mQueue = new LinkedList<QueueElement>();
+ private boolean mStopped;
public NonBlockingAudioTrack(int sampleRate, int channelCount, boolean hwAvSync,
int audioSessionId) {
@@ -107,14 +108,17 @@
}
public void play() {
+ mStopped = false;
mAudioTrack.play();
}
public void stop() {
- mAudioTrack.stop();
-
- mQueue.clear();
- mNumBytesQueued = 0;
+ if (mQueue.isEmpty()) {
+ mAudioTrack.stop();
+ mNumBytesQueued = 0;
+ } else {
+ mStopped = true;
+ }
}
public void pause() {
@@ -128,6 +132,7 @@
mAudioTrack.flush();
mQueue.clear();
mNumBytesQueued = 0;
+ mStopped = false;
}
public void release() {
@@ -135,6 +140,7 @@
mNumBytesQueued = 0;
mAudioTrack.release();
mAudioTrack = null;
+ mStopped = false;
}
public void process() {
@@ -153,6 +159,11 @@
}
mQueue.removeFirst();
}
+ if (mStopped) {
+ mAudioTrack.stop();
+ mNumBytesQueued = 0;
+ mStopped = false;
+ }
}
public int getPlayState() {
diff --git a/tests/tests/media/src/android/media/cts/RemoteControllerTest.java b/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
new file mode 100644
index 0000000..2511889
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/RemoteControllerTest.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.media.cts;
+
+import android.content.Context;
+import android.media.RemoteController;
+import android.media.RemoteController.OnClientUpdateListener;
+import android.test.InstrumentationTestCase;
+import android.test.UiThreadTest;
+import android.view.KeyEvent;
+import android.util.Log;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Tests for {@link RemoteController}.
+ */
+public class RemoteControllerTest extends InstrumentationTestCase {
+
+ private static final Set<Integer> MEDIA_KEY_EVENT = new HashSet<Integer>();
+ static {
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_PLAY);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_PAUSE);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_PLAY_PAUSE);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MUTE);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_HEADSETHOOK);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_STOP);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_NEXT);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_REWIND);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_RECORD);
+ MEDIA_KEY_EVENT.add(KeyEvent.KEYCODE_MEDIA_FAST_FORWARD);
+ }
+
+ static OnClientUpdateListener listener = new OnClientUpdateListener() {
+ @Override
+ public void onClientChange(boolean clearing) {}
+ @Override
+ public void onClientPlaybackStateUpdate(int state) {}
+ @Override
+ public void onClientPlaybackStateUpdate(
+ int state, long stateChangeTimeMs, long currentPosMs, float speed) {}
+ @Override
+ public void onClientTransportControlUpdate(int transportControlFlags) {}
+ @Override
+ public void onClientMetadataUpdate(RemoteController.MetadataEditor metadataEditor) {}
+ };
+
+ private Context mContext;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContext = getInstrumentation().getTargetContext();
+ }
+
+ private RemoteController createRemoteController() {
+ return new RemoteController(mContext, listener);
+ }
+
+ @UiThreadTest
+ public void testGetEstimatedMediaPosition() {
+ assertTrue(createRemoteController().getEstimatedMediaPosition() < 0);
+ }
+
+ @UiThreadTest
+ public void testSendMediaKeyEvent() {
+ RemoteController remoteController = createRemoteController();
+ for (Integer mediaKeyEvent : MEDIA_KEY_EVENT) {
+ assertFalse(remoteController.sendMediaKeyEvent(
+ new KeyEvent(KeyEvent.ACTION_DOWN, mediaKeyEvent)));
+ }
+ }
+
+ @UiThreadTest
+ public void testSeekTo_negativeValues() {
+ try {
+ createRemoteController().seekTo(-1);
+ fail("timeMs must be >= 0");
+ } catch (IllegalArgumentException expected) {}
+ }
+
+ @UiThreadTest
+ public void testSeekTo() {
+ assertTrue(createRemoteController().seekTo(0));
+ }
+
+ @UiThreadTest
+ public void testSetArtworkConfiguration() {
+ assertTrue(createRemoteController().setArtworkConfiguration(1, 1));
+ }
+
+ @UiThreadTest
+ public void testClearArtworkConfiguration() {
+ assertTrue(createRemoteController().clearArtworkConfiguration());
+ }
+
+ @UiThreadTest
+ public void testSetSynchronizationMode_unregisteredRemoteController() {
+ RemoteController remoteController = createRemoteController();
+ assertFalse(remoteController.setSynchronizationMode(
+ RemoteController.POSITION_SYNCHRONIZATION_NONE));
+ assertFalse(remoteController.setSynchronizationMode(
+ RemoteController.POSITION_SYNCHRONIZATION_CHECK));
+ }
+
+ @UiThreadTest
+ public void testEditMetadata() {
+ assertNotNull(createRemoteController().editMetadata());
+ }
+
+ @UiThreadTest
+ public void testOnClientUpdateListenerUnchanged() throws Exception {
+ Map<String, List<Method>> methodMap = new HashMap<String, List<Method>>();
+ for (Method method : listener.getClass().getDeclaredMethods()) {
+ if (!methodMap.containsKey(method.getName())) {
+ methodMap.put(method.getName(), new ArrayList<Method>());
+ }
+ methodMap.get(method.getName()).add(method);
+ }
+
+ for (Method method : OnClientUpdateListener.class.getDeclaredMethods()) {
+ assertTrue("Method not found: " + method.getName(),
+ methodMap.containsKey(method.getName()));
+ List<Method> implementedMethodList = methodMap.get(method.getName());
+ assertTrue("Method signature changed: " + method,
+ matchMethod(method, implementedMethodList));
+ }
+ }
+
+ private static boolean matchMethod(Method method, List<Method> potentialMatches) {
+ for (Method potentialMatch : potentialMatches) {
+ if (method.getName().equals(potentialMatch.getName()) &&
+ method.getReturnType().equals(potentialMatch.getReturnType()) &&
+ Arrays.equals(method.getTypeParameters(),
+ potentialMatch.getTypeParameters())) {
+ return true;
+ }
+ }
+ return false;
+ }
+}
diff --git a/tests/tests/mediastress/preconditions/tests/Android.mk b/tests/tests/mediastress/preconditions/tests/Android.mk
index 67eaf5d..48fdcfc 100644
--- a/tests/tests/mediastress/preconditions/tests/Android.mk
+++ b/tests/tests/mediastress/preconditions/tests/Android.mk
@@ -26,9 +26,6 @@
LOCAL_MODULE := compatibility-host-media-preconditions-tests
-# Tag this module as a cts_v2 test artifact
-LOCAL_COMPATIBILITY_SUITE := cts_v2
-
LOCAL_SDK_VERSION := current
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/tests/mediastress/preconditions/tests/run_tests.sh b/tests/tests/mediastress/preconditions/tests/run_tests.sh
new file mode 100755
index 0000000..1a47caf
--- /dev/null
+++ b/tests/tests/mediastress/preconditions/tests/run_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-host-util\
+ cts-tradefed_v2\
+ compatibility-host-media-preconditions\
+ compatibility-host-media-preconditions-tests"
+
+run_tests "android.mediastress.cts.preconditions.MediaPreparerTest" "${JARS}" "${@}"
diff --git a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
index 152789c..4478bd4 100644
--- a/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/WifiManagerTest.java
@@ -21,6 +21,8 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
import android.net.NetworkInfo;
import android.net.wifi.ScanResult;
import android.net.wifi.WifiConfiguration;
@@ -29,6 +31,7 @@
import android.net.wifi.WifiManager.TxPacketCountListener;
import android.net.wifi.WifiManager.WifiLock;
import android.os.SystemClock;
+import android.provider.Settings;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -278,6 +281,14 @@
Log.d(TAG, "Skipping test as WiFi is not supported");
return;
}
+ if (!hasLocationFeature()) {
+ Log.d(TAG, "Skipping test as location is not supported");
+ return;
+ }
+ if (!isLocationEnabled()) {
+ fail("Please enable location for this test - since Marshmallow WiFi scan results are"
+ + " empty when location is disabled!");
+ }
if (!mWifiManager.isWifiEnabled()) {
setWifiEnabled(true);
}
@@ -307,6 +318,18 @@
}
}
+ // Return true if location is enabled.
+ private boolean isLocationEnabled() {
+ return Settings.Secure.getInt(getContext().getContentResolver(),
+ Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF) !=
+ Settings.Secure.LOCATION_MODE_OFF;
+ }
+
+ // Returns true if the device has location feature.
+ private boolean hasLocationFeature() {
+ return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_LOCATION);
+ }
+
/**
* test point of wifiManager NetWork:
* 1.add NetWork
diff --git a/tests/tests/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java b/tests/tests/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
new file mode 100644
index 0000000..826b7ae
--- /dev/null
+++ b/tests/tests/net/src/org/apache/http/conn/ssl/cts/AbstractVerifierTest.java
@@ -0,0 +1,307 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.http.conn.ssl.cts;
+
+import javax.security.auth.x500.X500Principal;
+import junit.framework.TestCase;
+
+import org.apache.http.conn.ssl.AbstractVerifier;
+
+import java.lang.Override;
+import java.math.BigInteger;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.Principal;
+import java.security.PublicKey;
+import java.security.SignatureException;
+import java.security.cert.CertificateEncodingException;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateExpiredException;
+import java.security.cert.CertificateNotYetValidException;
+import java.security.cert.X509Certificate;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * See also {@link libcore.javax.security.auth.x500.X500PrincipalTest} as it shows some cases
+ * we are not checking as they are not allowed by the X500 principal in the first place.
+ */
+public final class AbstractVerifierTest extends TestCase {
+
+ public void testGetCns() {
+ assertCns("");
+ assertCns("ou=xxx");
+ assertCns("ou=xxx,cn=xxx", "xxx");
+ assertCns("ou=xxx+cn=yyy,cn=zzz+cn=abc", "yyy", "zzz", "abc");
+ assertCns("cn=a,cn=b", "a", "b");
+ assertCns("cn=a c,cn=b", "a c", "b");
+ assertCns("cn=a ,cn=b", "a", "b");
+ assertCns("cn=Cc,cn=Bb,cn=Aa", "Cc", "Bb", "Aa");
+ assertCns("cn=imap.gmail.com", "imap.gmail.com");
+ assertCns("l=\"abcn=a,b\", cn=c", "c");
+ assertCns("l=\"abcn=a,b\", cn=c", "c");
+ assertCns("l=\"abcn=a,b\", cn= c", "c");
+ assertCns("cn=<", "<");
+ assertCns("cn=>", ">");
+ assertCns("cn= >", ">");
+ assertCns("cn=a b", "a b");
+ assertCns("cn =a b", "a b");
+ assertCns("Cn=a b", "a b");
+ assertCns("cN=a b", "a b");
+ assertCns("CN=a b", "a b");
+ assertCns("cn=a#b", "a#b");
+ assertCns("cn=#130161", "a");
+ assertCns("l=q\t+cn=p", "p");
+ assertCns("l=q\n+cn=p", "p");
+ assertCns("l=q\n,cn=p", "p");
+ assertCns("l=,cn=p", "p");
+ assertCns("l=\tq\n,cn=\tp", "\tp");
+ }
+
+ /** A cn=, generates an empty value, unless it's at the very end */
+ public void testEmptyValues() {
+ assertCns("l=,cn=+cn=q", "", "q");
+ assertCns("l=,cn=,cn=q", "", "q");
+ assertCns("l=,cn=");
+ assertCns("l=,cn=q,cn= ", "q");
+ assertCns("l=,cn=q ,cn= ", "q");
+ assertCns("l=,cn=\"\"");
+ assertCns("l=,cn=\" \",cn=\" \"", " ", " ");
+ assertCns("l=,cn= ,cn= ","");
+ assertCns("l=,cn=,cn= ,cn= ", "", "");
+ }
+
+
+ public void testGetCns_escapedChars() {
+ assertCns("cn=\\,", ",");
+ assertCns("cn=\\#", "#");
+ assertCns("cn=\\+", "+");
+ assertCns("cn=\\\"", "\"");
+ assertCns("cn=\\\\", "\\");
+ assertCns("cn=\\<", "<");
+ assertCns("cn=\\>", ">");
+ assertCns("cn=\\;", ";");
+ assertCns("cn=\\+", "+");
+ assertCns("cn=\"\\+\"", "+");
+ assertCns("cn=\"\\,\"", ",");
+ assertCns("cn= a =", "a =");
+ assertCns("cn==", "=");
+ }
+
+ public void testGetCns_whitespace() {
+ assertCns("cn= p", "p");
+ assertCns("cn=\np", "\np");
+ assertCns("cn=\tp", "\tp");
+ }
+
+ public void testGetCnsWithOid() {
+ assertCns("2.5.4.3=a,ou=xxx", "a");
+ assertCns("2.5.4.3=\" a \",ou=xxx", " a ");
+ assertCns("2.5.5.3=a,ou=xxx,cn=b", "b");
+ }
+
+ public void testGetCnsWithQuotedStrings() {
+ assertCns("cn=\"\\\" a ,=<>#;\"", "\" a ,=<>#;");
+ assertCns("cn=abc\\,def", "abc,def");
+ assertCns("cn=\"\\\" a ,\\=<>\\#;\"", "\" a ,=<>#;");
+ }
+
+ public void testGetCnsWithUtf8() {
+ assertCns("cn=\"Lu\\C4\\8Di\\C4\\87\"", "\u004c\u0075\u010d\u0069\u0107");
+ assertCns("cn=Lu\\C4\\8Di\\C4\\87", "\u004c\u0075\u010d\u0069\u0107");
+ assertCns("cn=Lu\\C4\\8di\\c4\\87", "\u004c\u0075\u010d\u0069\u0107");
+ assertCns("cn=\"Lu\\C4\\8di\\c4\\87\"", "\u004c\u0075\u010d\u0069\u0107");
+ assertCns("cn=\u004c\u0075\u010d\u0069\u0107", "\u004c\u0075\u010d\u0069\u0107");
+ // \63=c
+ assertExceptionInPrincipal("\\63n=ab");
+ assertExceptionInPrincipal("cn=\\a");
+ }
+
+ public void testGetCnsWithWhitespace() {
+ assertCns("ou=a, cn= a b ,o=x", "a b");
+ assertCns("cn=\" a b \" ,o=x", " a b ");
+ }
+
+ private static void assertCns(String dn, String... expected) {
+ String[] result = AbstractVerifier.getCNs(createStubCertificate(dn));
+ System.out.println("Expected is: " + expected.length);
+ if (expected.length == 0) {
+ assertNull(result);
+ } else {
+ assertNotNull(dn, result);
+ assertEquals(dn, Arrays.asList(expected), Arrays.asList(result));
+ }
+ }
+
+ private static void assertExceptionInPrincipal(String dn) {
+ try {
+ X500Principal principal = new X500Principal(dn);
+ fail("Expected " + IllegalArgumentException.class.getName()
+ + " because of incorrect input name");
+ } catch (IllegalArgumentException e) {
+ // Expected.
+ }
+ }
+
+ private static X509Certificate createStubCertificate(final String subjectName) {
+ return new X509Certificate() {
+ @Override
+ public X500Principal getSubjectX500Principal() {
+ return new X500Principal(subjectName);
+ }
+
+ @Override
+ public Set<String> getCriticalExtensionOIDs() {
+ return null;
+ }
+
+ @Override
+ public byte[] getExtensionValue(String oid) {
+ return new byte[0];
+ }
+
+ @Override
+ public Set<String> getNonCriticalExtensionOIDs() {
+ return null;
+ }
+
+ @Override
+ public boolean hasUnsupportedCriticalExtension() {
+ return false;
+ }
+
+ @Override
+ public byte[] getEncoded() throws CertificateEncodingException {
+ return new byte[0];
+ }
+
+ @Override
+ public void verify(PublicKey key)
+ throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException {
+
+ }
+
+ @Override
+ public void verify(PublicKey key, String sigProvider)
+ throws CertificateException, NoSuchAlgorithmException, InvalidKeyException,
+ NoSuchProviderException, SignatureException {
+
+ }
+
+ @Override
+ public String toString() {
+ return null;
+ }
+
+ @Override
+ public PublicKey getPublicKey() {
+ return null;
+ }
+
+ @Override
+ public void checkValidity()
+ throws CertificateExpiredException, CertificateNotYetValidException {
+
+ }
+
+ @Override
+ public void checkValidity(Date date)
+ throws CertificateExpiredException, CertificateNotYetValidException {
+
+ }
+
+ @Override
+ public int getVersion() {
+ return 0;
+ }
+
+ @Override
+ public BigInteger getSerialNumber() {
+ return null;
+ }
+
+ @Override
+ public Principal getIssuerDN() {
+ return null;
+ }
+
+ @Override
+ public Principal getSubjectDN() {
+ return null;
+ }
+
+ @Override
+ public Date getNotBefore() {
+ return null;
+ }
+
+ @Override
+ public Date getNotAfter() {
+ return null;
+ }
+
+ @Override
+ public byte[] getTBSCertificate() throws CertificateEncodingException {
+ return new byte[0];
+ }
+
+ @Override
+ public byte[] getSignature() {
+ return new byte[0];
+ }
+
+ @Override
+ public String getSigAlgName() {
+ return null;
+ }
+
+ @Override
+ public String getSigAlgOID() {
+ return null;
+ }
+
+ @Override
+ public byte[] getSigAlgParams() {
+ return new byte[0];
+ }
+
+ @Override
+ public boolean[] getIssuerUniqueID() {
+ return new boolean[0];
+ }
+
+ @Override
+ public boolean[] getSubjectUniqueID() {
+ return new boolean[0];
+ }
+
+ @Override
+ public boolean[] getKeyUsage() {
+ return new boolean[0];
+ }
+
+ @Override
+ public int getBasicConstraints() {
+ return 0;
+ }
+ };
+ }
+}
+
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index f4b140e..6a2f8f8 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -36,6 +36,9 @@
LOCAL_PACKAGE_NAME := CtsOsTestCases
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
# uncomment when b/13282254 is fixed
#LOCAL_SDK_VERSION := current
LOCAL_JAVA_LIBRARIES += android.test.runner
diff --git a/tests/tests/os/AndroidTest.xml b/tests/tests/os/AndroidTest.xml
new file mode 100644
index 0000000..cfa29ae
--- /dev/null
+++ b/tests/tests/os/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Configuration for OS Tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsOsTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="com.android.cts.os" />
+ </test>
+</configuration>
diff --git a/tests/tests/os/jni/seccomp-tests/README.android b/tests/tests/os/jni/seccomp-tests/README.android
index 4c5bb83..8b1ac9a 100644
--- a/tests/tests/os/jni/seccomp-tests/README.android
+++ b/tests/tests/os/jni/seccomp-tests/README.android
@@ -11,3 +11,7 @@
- Add get_seccomp_test_list()
The diff of modifications can be found in local-modifications-android.diff.
+
+Additional modification is to backport fixes for Android Native Bridge:
+https://patchwork.kernel.org/patch/7537891/. This is not found in the above
+diff file. The patch is located in local-modifications-strict-args-fd88d16.diff.
diff --git a/tests/tests/os/jni/seccomp-tests/local-modifications-strict-args-fd88d16.diff b/tests/tests/os/jni/seccomp-tests/local-modifications-strict-args-fd88d16.diff
new file mode 100644
index 0000000..a289147
--- /dev/null
+++ b/tests/tests/os/jni/seccomp-tests/local-modifications-strict-args-fd88d16.diff
@@ -0,0 +1,102 @@
+diff --git a/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c b/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
+index 98b0231..3c238e6 100644
+--- a/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
++++ b/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
+@@ -28,6 +28,9 @@
+ #include <string.h>
+ #include <linux/elf.h>
+ #include <sys/uio.h>
++#include <fcntl.h> // ANDROID
++#include <sys/mman.h>
++#include <sys/times.h>
+
+ #define _GNU_SOURCE
+ #include <unistd.h>
+@@ -386,14 +389,16 @@ TEST_SIGNAL(KILL_one, SIGSYS) {
+ }
+
+ TEST_SIGNAL(KILL_one_arg_one, SIGSYS) {
++ void *fatal_address;
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
+ offsetof(struct seccomp_data, nr)),
+- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
++ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0),
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+ /* Only both with lower 32-bit for now. */
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)),
+- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1),
++ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
++ (unsigned long)&fatal_address, 0, 1),
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+ };
+@@ -403,23 +408,29 @@ TEST_SIGNAL(KILL_one_arg_one, SIGSYS) {
+ };
+ long ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ pid_t parent = getppid();
+- pid_t pid = getpid();
++ struct tms timebuf;
++ clock_t clock = times(&timebuf);
+ ASSERT_EQ(0, ret);
+
+ ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+ ASSERT_EQ(0, ret);
+
+ EXPECT_EQ(parent, syscall(__NR_getppid));
+- EXPECT_EQ(pid, syscall(__NR_getpid));
+- /* getpid() should never return. */
+- EXPECT_EQ(0, syscall(__NR_getpid, 0x0C0FFEE));
++ EXPECT_LE(clock, syscall(__NR_times, &timebuf));
++ /* times() should never return. */
++ EXPECT_EQ(0, syscall(__NR_times, &fatal_address));
+ }
+
+ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) {
++#ifndef __NR_mmap2
++ int sysno = __NR_mmap;
++#else
++ int sysno = __NR_mmap2;
++#endif
+ struct sock_filter filter[] = {
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
+ offsetof(struct seccomp_data, nr)),
+- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
++ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0),
+ BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
+ /* Only both with lower 32-bit for now. */
+ BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)),
+@@ -433,16 +444,29 @@ TEST_SIGNAL(KILL_one_arg_six, SIGSYS) {
+ };
+ long ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
+ pid_t parent = getppid();
+- pid_t pid = getpid();
++ int fd;
++ void *map1, *map2;
+ ASSERT_EQ(0, ret);
+
+ ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
+ ASSERT_EQ(0, ret);
+
++ fd = open("/dev/zero", O_RDONLY);
++ ASSERT_NE(-1, fd);
++
+ EXPECT_EQ(parent, syscall(__NR_getppid));
+- EXPECT_EQ(pid, syscall(__NR_getpid));
+- /* getpid() should never return. */
+- EXPECT_EQ(0, syscall(__NR_getpid, 1, 2, 3, 4, 5, 0x0C0FFEE));
++ map1 = (void *)syscall(sysno,
++ NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, PAGE_SIZE);
++ EXPECT_NE(MAP_FAILED, map1);
++ /* mmap2() should never return. */
++ map2 = (void *)syscall(sysno,
++ NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
++ EXPECT_EQ(MAP_FAILED, map2);
++
++ /* The test failed, so clean up the resources. */
++ munmap(map1, PAGE_SIZE);
++ munmap(map2, PAGE_SIZE);
++ close(fd);
+ }
+
+ /* TODO(wad) add 64-bit versus 32-bit arg tests. */
diff --git a/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c b/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
index 98b0231..3c238e6 100644
--- a/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
+++ b/tests/tests/os/jni/seccomp-tests/tests/seccomp_bpf_tests.c
@@ -28,6 +28,9 @@
#include <string.h>
#include <linux/elf.h>
#include <sys/uio.h>
+#include <fcntl.h> // ANDROID
+#include <sys/mman.h>
+#include <sys/times.h>
#define _GNU_SOURCE
#include <unistd.h>
@@ -386,14 +389,16 @@
}
TEST_SIGNAL(KILL_one_arg_one, SIGSYS) {
+ void *fatal_address;
struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
offsetof(struct seccomp_data, nr)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_times, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
/* Only both with lower 32-bit for now. */
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(0)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x0C0FFEE, 0, 1),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K,
+ (unsigned long)&fatal_address, 0, 1),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_KILL),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
};
@@ -403,23 +408,29 @@
};
long ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
pid_t parent = getppid();
- pid_t pid = getpid();
+ struct tms timebuf;
+ clock_t clock = times(&timebuf);
ASSERT_EQ(0, ret);
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
ASSERT_EQ(0, ret);
EXPECT_EQ(parent, syscall(__NR_getppid));
- EXPECT_EQ(pid, syscall(__NR_getpid));
- /* getpid() should never return. */
- EXPECT_EQ(0, syscall(__NR_getpid, 0x0C0FFEE));
+ EXPECT_LE(clock, syscall(__NR_times, &timebuf));
+ /* times() should never return. */
+ EXPECT_EQ(0, syscall(__NR_times, &fatal_address));
}
TEST_SIGNAL(KILL_one_arg_six, SIGSYS) {
+#ifndef __NR_mmap2
+ int sysno = __NR_mmap;
+#else
+ int sysno = __NR_mmap2;
+#endif
struct sock_filter filter[] = {
BPF_STMT(BPF_LD|BPF_W|BPF_ABS,
offsetof(struct seccomp_data, nr)),
- BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, __NR_getpid, 1, 0),
+ BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, sysno, 1, 0),
BPF_STMT(BPF_RET|BPF_K, SECCOMP_RET_ALLOW),
/* Only both with lower 32-bit for now. */
BPF_STMT(BPF_LD|BPF_W|BPF_ABS, syscall_arg(5)),
@@ -433,16 +444,29 @@
};
long ret = prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0);
pid_t parent = getppid();
- pid_t pid = getpid();
+ int fd;
+ void *map1, *map2;
ASSERT_EQ(0, ret);
ret = prctl(PR_SET_SECCOMP, SECCOMP_MODE_FILTER, &prog);
ASSERT_EQ(0, ret);
+ fd = open("/dev/zero", O_RDONLY);
+ ASSERT_NE(-1, fd);
+
EXPECT_EQ(parent, syscall(__NR_getppid));
- EXPECT_EQ(pid, syscall(__NR_getpid));
- /* getpid() should never return. */
- EXPECT_EQ(0, syscall(__NR_getpid, 1, 2, 3, 4, 5, 0x0C0FFEE));
+ map1 = (void *)syscall(sysno,
+ NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, PAGE_SIZE);
+ EXPECT_NE(MAP_FAILED, map1);
+ /* mmap2() should never return. */
+ map2 = (void *)syscall(sysno,
+ NULL, PAGE_SIZE, PROT_READ, MAP_PRIVATE, fd, 0x0C0FFEE);
+ EXPECT_EQ(MAP_FAILED, map2);
+
+ /* The test failed, so clean up the resources. */
+ munmap(map1, PAGE_SIZE);
+ munmap(map2, PAGE_SIZE);
+ close(fd);
}
/* TODO(wad) add 64-bit versus 32-bit arg tests. */
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index af60139..75ad865 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -29,7 +29,7 @@
private static final String LOG_TAG = "BuildVersionTest";
private static final Set<String> EXPECTED_RELEASES =
- new HashSet<String>(Arrays.asList("6.0"));
+ new HashSet<String>(Arrays.asList("6.0.1", "6.0"));
private static final int EXPECTED_SDK = 23;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_TAG = "release-keys";
diff --git a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
index 480b98d..7096757 100644
--- a/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/FileSystemPermissionTest.java
@@ -263,6 +263,20 @@
}
@MediumTest
+ public void testProcSelfPagemapNotAccessible() {
+ // Note: can't use f.canRead() here, since the security check is done
+ // during the open() process. access(R_OK) return OK even through
+ // open() eventually fails.
+ try {
+ new FileInputStream("/proc/self/pagemap");
+ fail("Device is missing the following kernel security patch: "
+ + "https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=ab676b7d6fbf4b294bf198fb27ade5b0e865c7ce");
+ } catch (FileNotFoundException e) {
+ // expected
+ }
+ }
+
+ @MediumTest
public void testTcpDefaultRwndSane() throws Exception {
File f = new File("/proc/sys/net/ipv4/tcp_default_init_rwnd");
assertTrue(f.canRead());
@@ -786,8 +800,10 @@
new File("/dev/binder"),
new File("/dev/card0"), // b/13159510
new File("/dev/renderD128"),
+ new File("/dev/renderD129"), // b/23798677
new File("/dev/dri/card0"), // b/13159510
new File("/dev/dri/renderD128"),
+ new File("/dev/dri/renderD129"), // b/23798677
new File("/dev/felica"), // b/11142586
new File("/dev/felica_ant"), // b/11142586
new File("/dev/felica_cen"), // b/11142586
diff --git a/tests/tests/print/Android.mk b/tests/tests/print/Android.mk
index 26e0d24..211b5ee 100644
--- a/tests/tests/print/Android.mk
+++ b/tests/tests/print/Android.mk
@@ -29,6 +29,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := mockito-target ctstestrunner ub-uiautomator ctsdeviceutil
-LOCAL_SDK_VERSION := current
+LOCAL_SDK_VERSION := test_current
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/print/src/android/print/cts/BasePrintTest.java b/tests/tests/print/src/android/print/cts/BasePrintTest.java
index c4dd026..dc69dad 100644
--- a/tests/tests/print/src/android/print/cts/BasePrintTest.java
+++ b/tests/tests/print/src/android/print/cts/BasePrintTest.java
@@ -41,15 +41,14 @@
import android.print.PrintDocumentAdapter.WriteResultCallback;
import android.print.PrintManager;
import android.print.PrinterId;
-import android.print.cts.services.FirstPrintService;
import android.print.cts.services.PrintServiceCallbacks;
import android.print.cts.services.PrinterDiscoverySessionCallbacks;
-import android.print.cts.services.SecondPrintService;
import android.print.cts.services.StubbablePrinterDiscoverySession;
import android.print.pdf.PrintedPdfDocument;
import android.printservice.PrintJob;
import android.printservice.PrintService;
import android.support.test.uiautomator.UiAutomatorTestCase;
+import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject;
import android.support.test.uiautomator.UiObjectNotFoundException;
import android.support.test.uiautomator.UiSelector;
@@ -139,6 +138,14 @@
}
@Override
+ protected void runTest() throws Throwable {
+ // Do nothing if the device does not support printing.
+ if (supportsPrinting()) {
+ super.runTest();
+ }
+ }
+
+ @Override
public void setUp() throws Exception {
super.setUp();
if (!supportsPrinting()) {
@@ -147,7 +154,6 @@
// Make sure we start with a clean slate.
clearPrintSpoolerData();
- enablePrintServices();
disableImes();
// Workaround for dexmaker bug: https://code.google.com/p/dexmaker/issues/detail?id=2
@@ -181,40 +187,46 @@
@Override
public void tearDown() throws Exception {
- if (supportsPrinting()) {
- // Done with the activity.
- getActivity().finish();
- enableImes();
-
- // Restore the locale if needed.
- if (mOldLocale != null) {
- Resources resources = getInstrumentation().getTargetContext().getResources();
- DisplayMetrics displayMetrics = resources.getDisplayMetrics();
- Configuration newConfiguration = new Configuration(resources.getConfiguration());
- newConfiguration.locale = mOldLocale;
- mOldLocale = null;
- resources.updateConfiguration(newConfiguration, displayMetrics);
- }
-
- disablePrintServices();
- // Make sure the spooler is cleaned.
- clearPrintSpoolerData();
+ if (!supportsPrinting()) {
+ return;
}
+
+ // Done with the activity.
+ getActivity().finish();
+ enableImes();
+
+ // Restore the locale if needed.
+ if (mOldLocale != null) {
+ Resources resources = getInstrumentation().getTargetContext().getResources();
+ DisplayMetrics displayMetrics = resources.getDisplayMetrics();
+ Configuration newConfiguration = new Configuration(resources.getConfiguration());
+ newConfiguration.locale = mOldLocale;
+ mOldLocale = null;
+ resources.updateConfiguration(newConfiguration, displayMetrics);
+ }
+
+ // Make sure the spooler is cleaned, this also un-approves all services
+ clearPrintSpoolerData();
+
super.tearDown();
}
- protected void print(final PrintDocumentAdapter adapter) {
+ protected void print(final PrintDocumentAdapter adapter, final PrintAttributes attributes) {
// Initiate printing as if coming from the app.
getInstrumentation().runOnMainSync(new Runnable() {
@Override
public void run() {
PrintManager printManager = (PrintManager) getActivity()
.getSystemService(Context.PRINT_SERVICE);
- printManager.print("Print job", adapter, null);
+ printManager.print("Print job", adapter, attributes);
}
});
}
+ protected void print(PrintDocumentAdapter adapter) {
+ print(adapter, null);
+ }
+
protected void onCancelOperationCalled() {
mCancelOperationCounter.call();
}
@@ -293,6 +305,17 @@
}
}
+ protected void answerPrintServicesWarning(boolean confirm) throws UiObjectNotFoundException {
+ UiDevice uiDevice = UiDevice.getInstance(getInstrumentation());
+ UiObject button;
+ if (confirm) {
+ button = uiDevice.findObject(new UiSelector().resourceId("android:id/button1"));
+ } else {
+ button = uiDevice.findObject(new UiSelector().resourceId("android:id/button2"));
+ }
+ button.click();
+ }
+
protected void changeOrientation(String orientation) throws UiObjectNotFoundException {
try {
UiObject orientationSpinner = new UiObject(new UiSelector().resourceId(
@@ -366,7 +389,7 @@
return mActivity;
}
- private void createActivity() {
+ protected void createActivity() {
mActivity = launchActivity(
getInstrumentation().getTargetContext().getPackageName(),
PrintDocumentActivity.class, null);
@@ -385,20 +408,6 @@
.contains(PM_CLEAR_SUCCESS_OUTPUT));
}
- private void enablePrintServices() throws Exception {
- String pkgName = getInstrumentation().getContext().getPackageName();
- String enabledServicesValue = String.format("%s/%s:%s/%s",
- pkgName, FirstPrintService.class.getCanonicalName(),
- pkgName, SecondPrintService.class.getCanonicalName());
- SystemUtil.runShellCommand(getInstrumentation(),
- "settings put secure enabled_print_services " + enabledServicesValue);
- }
-
- private void disablePrintServices() throws Exception {
- SystemUtil.runShellCommand(getInstrumentation(),
- "settings put secure enabled_print_services \"\"");
- }
-
protected void verifyLayoutCall(InOrder inOrder, PrintDocumentAdapter mock,
PrintAttributes oldAttributes, PrintAttributes newAttributes,
final boolean forPreview) {
diff --git a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
index b9fd50a..17897dd 100644
--- a/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
+++ b/tests/tests/print/src/android/print/cts/PageRangeAdjustmentTest.java
@@ -146,6 +146,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for finish.
waitForAdapterFinishCallbackCalled();
@@ -258,6 +261,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for finish.
waitForAdapterFinishCallbackCalled();
@@ -386,6 +392,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for finish.
waitForAdapterFinishCallbackCalled();
@@ -598,6 +607,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for finish.
waitForAdapterFinishCallbackCalled();
diff --git a/tests/tests/print/src/android/print/cts/PrintAttributesTest.java b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
new file mode 100644
index 0000000..a50c977
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintAttributesTest.java
@@ -0,0 +1,651 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.print.cts;
+
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.printservice.PrintJob;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Test that the print attributes are correctly propagated through the print framework
+ */
+public class PrintAttributesTest extends BasePrintTest {
+ private final String PRINTER_NAME = "Test printer";
+
+ private final Margins[] MIN_MARGINS = {
+ new Margins(0, 0, 0, 0), new Margins(10, 10, 10, 10), new Margins(20, 20, 20, 20),
+ };
+
+ private final MediaSize MEDIA_SIZES[] = {
+ MediaSize.ISO_A3, MediaSize.ISO_A4, MediaSize.ISO_A5
+ };
+
+ private final int COLOR_MODES[] = {
+ PrintAttributes.COLOR_MODE_MONOCHROME, PrintAttributes.COLOR_MODE_COLOR
+ };
+
+ private final int DUPLEX_MODES[] = {
+ PrintAttributes.DUPLEX_MODE_NONE, PrintAttributes.DUPLEX_MODE_LONG_EDGE,
+ PrintAttributes.DUPLEX_MODE_SHORT_EDGE
+ };
+
+ private final Resolution RESOLUTIONS[] = {
+ new Resolution("300x300", "300x300", 300, 300),
+ new Resolution("600x600", "600x600", 600, 600),
+ new Resolution("1200x1200", "1200x1200", 1200, 1200)
+ };
+
+ /**
+ * Stores the {@link PrintAttributes} passed to the layout method
+ */
+ private PrintAttributes mLayoutAttributes;
+
+ /**
+ * Create a new {@link PrintAttributes} object with the given properties.
+ *
+ * All properties can be null/0 to remain unset.
+ *
+ * @param mediaSize {@link MediaSize} to use
+ * @param colorMode Color mode to use
+ * @param duplexMode Duplex mode to use
+ * @param resolution {@link Resolution} to use
+ *
+ * @return The newly created object or null if no properties are set
+ */
+ private PrintAttributes createAttributes(MediaSize mediaSize, int colorMode, int duplexMode,
+ Resolution resolution) {
+ if (mediaSize == null && colorMode == 0 && duplexMode == 0 && resolution == null) {
+ return null;
+ }
+
+ PrintAttributes.Builder builder = new PrintAttributes.Builder();
+
+ if (mediaSize != null) {
+ builder.setMediaSize(mediaSize);
+ }
+
+ if (colorMode != 0) {
+ builder.setColorMode(colorMode);
+ }
+
+ if (duplexMode != 0) {
+ builder.setDuplexMode(duplexMode);
+ }
+
+ if (resolution != null) {
+ builder.setResolution(resolution);
+ }
+
+ return builder.build();
+ }
+
+ /**
+ * Make {@link #PRINTER_NAME} the default printer by adding it to the history of printers by
+ * printing once.
+ *
+ * @param adapter The {@link PrintDocumentAdapter} used
+ *
+ * @throws UiObjectNotFoundException If any UI element needed for this operation does not
+ * appear
+ */
+ private void makeDefaultPrinter(PrintDocumentAdapter adapter)
+ throws UiObjectNotFoundException {
+ // Perform a full print operation on the printer
+ print(adapter);
+ selectPrinter(PRINTER_NAME);
+ clickPrintButton();
+ answerPrintServicesWarning(true);
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+ // Switch to new activity, which should now use the default printer
+ getActivity().finish();
+ createActivity();
+ }
+
+ /**
+ * Create {@link PrinterDiscoverySessionCallbacks} with a single printer that has the given
+ * capabilities
+ *
+ * @param minMargins The minMargins of the printer
+ * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+ * @param defaultMediaSize The default {@link MediaSize}
+ * @param colorModes The color modes supported by the printer
+ * @param defaultColorMode The default color mode
+ * @param duplexModes The duplex modes supported by the printer
+ * @param defaultDuplexMode The default duplex mode
+ * @param resolutions The {@link Resolution resolutions} supported by the printer
+ * @param defaultResolution The default {@link Resolution} to use
+ *
+ * @return New {@link PrinterDiscoverySessionCallbacks} with a single printer that has the
+ * given capabilities
+ */
+ private PrinterDiscoverySessionCallbacks createMockPrinterDiscoverySessionCallbacks(
+ final Margins minMargins, final MediaSize mediaSizes[],
+ final MediaSize defaultMediaSize, final int colorModes[], final int defaultColorMode,
+ final int duplexModes[], final int defaultDuplexMode, final Resolution resolutions[],
+ final Resolution defaultResolution) {
+ return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ StubbablePrinterDiscoverySession session =
+ ((PrinterDiscoverySessionCallbacks) invocation.getMock()).getSession();
+
+ if (session.getPrinters().isEmpty()) {
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+ PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+
+ PrinterCapabilitiesInfo.Builder builder =
+ new PrinterCapabilitiesInfo.Builder(printerId);
+
+ builder.setMinMargins(minMargins);
+
+ int mediaSizesLength = mediaSizes.length;
+ for (int i = 0; i < mediaSizesLength; i++) {
+ if (mediaSizes[i].equals(defaultMediaSize)) {
+ builder.addMediaSize(mediaSizes[i], true);
+ } else {
+ builder.addMediaSize(mediaSizes[i], false);
+ }
+ }
+
+ int colorModesMask = 0;
+ int colorModesLength = colorModes.length;
+ for (int i = 0; i < colorModesLength; i++) {
+ colorModesMask |= colorModes[i];
+ }
+ builder.setColorModes(colorModesMask, defaultColorMode);
+
+ int duplexModesMask = 0;
+ int duplexModeLength = duplexModes.length;
+ for (int i = 0; i < duplexModeLength; i++) {
+ duplexModesMask |= duplexModes[i];
+ }
+ builder.setDuplexModes(duplexModesMask, defaultDuplexMode);
+
+ int resolutionsLength = resolutions.length;
+ for (int i = 0; i < resolutionsLength; i++) {
+ if (resolutions[i].equals(defaultResolution)) {
+ builder.addResolution(resolutions[i], true);
+ } else {
+ builder.addResolution(resolutions[i], false);
+ }
+ }
+
+ PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
+ PrinterInfo.STATUS_IDLE).setCapabilities(builder.build()).build();
+ printers.add(printer);
+
+ session.addPrinters(printers);
+ }
+ return null;
+ }
+ }, null, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ return null;
+ }
+ }, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Take a note onDestroy was called.
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Create dummy {@link PrintServiceCallbacks}
+ *
+ * This is needed to as the print framework is trying to talk to any printer even if is not set
+ * up.
+ *
+ * @return Dummy {@link PrintServiceCallbacks}
+ */
+ private PrintServiceCallbacks createDummyMockPrintServiceCallbacks() {
+ return createMockPrintServiceCallbacks(null, null, null);
+ }
+
+ /**
+ * Create a {@link PrintDocumentAdapter} that serves empty pages
+ *
+ * @return A new {@link PrintDocumentAdapter}
+ */
+ private PrintDocumentAdapter createMockPrintDocumentAdapter() {
+ return createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ mLayoutAttributes = (PrintAttributes) invocation.getArguments()[1];
+ LayoutResultCallback callback =
+ (LayoutResultCallback) invocation.getArguments()[3];
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(1)
+ .build();
+ callback.onLayoutFinished(info, false);
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+ writeBlankPages(mLayoutAttributes, fd, pages[0].getStart(),
+ pages[0].getEnd());
+ fd.close();
+ callback.onWriteFinished(pages);
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Set up a single printer with the given capabilities
+ *
+ * @param minMargins The minMargins of the printer
+ * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+ * @param defaultMediaSize The default {@link MediaSize}
+ * @param colorModes The color modes supported by the printer
+ * @param defaultColorMode The default color mode
+ * @param duplexModes The duplex modes supported by the printer
+ * @param defaultDuplexMode The default duplex mode
+ * @param resolutions The {@link Resolution resolutions} supported by the printer
+ * @param defaultResolution The default {@link Resolution} to use
+ *
+ * @return A {@link PrintDocumentAdapter} that can be used for the new printer
+ */
+ private PrintDocumentAdapter setUpPrinter(Margins minMargins, MediaSize mediaSizes[],
+ MediaSize defaultMediaSize, int colorModes[], int defaultColorMode, int duplexModes[],
+ int defaultDuplexMode, Resolution resolutions[], Resolution defaultResolution) {
+ final PrinterDiscoverySessionCallbacks sessionCallbacks =
+ createMockPrinterDiscoverySessionCallbacks(minMargins, mediaSizes,
+ defaultMediaSize, colorModes, defaultColorMode, duplexModes,
+ defaultDuplexMode, resolutions, defaultResolution);
+
+ PrintServiceCallbacks serviceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return sessionCallbacks;
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ // We pretend the job is handled immediately.
+ printJob.complete();
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(serviceCallbacks);
+
+ // We need to set up the second print service too, otherwise we get a null pointer in the
+ // print framework
+ SecondPrintService.setCallbacks(createDummyMockPrintServiceCallbacks());
+
+ // Create a print adapter that respects the print contract.
+ return createMockPrintDocumentAdapter();
+ }
+
+ /**
+ * Check if a value is in an array.
+ *
+ * To be use instead of Arrays.asList(array).contains(value) for ints.
+ *
+ * @param array The array the value might be in
+ * @param value The value to search for
+ *
+ * @return true iff the value is in the array
+ */
+ private boolean isInArray(final int array[], int value) {
+ int arrayLength = array.length;
+ for (int i = 0; i < arrayLength; i++) {
+ if (array[i] == value) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Flexible base test for all print attribute tests.
+ *
+ * Asserts that the default and suggested attributes are properly honored by the print
+ * framework.
+ *
+ * @param minMargins The minMargins of the printer
+ * @param mediaSizes The {@link MediaSize media sizes} supported by the printer
+ * @param defaultMediaSize The default {@link MediaSize}
+ * @param colorModes The color modes supported by the printer
+ * @param defaultColorMode The default color mode
+ * @param duplexModes The duplex modes supported by the printer
+ * @param defaultDuplexMode The default duplex mode
+ * @param resolutions The {@link Resolution resolutions} supported by the printer
+ * @param defaultResolution The default {@link Resolution} to use
+ * @param suggestedMediaSize The suggested {@link MediaSize} for the print job
+ * @param suggestedColorMode The suggested color mode for the print job
+ * @param suggestedDuplexMode The suggested duplex mode for the print job
+ * @param suggestedResolution The suggested resolution for the print job
+ *
+ * @throws Exception If anything is unexpected
+ */
+ private void baseTest(Margins minMargins, MediaSize mediaSizes[],
+ MediaSize defaultMediaSize, MediaSize suggestedMediaSize, int colorModes[],
+ int defaultColorMode, int suggestedColorMode, int duplexModes[],
+ int defaultDuplexMode, int suggestedDuplexMode, Resolution resolutions[],
+ Resolution defaultResolution, Resolution suggestedResolution) throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+
+ // Set up printer with supported and default attributes
+ PrintDocumentAdapter adapter =
+ setUpPrinter(minMargins, mediaSizes, defaultMediaSize, colorModes, defaultColorMode,
+ duplexModes, defaultDuplexMode, resolutions, defaultResolution);
+
+ // Make printer default. This is necessary as a different default printer might pre-select
+ // its default attributes and thereby overrides the defaults of the tested printer.
+ makeDefaultPrinter(adapter);
+
+ // Select suggested attributes
+ PrintAttributes suggestedAttributes = createAttributes(suggestedMediaSize,
+ suggestedColorMode, suggestedDuplexMode, suggestedResolution);
+
+ // Start print action and wait for layout, the result is stored in #layoutAttributes,
+ // @see createMockPrintDocumentAdapter
+ print(adapter, suggestedAttributes);
+ waitForWriteAdapterCallback();
+ clickPrintButton();
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+ // It does not make sense to suggest minMargins, hence the print framework always picks
+ // the one set up for the printer.
+ assertEquals("Min margins not as expected", minMargins, mLayoutAttributes.getMinMargins());
+
+ // Verify that the attributes are honored properly
+ if (suggestedMediaSize != null && Arrays.asList(mediaSizes).contains(suggestedMediaSize)) {
+ assertEquals("Media size not as suggested", suggestedMediaSize,
+ mLayoutAttributes.getMediaSize());
+ } else {
+ assertEquals("Media size not default", defaultMediaSize,
+ mLayoutAttributes.getMediaSize());
+ }
+
+ if (suggestedColorMode != 0 && isInArray(colorModes, suggestedColorMode)) {
+ assertEquals("Color mode not as suggested", suggestedColorMode,
+ mLayoutAttributes.getColorMode());
+ } else {
+ assertEquals("Color mode not default", defaultColorMode,
+ mLayoutAttributes.getColorMode());
+ }
+
+ if (suggestedDuplexMode != 0 && isInArray(duplexModes, suggestedDuplexMode)) {
+ assertEquals("Duplex mode not as suggested", suggestedDuplexMode,
+ mLayoutAttributes.getDuplexMode());
+ } else {
+ assertEquals("Duplex mode not default", defaultDuplexMode,
+ mLayoutAttributes.getDuplexMode());
+ }
+
+ if (suggestedResolution != null
+ && Arrays.asList(resolutions).contains(suggestedResolution)) {
+ assertEquals("Resolution not as suggested", suggestedResolution,
+ mLayoutAttributes.getResolution());
+ } else {
+ assertEquals("Resolution not default", defaultResolution,
+ mLayoutAttributes.getResolution());
+ }
+ }
+
+ /**
+ * Test that attributes are as expected if the default attributes match the suggested ones.
+ *
+ * This test sets the default and suggested attributes to the first selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testDefaultMatchesSuggested0() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ MEDIA_SIZES, MEDIA_SIZES[0], MEDIA_SIZES[0],
+ COLOR_MODES, COLOR_MODES[0], COLOR_MODES[0],
+ DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[0],
+ RESOLUTIONS, RESOLUTIONS[0], RESOLUTIONS[0]);
+ }
+
+ /**
+ * Test that attributes are as expected if the default attributes match the suggested ones.
+ *
+ * This test sets the default and suggested attributes to the second selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testDefaultMatchesSuggested1() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[1],
+ MEDIA_SIZES, MEDIA_SIZES[1], MEDIA_SIZES[1],
+ COLOR_MODES, COLOR_MODES[1], COLOR_MODES[1],
+ DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[1],
+ RESOLUTIONS, RESOLUTIONS[1], RESOLUTIONS[1]);
+ }
+
+ /**
+ * Test that attributes are as expected if the default attributes match the suggested ones.
+ *
+ * This test sets the default and suggested attributes to the third selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testDefaultMatchesSuggested2() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[2],
+ MEDIA_SIZES, MEDIA_SIZES[2], MEDIA_SIZES[2],
+ // There are only two color modes, hence pick [1]
+ COLOR_MODES, COLOR_MODES[1], COLOR_MODES[1],
+ DUPLEX_MODES, DUPLEX_MODES[2], DUPLEX_MODES[2],
+ RESOLUTIONS, RESOLUTIONS[2], RESOLUTIONS[2]);
+ }
+
+ /**
+ * Test that attributes are as expected if the no suggestion is given.
+ *
+ * This test sets the default attributes to the first selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testNoSuggestion0() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ MEDIA_SIZES, MEDIA_SIZES[0], null,
+ COLOR_MODES, COLOR_MODES[0], 0,
+ DUPLEX_MODES, DUPLEX_MODES[0], 0,
+ RESOLUTIONS, RESOLUTIONS[0], null);
+ }
+
+ /**
+ * Test that attributes are as expected if the no suggestion is given.
+ *
+ * This test sets the default attributes to the second selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testNoSuggestion1() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[1],
+ MEDIA_SIZES, MEDIA_SIZES[1], null,
+ COLOR_MODES, COLOR_MODES[1], 0,
+ DUPLEX_MODES, DUPLEX_MODES[1], 0,
+ RESOLUTIONS, RESOLUTIONS[1], null);
+ }
+
+ /**
+ * Test that attributes are as expected if the no suggestion is given.
+ *
+ * This test sets the default attributes to the third selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testNoSuggestion2() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[2],
+ MEDIA_SIZES, MEDIA_SIZES[2], null,
+ // There are only two color modes, hence pick [1]
+ COLOR_MODES, COLOR_MODES[1], 0,
+ DUPLEX_MODES, DUPLEX_MODES[2], 0,
+ RESOLUTIONS, RESOLUTIONS[2], null);
+ }
+
+ /**
+ * Test that attributes are as expected if only the {@link MediaSize} is suggested.
+ *
+ * This test sets the default attributes to the first selection, but the {@link MediaSize} is
+ * suggested to be the second selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testMediaSizeSuggestion0() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ MEDIA_SIZES, MEDIA_SIZES[0], MEDIA_SIZES[1],
+ COLOR_MODES, COLOR_MODES[0], 0,
+ DUPLEX_MODES, DUPLEX_MODES[0], 0,
+ RESOLUTIONS, RESOLUTIONS[0], null);
+ }
+
+ /**
+ * Test that attributes are as expected if only the {@link MediaSize} is suggested.
+ *
+ * This test sets the default attributes to the second selection, but the {@link MediaSize} is
+ * suggested to be the first selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testMediaSizeSuggestion1() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[1],
+ MEDIA_SIZES, MEDIA_SIZES[1], MEDIA_SIZES[0],
+ COLOR_MODES, COLOR_MODES[1], 0,
+ DUPLEX_MODES, DUPLEX_MODES[1], 0,
+ RESOLUTIONS, RESOLUTIONS[1], null);
+ }
+
+ /**
+ * Test that attributes are as expected if only the duplex mode is suggested.
+ *
+ * This test sets the default attributes to the first selection, but the duplex mode is
+ * suggested to be the second selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testDuplexModeSuggestion0() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ MEDIA_SIZES, MEDIA_SIZES[0], null,
+ COLOR_MODES, COLOR_MODES[0], 0,
+ DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
+ RESOLUTIONS, RESOLUTIONS[0], null);
+ }
+
+ /**
+ * Test that attributes are as expected if only the duplex mode is suggested.
+ *
+ * This test sets the default attributes to the second selection, but the duplex mode is
+ * suggested to be the first selection.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testDuplexModeSuggestion1() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[1],
+ MEDIA_SIZES, MEDIA_SIZES[1], null,
+ COLOR_MODES, COLOR_MODES[1], 0,
+ DUPLEX_MODES, DUPLEX_MODES[1], DUPLEX_MODES[0],
+ RESOLUTIONS, RESOLUTIONS[1], null);
+ }
+
+ /**
+ * Test that attributes are as expected if all attributes are suggested and different from the
+ * default attributes.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testSuggestedDifferentFromDefault() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ MEDIA_SIZES, MEDIA_SIZES[0], MEDIA_SIZES[1],
+ COLOR_MODES, COLOR_MODES[0], COLOR_MODES[1],
+ DUPLEX_MODES, DUPLEX_MODES[0], DUPLEX_MODES[1],
+ RESOLUTIONS, RESOLUTIONS[0], RESOLUTIONS[1]);
+ }
+
+ /**
+ * Test that attributes are as expected if all attributes are suggested but all of them are not
+ * supported by the printer.
+ *
+ * @throws Exception If anything is unexpected
+ */
+ public void testIllegalSuggested() throws Exception {
+ // available default suggestion
+ baseTest( MIN_MARGINS[0],
+ Arrays.copyOfRange(MEDIA_SIZES, 0, 1), MEDIA_SIZES[0], MEDIA_SIZES[1],
+ Arrays.copyOfRange(COLOR_MODES, 0, 1), COLOR_MODES[0], COLOR_MODES[1],
+ Arrays.copyOfRange(DUPLEX_MODES, 0, 1), DUPLEX_MODES[0], DUPLEX_MODES[1],
+ Arrays.copyOfRange(RESOLUTIONS, 0, 1), RESOLUTIONS[0], RESOLUTIONS[1]);
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
index 9f1e3a5..4811194 100644
--- a/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
+++ b/tests/tests/print/src/android/print/cts/PrintDocumentAdapterContractTest.java
@@ -122,6 +122,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for finish.
waitForAdapterFinishCallbackCalled();
@@ -142,6 +145,7 @@
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS)
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -256,6 +260,7 @@
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS)
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -363,6 +368,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for a finish.
waitForAdapterFinishCallbackCalled();
@@ -383,6 +391,7 @@
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS)
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -552,6 +561,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for a finish.
waitForAdapterFinishCallbackCalled();
@@ -572,6 +584,7 @@
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS)
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -613,6 +626,7 @@
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(new Margins(200, 200, 200, 200))
.setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, fourthOldAttributes, fourthNewAttributes, true);
@@ -699,6 +713,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for a finish.
waitForAdapterFinishCallbackCalled();
@@ -718,6 +735,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -823,6 +841,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for a finish.
waitForAdapterFinishCallbackCalled();
@@ -842,6 +863,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -932,6 +954,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for a finish.
waitForAdapterFinishCallbackCalled();
@@ -951,6 +976,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1058,6 +1084,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1152,6 +1179,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1224,6 +1252,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1306,6 +1335,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1398,6 +1428,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1469,6 +1500,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
@@ -1548,6 +1580,7 @@
.setMediaSize(MediaSize.NA_LETTER)
.setResolution(new Resolution("PDF resolution", "PDF resolution", 300, 300))
.setMinMargins(Margins.NO_MARGINS).setColorMode(PrintAttributes.COLOR_MODE_COLOR)
+ .setDuplexMode(PrintAttributes.DUPLEX_MODE_NONE)
.build();
verifyLayoutCall(inOrder, adapter, firstOldAttributes, firstNewAttributes, true);
diff --git a/tests/tests/print/src/android/print/cts/PrintServicesTest.java b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
new file mode 100644
index 0000000..9476d05
--- /dev/null
+++ b/tests/tests/print/src/android/print/cts/PrintServicesTest.java
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.print.cts;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.print.PageRange;
+import android.print.PrintAttributes;
+import android.print.PrintDocumentAdapter;
+import android.print.PrintDocumentInfo;
+import android.print.PrinterCapabilitiesInfo;
+import android.print.PrinterId;
+import android.print.PrinterInfo;
+import android.print.cts.services.FirstPrintService;
+import android.print.cts.services.PrintServiceCallbacks;
+import android.print.cts.services.PrinterDiscoverySessionCallbacks;
+import android.print.cts.services.SecondPrintService;
+import android.print.cts.services.StubbablePrinterDiscoverySession;
+import android.print.PrintAttributes.Margins;
+import android.print.PrintAttributes.MediaSize;
+import android.print.PrintAttributes.Resolution;
+import android.print.PrintDocumentAdapter.LayoutResultCallback;
+import android.print.PrintDocumentAdapter.WriteResultCallback;
+import android.printservice.PrintJob;
+
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * Test the interface from a print service to the print manager
+ */
+public class PrintServicesTest extends BasePrintTest {
+ private static final String PRINTER_NAME = "Test printer";
+ private static final int NUM_PAGES = 2;
+
+ /** The print job processed in the test */
+ private static PrintJob mPrintJob;
+
+ /** The current progress of #mPrintJob once read from the system */
+ private static float mPrintProgress;
+
+ /** The current status of #mPrintJob once read from the system */
+ private static CharSequence mPrintStatus;
+
+ /**
+ * Create a mock {@link PrintDocumentAdapter} that provides {@link #NUM_PAGES} empty pages.
+ *
+ * @return The mock adapter
+ */
+ private PrintDocumentAdapter createMockPrintDocumentAdapter() {
+ final PrintAttributes[] printAttributes = new PrintAttributes[1];
+
+ return createMockPrintDocumentAdapter(
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ printAttributes[0] = (PrintAttributes) invocation.getArguments()[1];
+ LayoutResultCallback callback = (LayoutResultCallback) invocation
+ .getArguments()[3];
+
+ PrintDocumentInfo info = new PrintDocumentInfo.Builder(PRINT_JOB_NAME)
+ .setContentType(PrintDocumentInfo.CONTENT_TYPE_DOCUMENT)
+ .setPageCount(NUM_PAGES)
+ .build();
+
+ callback.onLayoutFinished(info, false);
+
+ // Mark layout was called.
+ onLayoutCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ Object[] args = invocation.getArguments();
+ PageRange[] pages = (PageRange[]) args[0];
+ ParcelFileDescriptor fd = (ParcelFileDescriptor) args[1];
+ WriteResultCallback callback = (WriteResultCallback) args[3];
+
+ writeBlankPages(printAttributes[0], fd, pages[0].getStart(),
+ pages[0].getEnd());
+ fd.close();
+ callback.onWriteFinished(pages);
+
+ // Mark write was called.
+ onWriteCalled();
+ return null;
+ }
+ }, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Mark finish was called.
+ onFinishCalled();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Create a mock {@link PrinterDiscoverySessionCallbacks} that discovers a single printer with
+ * minimal capabilities.
+ *
+ * @return The mock session callbacks
+ */
+ private PrinterDiscoverySessionCallbacks createFirstMockPrinterDiscoverySessionCallbacks() {
+ return createMockPrinterDiscoverySessionCallbacks(new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ // Get the session.
+ StubbablePrinterDiscoverySession session = ((PrinterDiscoverySessionCallbacks) invocation
+ .getMock()).getSession();
+
+ if (session.getPrinters().isEmpty()) {
+ List<PrinterInfo> printers = new ArrayList<PrinterInfo>();
+
+ // Add the printer.
+ PrinterId printerId = session.getService().generatePrinterId(PRINTER_NAME);
+
+ PrinterCapabilitiesInfo capabilities = new PrinterCapabilitiesInfo.Builder(
+ printerId)
+ .setMinMargins(new Margins(200, 200, 200, 200))
+ .addMediaSize(MediaSize.ISO_A4, true)
+ .addResolution(new Resolution("300x300", "300x300", 300, 300),
+ true)
+ .setColorModes(PrintAttributes.COLOR_MODE_COLOR,
+ PrintAttributes.COLOR_MODE_COLOR)
+ .build();
+
+ PrinterInfo printer = new PrinterInfo.Builder(printerId, PRINTER_NAME,
+ PrinterInfo.STATUS_IDLE)
+ .setCapabilities(capabilities)
+ .build();
+ printers.add(printer);
+
+ session.addPrinters(printers);
+ }
+ return null;
+ }
+ }, null, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ return null;
+ }
+ }, null, new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) throws Throwable {
+ // Take a note onDestroy was called.
+ onPrinterDiscoverySessionDestroyCalled();
+ return null;
+ }
+ });
+ }
+
+ /**
+ * Get the current progress of #mPrintJob
+ *
+ * @return The current progress
+ * @throws InterruptedException
+ */
+ private float getProgress() throws InterruptedException {
+ final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+ synchronized (synchronizer) {
+ Runnable getter = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (synchronizer) {
+ mPrintProgress = mPrintJob.getInfo().getProgress();
+
+ synchronizer.notify();
+ }
+ }
+ };
+
+ (new Handler(Looper.getMainLooper())).post(getter);
+
+ synchronizer.wait();
+ }
+
+ return mPrintProgress;
+ }
+
+ /**
+ * Get the current status of #mPrintJob
+ *
+ * @return The current status
+ * @throws InterruptedException
+ */
+ private CharSequence getStatus() throws InterruptedException {
+ final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+ synchronized (synchronizer) {
+ Runnable getter = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (synchronizer) {
+ mPrintStatus = mPrintJob.getInfo().getStatus();
+
+ synchronizer.notify();
+ }
+ }
+ };
+
+ (new Handler(Looper.getMainLooper())).post(getter);
+
+ synchronizer.wait();
+ }
+
+ return mPrintStatus;
+ }
+
+ /**
+ * Check if a print progress is correct.
+ *
+ * @param desiredProgress The expected @{link PrintProgresses}
+ * @throws Exception If anything goes wrong or this takes more than 5 seconds
+ */
+ private void checkNotification(float desiredProgress,
+ CharSequence desiredStatus) throws Exception {
+ final long TIMEOUT = 5000;
+ final Date start = new Date();
+
+ while ((new Date()).getTime() - start.getTime() < TIMEOUT) {
+ if (desiredProgress == getProgress()
+ && desiredStatus.toString().equals(getStatus().toString())) {
+ return;
+ }
+
+ Thread.sleep(200);
+ }
+
+ throw new TimeoutException("Progress or status not updated in " + TIMEOUT + " ms");
+ }
+
+ /**
+ * Set a new progress and status for #mPrintJob
+ *
+ * @param progress The new progress to set
+ * @param status The new status to set
+ * @throws InterruptedException
+ */
+ private void setProgressAndStatus(final float progress, final CharSequence status)
+ throws InterruptedException {
+ final PrintServicesTest synchronizer = PrintServicesTest.this;
+
+ synchronized (synchronizer) {
+ Runnable completer = new Runnable() {
+ @Override
+ public void run() {
+ synchronized (synchronizer) {
+ mPrintJob.setProgress(progress);
+ mPrintJob.setStatus(status);
+
+ synchronizer.notify();
+ }
+ }
+ };
+
+ (new Handler(Looper.getMainLooper())).post(completer);
+
+ synchronizer.wait();
+ }
+ }
+
+ /**
+ * Progress print job and check the print job state.
+ *
+ * @param progress How much to progress
+ * @param status The status to set
+ * @throws Exception If anything goes wrong.
+ */
+ private void progress(float progress, CharSequence status) throws Exception {
+ setProgressAndStatus(progress, status);
+
+ // Check that progress of job is correct
+ checkNotification(progress, status);
+ }
+
+ /**
+ * Test that the progress and status is propagated correctly.
+ *
+ * @throws Exception If anything is unexpected.
+ */
+ public void testProgress()
+ throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+ // Create the session callbacks that we will be checking.
+ final PrinterDiscoverySessionCallbacks sessionCallbacks = createFirstMockPrinterDiscoverySessionCallbacks();
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks serviceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return sessionCallbacks;
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ mPrintJob = (PrintJob) invocation.getArguments()[0];
+ mPrintJob.start();
+ onPrintJobQueuedCalled();
+
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(serviceCallbacks);
+
+ // We don't use the second service, but we have to still configure it
+ SecondPrintService.setCallbacks(createMockPrintServiceCallbacks(null, null, null));
+
+ // Create a print adapter that respects the print contract.
+ PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write of the first page.
+ waitForWriteAdapterCallback();
+
+ // Select the printer.
+ selectPrinter(PRINTER_NAME);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
+ // Wait until the print job is queued and #mPrintJob is set
+ waitForServiceOnPrintJobQueuedCallbackCalled();
+
+ // Progress print job and check for appropriate notifications
+ progress(0, "printed 0");
+ progress(0.5f, "printed 50");
+ progress(1, "printed 100");
+
+ // Call complete from the main thread
+ Handler handler = new Handler(Looper.getMainLooper());
+
+ Runnable completer = new Runnable() {
+ @Override
+ public void run() {
+ mPrintJob.complete();
+ }
+ };
+
+ handler.post(completer);
+
+ // Wait for all print jobs to be handled after which the session destroyed.
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+ }
+}
diff --git a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
index 7ea09e5..a9ea29b 100644
--- a/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
+++ b/tests/tests/print/src/android/print/cts/PrinterDiscoverySessionLifecycleTest.java
@@ -123,6 +123,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for all print jobs to be handled after which the session destroyed.
waitForPrinterDiscoverySessionDestroyCallbackCalled();
@@ -157,6 +160,93 @@
inOrder.verify(firstSessionCallbacks).onDestroy();
}
+ public void testCancelPrintServicesAlertDialog() throws Exception {
+ if (!supportsPrinting()) {
+ return;
+ }
+ // Create the session callbacks that we will be checking.
+ final PrinterDiscoverySessionCallbacks firstSessionCallbacks =
+ createFirstMockPrinterDiscoverySessionCallbacks();
+
+ // Create the service callbacks for the first print service.
+ PrintServiceCallbacks firstServiceCallbacks = createMockPrintServiceCallbacks(
+ new Answer<PrinterDiscoverySessionCallbacks>() {
+ @Override
+ public PrinterDiscoverySessionCallbacks answer(InvocationOnMock invocation) {
+ return firstSessionCallbacks;
+ }
+ },
+ new Answer<Void>() {
+ @Override
+ public Void answer(InvocationOnMock invocation) {
+ PrintJob printJob = (PrintJob) invocation.getArguments()[0];
+ // We pretend the job is handled immediately.
+ printJob.complete();
+ return null;
+ }
+ }, null);
+
+ // Configure the print services.
+ FirstPrintService.setCallbacks(firstServiceCallbacks);
+
+ // Create a print adapter that respects the print contract.
+ PrintDocumentAdapter adapter = createMockPrintDocumentAdapter();
+
+ // Start printing.
+ print(adapter);
+
+ // Wait for write of the first page.
+ waitForWriteAdapterCallback();
+
+ // Select the first printer.
+ selectPrinter(FIRST_PRINTER_NAME);
+
+ // While the printer discovery session is still alive store the
+ // ids of printers as we want to make some assertions about them
+ // but only the print service can create printer ids which means
+ // that we need to get the created ones.
+ PrinterId firstPrinterId = getAddedPrinterIdForLocalId(firstSessionCallbacks,
+ FIRST_PRINTER_LOCAL_ID);
+ assertNotNull("Coundn't find printer:" + FIRST_PRINTER_LOCAL_ID, firstPrinterId);
+
+ // Click the print button.
+ clickPrintButton();
+
+ // Cancel the dialog for the print service cloud warning
+ answerPrintServicesWarning(false);
+
+ // Click the print button again.
+ clickPrintButton();
+
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
+ // Wait for all print jobs to be handled after which the session destroyed.
+ waitForPrinterDiscoverySessionDestroyCallbackCalled();
+
+ // Verify the expected calls.
+ InOrder inOrder = inOrder(firstSessionCallbacks);
+
+ // We start discovery as the print dialog was up.
+ List<PrinterId> emptyPrinterIdList = Collections.emptyList();
+ inOrder.verify(firstSessionCallbacks).onStartPrinterDiscovery(
+ emptyPrinterIdList);
+
+ // We selected the first printer and now it should be tracked.
+ inOrder.verify(firstSessionCallbacks).onStartPrinterStateTracking(
+ firstPrinterId);
+
+ // We selected the second printer so the first should not be tracked.
+ inOrder.verify(firstSessionCallbacks).onStopPrinterStateTracking(
+ firstPrinterId);
+
+ // ... next we stop printer discovery...
+ inOrder.verify(firstSessionCallbacks).onStopPrinterDiscovery();
+
+ // ... last the session is destroyed.
+ inOrder.verify(firstSessionCallbacks).onDestroy();
+ }
+
public void testStartPrinterDiscoveryWithHistoricalPrinters() throws Exception {
if (!supportsPrinting()) {
return;
@@ -213,6 +303,9 @@
// Click the print button.
clickPrintButton();
+ // Answer the dialog for the print service cloud warning
+ answerPrintServicesWarning(true);
+
// Wait for the print to complete.
waitForAdapterFinishCallbackCalled();
diff --git a/tests/tests/renderscriptlegacy/AndroidTest.xml b/tests/tests/renderscriptlegacy/AndroidTest.xml
index c11c0a6..a9b63a6 100644
--- a/tests/tests/renderscriptlegacy/AndroidTest.xml
+++ b/tests/tests/renderscriptlegacy/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="test-file-name" value="CtsRenderscriptLegacyTestCases.apk" />
</target_preparer>
<test class="com.android.tradefed.testtype.InstrumentationTest" >
- <option name="package" value="android.renderscript.cts" />
+ <option name="package" value="android.renderscriptlegacy.cts" />
<option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
</test>
</configuration>
diff --git a/tests/tests/rscpp/Android.mk b/tests/tests/rscpp/Android.mk
index 0eb32b5..35e61fa 100644
--- a/tests/tests/rscpp/Android.mk
+++ b/tests/tests/rscpp/Android.mk
@@ -35,5 +35,8 @@
LOCAL_SDK_VERSION := current
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
include $(LOCAL_PATH)/librscpptest/Android.mk
diff --git a/tests/tests/rscpp/AndroidManifest.xml b/tests/tests/rscpp/AndroidManifest.xml
index b68ebc3..035d242 100644
--- a/tests/tests/rscpp/AndroidManifest.xml
+++ b/tests/tests/rscpp/AndroidManifest.xml
@@ -15,7 +15,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.rscpp">
+ package="android.rscpp.cts">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
@@ -24,7 +24,7 @@
<!-- This is a self-instrumenting test package. -->
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.rscpp"
+ android:targetPackage="android.rscpp.cts"
android:label="CTS tests of RenderScript C++ component">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
diff --git a/tests/tests/rscpp/AndroidTest.xml b/tests/tests/rscpp/AndroidTest.xml
new file mode 100644
index 0000000..c0399d6
--- /dev/null
+++ b/tests/tests/rscpp/AndroidTest.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Configuration for renderscript cpp Tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsRsCppTestCases.apk" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.rscpp.cts" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/rscpp/librscpptest/clear_object.rs b/tests/tests/rscpp/librscpptest/clear_object.rs
index 70ba42b..cb6a0ad 100644
--- a/tests/tests/rscpp/librscpptest/clear_object.rs
+++ b/tests/tests/rscpp/librscpptest/clear_object.rs
@@ -1,5 +1,5 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
rs_allocation allocation;
diff --git a/tests/tests/rscpp/librscpptest/fe_all.rs b/tests/tests/rscpp/librscpptest/fe_all.rs
index dc20ba7..d5076bf 100644
--- a/tests/tests/rscpp/librscpptest/fe_all.rs
+++ b/tests/tests/rscpp/librscpptest/fe_all.rs
@@ -1,5 +1,5 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
void test_i8(const char *ain, uchar *aout) {
aout[0] = ain[0] + 1;
diff --git a/tests/tests/rscpp/librscpptest/rs_jni.cpp b/tests/tests/rscpp/librscpptest/rs_jni.cpp
index 47fa6c5..920d95d 100644
--- a/tests/tests/rscpp/librscpptest/rs_jni.cpp
+++ b/tests/tests/rscpp/librscpptest/rs_jni.cpp
@@ -459,7 +459,7 @@
sp<RS> mRS = new RS();
mRS->init(path);
- RSYuvFormat mYuvFormat = (RSYuvFormat)yuvFormat;
+ RsYuvFormat mYuvFormat = (RsYuvFormat)yuvFormat;
sp<ScriptIntrinsicYuvToRGB> syuv = ScriptIntrinsicYuvToRGB::create(mRS, Element::U8_4(mRS));;
sp<Allocation> inputAlloc = nullptr;
diff --git a/tests/tests/rscpp/librscpptest/setelementat.rs b/tests/tests/rscpp/librscpptest/setelementat.rs
index 5a84552..fc706de 100644
--- a/tests/tests/rscpp/librscpptest/setelementat.rs
+++ b/tests/tests/rscpp/librscpptest/setelementat.rs
@@ -1,5 +1,5 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
#pragma rs_fp_relaxed
int memset_toValue = 0;
diff --git a/tests/tests/rscpp/librscpptest/shared.rsh b/tests/tests/rscpp/librscpptest/shared.rsh
index c5599d7..70668e0 100644
--- a/tests/tests/rscpp/librscpptest/shared.rsh
+++ b/tests/tests/rscpp/librscpptest/shared.rsh
@@ -1,5 +1,5 @@
#pragma version(1)
-#pragma rs java_package_name(com.android.cts.rscpp)
+#pragma rs java_package_name(android.rscpp.cts)
static int64_t g_time;
diff --git a/tests/tests/rscpp/src/android/cts/rscpp/RSYuvTest.java b/tests/tests/rscpp/src/android/cts/rscpp/RSYuvTest.java
index 8f79a4c..30c76e4 100644
--- a/tests/tests/rscpp/src/android/cts/rscpp/RSYuvTest.java
+++ b/tests/tests/rscpp/src/android/cts/rscpp/RSYuvTest.java
@@ -141,7 +141,8 @@
syuv.forEach(aout);
byte[] nativeByteAlloc = new byte[width * height * 4];
- yuvTest(this.getContext().getCacheDir().toString(), width, height, tmp, nativeByteAlloc, 1);
+ yuvTest(this.getContext().getCacheDir().toString(), width, height, tmp, nativeByteAlloc,
+ android.graphics.ImageFormat.YV12);
aref.copyFromUnchecked(nativeByteAlloc);
mVerify.invoke_verify(aref, aout, ay);
@@ -177,7 +178,8 @@
syuv.forEach(aout);
byte[] nativeByteAlloc = new byte[width * height * 4];
- yuvTest(this.getContext().getCacheDir().toString(), width, height, tmp, nativeByteAlloc, 2);
+ yuvTest(this.getContext().getCacheDir().toString(), width, height, tmp, nativeByteAlloc,
+ android.graphics.ImageFormat.NV21);
aref.copyFromUnchecked(nativeByteAlloc);
mVerify.invoke_verify(aref, aout, ay);
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 043553b..9f7ca33 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -14,6 +14,55 @@
LOCAL_PATH:= $(call my-dir)
+test_executable := CtsAslrMallocTest
+list_executable := $(test_executable)_list
+
+include $(CLEAR_VARS)
+LOCAL_MODULE:= $(test_executable)
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA)/nativetest
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := $(LOCAL_MODULE)32
+LOCAL_MODULE_STEM_64 := $(LOCAL_MODULE)64
+
+LOCAL_C_INCLUDES := \
+ external/gtest/include
+
+LOCAL_SRC_FILES := \
+ src/AslrMallocTest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libutils \
+ liblog \
+
+LOCAL_STATIC_LIBRARIES := \
+ libgtest
+
+LOCAL_CTS_TEST_PACKAGE := android.security.cts
+
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
+include $(BUILD_CTS_EXECUTABLE)
+
+include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
+
+LOCAL_MODULE := $(list_executable)
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+ src/AslrMallocTest.cpp
+
+LOCAL_CFLAGS := \
+ -DBUILD_ONLY \
+
+LOCAL_SHARED_LIBRARIES := \
+ liblog
+
+include $(BUILD_HOST_NATIVE_TEST)
+
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := tests
@@ -34,6 +83,9 @@
LOCAL_SDK_VERSION := current
+# Tag this module as a cts_v2 test artifact
+LOCAL_COMPATIBILITY_SUITE := cts_v2
+
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/tests/security/AndroidManifest.xml b/tests/tests/security/AndroidManifest.xml
index 911442a..7a67b08 100644
--- a/tests/tests/security/AndroidManifest.xml
+++ b/tests/tests/security/AndroidManifest.xml
@@ -16,7 +16,7 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.cts.security">
+ package="android.security.cts">
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
@@ -24,6 +24,7 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application>
<uses-library android:name="android.test.runner" />
@@ -39,8 +40,8 @@
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
- android:targetPackage="com.android.cts.security"
- android:label="CTS tests of com.android.cts.security">
+ android:targetPackage="android.security.cts"
+ android:label="CTS tests of android.security.cts">
<meta-data android:name="listener"
android:value="com.android.cts.runner.CtsTestRunListener" />
</instrumentation>
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
new file mode 100644
index 0000000..11d1b3c
--- /dev/null
+++ b/tests/tests/security/AndroidTest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS security test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsSecurityTestCases.apk" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.security.cts" />
+ </test>
+</configuration>
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/drm_uaf.dm b/tests/tests/security/res/raw/drm_uaf.dm
new file mode 100644
index 0000000..50f42bc
--- /dev/null
+++ b/tests/tests/security/res/raw/drm_uaf.dm
Binary files differ
diff --git a/tests/tests/security/res/raw/id3v2_3_extended_header_overflow_padding.mp3 b/tests/tests/security/res/raw/id3v2_3_extended_header_overflow_padding.mp3
new file mode 100644
index 0000000..7e8d38c
--- /dev/null
+++ b/tests/tests/security/res/raw/id3v2_3_extended_header_overflow_padding.mp3
Binary files differ
diff --git a/tests/tests/security/src/AslrMallocTest.cpp b/tests/tests/security/src/AslrMallocTest.cpp
new file mode 100644
index 0000000..6e773cb
--- /dev/null
+++ b/tests/tests/security/src/AslrMallocTest.cpp
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#define LOG_TAG "AslrMallocTest"
+
+#if !defined(BUILD_ONLY)
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <linux/limits.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <unordered_set>
+#endif
+
+#include <gtest/gtest.h>
+#include <string>
+#include <utils/Log.h>
+
+/* minimum entropy for malloc return addresses */
+const size_t minEntropyBits = 8;
+
+/* test using the following allocation sizes */
+const size_t allocSizes[] = {
+ 1 << 8, // small
+ 1 << 16, // large
+ 1 << 23 // huge
+};
+
+/* when started using this argument followed by the allocation size,
+ * performs malloc(size) and prints out the address */
+static const std::string argPrint = "--print-malloc-address";
+
+#if !defined(BUILD_ONLY)
+class AslrMallocTest : public ::testing::Test
+{
+protected:
+ std::string self_;
+
+ AslrMallocTest() {}
+ virtual ~AslrMallocTest() {}
+
+ virtual void SetUp()
+ {
+ /* path to self for exec */
+ char path[PATH_MAX];
+ auto size = readlink("/proc/self/exe", path, sizeof(path));
+ ASSERT_TRUE(size > 0 && size < PATH_MAX);
+ path[size] = '\0';
+ self_ = path;
+ }
+
+ void GetAddress(size_t allocSize, uintptr_t& address)
+ {
+ int fds[2];
+ ASSERT_TRUE(pipe(fds) != -1);
+
+ auto pid = fork();
+ ASSERT_TRUE(pid != -1);
+
+ if (pid == 0) {
+ /* child process */
+ ASSERT_TRUE(TEMP_FAILURE_RETRY(dup2(fds[1], STDOUT_FILENO)) != -1);
+
+ for (auto fd : fds) {
+ TEMP_FAILURE_RETRY(close(fd));
+ }
+
+ /* exec self to print malloc output */
+ ASSERT_TRUE(execl(self_.c_str(), self_.c_str(), argPrint.c_str(),
+ android::base::StringPrintf("%zu", allocSize).c_str(),
+ nullptr) != -1);
+ }
+
+ /* parent process */
+ TEMP_FAILURE_RETRY(close(fds[1]));
+
+ std::string output;
+ ASSERT_TRUE(android::base::ReadFdToString(fds[0], &output));
+ TEMP_FAILURE_RETRY(close(fds[0]));
+
+ int status;
+ ASSERT_TRUE(waitpid(pid, &status, 0) != -1);
+ ASSERT_TRUE(WEXITSTATUS(status) == EXIT_SUCCESS);
+
+ ASSERT_TRUE(android::base::ParseUint(output.c_str(), &address));
+ }
+
+ void TestRandomization()
+ {
+ /* should be sufficient to see minEntropyBits when rounded up */
+ size_t iterations = 2 * (1 << minEntropyBits);
+
+ for (auto size : allocSizes) {
+ ALOGV("running %zu iterations for allocation size %zu",
+ iterations, size);
+
+ /* collect unique return addresses */
+ std::unordered_set<uintptr_t> addresses;
+
+ for (size_t i = 0; i < iterations; ++i) {
+ uintptr_t address;
+ GetAddress(size, address);
+
+ addresses.emplace(address);
+ }
+
+ size_t entropy = static_cast<size_t>(0.5 +
+ log2(static_cast<double>(addresses.size())));
+
+ ALOGV("%zu bits of entropy for allocation size %zu (minimum %zu)",
+ entropy, size, minEntropyBits);
+ ALOGE_IF(entropy < minEntropyBits,
+ "insufficient entropy for malloc(%zu)", size);
+ ASSERT_TRUE(entropy >= minEntropyBits);
+ }
+ }
+};
+#else /* defined(BUILD_ONLY) */
+class AslrMallocTest : public ::testing::Test
+{
+protected:
+ void TestRandomization() {}
+};
+#endif
+
+TEST_F(AslrMallocTest, testMallocRandomization) {
+ TestRandomization();
+}
+
+int main(int argc, char **argv)
+{
+#if !defined(BUILD_ONLY)
+ if (argc == 3 && argPrint == argv[1]) {
+ size_t size;
+
+ if (!android::base::ParseUint(argv[2], &size)) {
+ return EXIT_FAILURE;
+ }
+
+ printf("%p", malloc(size));
+ return EXIT_SUCCESS;
+ }
+#endif
+
+ testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
+}
diff --git a/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java b/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java
new file mode 100644
index 0000000..6ae0d69
--- /dev/null
+++ b/tests/tests/security/src/android/security/cts/MediaMetadataRetrieverTest.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.security.cts;
+
+import android.security.cts.R;
+
+import android.content.res.AssetFileDescriptor;
+import android.content.res.Resources;
+import android.media.MediaMetadataRetriever;
+import android.test.AndroidTestCase;
+
+import java.io.IOException;
+
+public class MediaMetadataRetrieverTest extends AndroidTestCase {
+ protected Resources mResources;
+ protected MediaMetadataRetriever mRetriever;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mResources = getContext().getResources();
+ mRetriever = new MediaMetadataRetriever();
+ }
+
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ mRetriever.release();
+ }
+
+ protected void setDataSourceFd(int resid) {
+ try {
+ AssetFileDescriptor afd = mResources.openRawResourceFd(resid);
+ mRetriever.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ afd.close();
+ } catch (Exception e) {
+ fail("Unable to open file");
+ }
+ }
+
+ public void testID3v2EmbeddedPicture() {
+ setDataSourceFd(R.raw.id3v2_3_extended_header_overflow_padding);
+
+ assertEquals("EmbeddedPicture was other than expected null array",
+ null, mRetriever.getEmbeddedPicture());
+ }
+}
diff --git a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
index 4dc6783..5298196 100644
--- a/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
+++ b/tests/tests/security/src/android/security/cts/MediaServerCrashTest.java
@@ -17,70 +17,259 @@
package android.security.cts;
import android.content.res.AssetFileDescriptor;
+import android.drm.DrmConvertedStatus;
+import android.drm.DrmManagerClient;
import android.media.MediaPlayer;
import android.os.ConditionVariable;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
import android.test.AndroidTestCase;
import android.util.Log;
-import com.android.cts.security.R;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+
+import android.security.cts.R;
public class MediaServerCrashTest extends AndroidTestCase {
private static final String TAG = "MediaServerCrashTest";
- public void testInvalidMidiNullPointerAccess() throws Exception {
- testIfMediaServerDied(R.raw.midi_crash);
- }
+ private static final String MIMETYPE_DRM_MESSAGE = "application/vnd.oma.drm.message";
- private void testIfMediaServerDied(int res) throws Exception {
- final MediaPlayer mediaPlayer = new MediaPlayer();
- final ConditionVariable onPrepareCalled = new ConditionVariable();
- final ConditionVariable onCompletionCalled = new ConditionVariable();
+ private String mFlFilePath;
- onPrepareCalled.close();
- onCompletionCalled.close();
- mediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
+ private final MediaPlayer mMediaPlayer = new MediaPlayer();
+ private final ConditionVariable mOnPrepareCalled = new ConditionVariable();
+ private final ConditionVariable mOnCompletionCalled = new ConditionVariable();
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mFlFilePath = new File(Environment.getExternalStorageDirectory(),
+ "temp.fl").getAbsolutePath();
+
+ mOnPrepareCalled.close();
+ mOnCompletionCalled.close();
+ mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() {
@Override
public boolean onError(MediaPlayer mp, int what, int extra) {
- assertTrue(mp == mediaPlayer);
+ assertTrue(mp == mMediaPlayer);
assertTrue("mediaserver process died", what != MediaPlayer.MEDIA_ERROR_SERVER_DIED);
Log.w(TAG, "onError " + what);
return false;
}
});
- mediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
+ mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() {
@Override
public void onPrepared(MediaPlayer mp) {
- assertTrue(mp == mediaPlayer);
- onPrepareCalled.open();
+ assertTrue(mp == mMediaPlayer);
+ mOnPrepareCalled.open();
}
});
- mediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
+ mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {
@Override
public void onCompletion(MediaPlayer mp) {
- assertTrue(mp == mediaPlayer);
- onCompletionCalled.open();
+ assertTrue(mp == mMediaPlayer);
+ mOnCompletionCalled.open();
}
});
+ }
+ @Override
+ protected void tearDown() throws Exception {
+ super.tearDown();
+ File flFile = new File(mFlFilePath);
+ if (flFile.exists()) {
+ flFile.delete();
+ }
+ }
+
+ public void testInvalidMidiNullPointerAccess() throws Exception {
+ testIfMediaServerDied(R.raw.midi_crash);
+ }
+
+ private void testIfMediaServerDied(int res) throws Exception {
AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
- mediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
+ mMediaPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(), afd.getLength());
afd.close();
try {
- mediaPlayer.prepareAsync();
- if (!onPrepareCalled.block(5000)) {
+ mMediaPlayer.prepareAsync();
+ if (!mOnPrepareCalled.block(5000)) {
Log.w(TAG, "testIfMediaServerDied: Timed out waiting for prepare");
return;
}
- mediaPlayer.start();
- if (!onCompletionCalled.block(5000)) {
+ mMediaPlayer.start();
+ if (!mOnCompletionCalled.block(5000)) {
Log.w(TAG, "testIfMediaServerDied: Timed out waiting for Error/Completion");
}
} catch (Exception e) {
Log.w(TAG, "playback failed", e);
} finally {
- mediaPlayer.release();
+ mMediaPlayer.release();
}
}
+
+ public void testDrmManagerClientReset() throws Exception {
+ checkIfMediaServerDiedForDrm(R.raw.drm_uaf);
+ }
+
+ private void checkIfMediaServerDiedForDrm(int res) throws Exception {
+ if (!convertDmToFl(res, mFlFilePath)) {
+ fail("Can not convert dm to fl");
+ }
+ Log.d(TAG, "intermediate fl file is " + mFlFilePath);
+
+ ParcelFileDescriptor flFd = null;
+ try {
+ flFd = ParcelFileDescriptor.open(new File(mFlFilePath),
+ ParcelFileDescriptor.MODE_READ_ONLY);
+ } catch (FileNotFoundException e) {
+ fail("Could not find file: " + mFlFilePath + e);
+ }
+
+ mMediaPlayer.setDataSource(flFd.getFileDescriptor(), 0, flFd.getStatSize());
+ flFd.close();
+ try {
+ mMediaPlayer.prepare();
+ } catch (Exception e) {
+ Log.d(TAG, "Prepare failed", e);
+ }
+
+ try {
+ mMediaPlayer.reset();
+ if (!mOnCompletionCalled.block(5000)) {
+ Log.w(TAG, "checkIfMediaServerDiedForDrm: Timed out waiting for Error/Completion");
+ }
+ } catch (Exception e) {
+ fail("reset failed" + e);
+ } finally {
+ mMediaPlayer.release();
+ }
+ }
+
+ private boolean convertDmToFl(int res, String flFilePath) throws Exception {
+ AssetFileDescriptor afd = getContext().getResources().openRawResourceFd(res);
+ FileInputStream inputStream = afd.createInputStream();
+ int inputLength = (int)afd.getLength();
+ byte[] fileData = new byte[inputLength];
+ int readSize = inputStream.read(fileData, 0, inputLength);
+ assertEquals("can not pull in all data", readSize, inputLength);
+ inputStream.close();
+ afd.close();
+
+ FileOutputStream flStream = new FileOutputStream(new File(flFilePath));
+
+ DrmManagerClient drmClient = null;
+ try {
+ drmClient = new DrmManagerClient(mContext);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "DrmManagerClient instance could not be created, context is Illegal.");
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "DrmManagerClient didn't initialize properly.");
+ return false;
+ }
+
+ if (drmClient == null) {
+ Log.w(TAG, "Failed to create DrmManagerClient.");
+ return false;
+ }
+
+ int convertSessionId = -1;
+ try {
+ convertSessionId = drmClient.openConvertSession(MIMETYPE_DRM_MESSAGE);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Conversion of Mimetype: " + MIMETYPE_DRM_MESSAGE
+ + " is not supported.", e);
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not access Open DrmFramework.", e);
+ return false;
+ }
+
+ if (convertSessionId < 0) {
+ Log.w(TAG, "Failed to open session.");
+ return false;
+ }
+
+ DrmConvertedStatus convertedStatus = null;
+ try {
+ convertedStatus = drmClient.convertData(convertSessionId, fileData);
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Buffer with data to convert is illegal. Convertsession: "
+ + convertSessionId, e);
+ return false;
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not convert data. Convertsession: " + convertSessionId, e);
+ return false;
+ }
+
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ Log.w(TAG, "Error in converting data. Convertsession: " + convertSessionId);
+ try {
+ drmClient.closeConvertSession(convertSessionId);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not close session. Convertsession: " +
+ convertSessionId, e);
+ }
+ return false;
+ }
+
+ flStream.write(convertedStatus.convertedData, 0, convertedStatus.convertedData.length);
+ flStream.close();
+
+ try {
+ convertedStatus = drmClient.closeConvertSession(convertSessionId);
+ } catch (IllegalStateException e) {
+ Log.w(TAG, "Could not close convertsession. Convertsession: " +
+ convertSessionId, e);
+ return false;
+ }
+
+ if (convertedStatus == null ||
+ convertedStatus.statusCode != DrmConvertedStatus.STATUS_OK ||
+ convertedStatus.convertedData == null) {
+ Log.w(TAG, "Error in closing session. Convertsession: " + convertSessionId);
+ return false;
+ }
+
+ RandomAccessFile flRandomAccessFile = null;
+ try {
+ flRandomAccessFile = new RandomAccessFile(flFilePath, "rw");
+ flRandomAccessFile.seek(convertedStatus.offset);
+ flRandomAccessFile.write(convertedStatus.convertedData);
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "File: " + flFilePath + " could not be found.", e);
+ return false;
+ } catch (IOException e) {
+ Log.w(TAG, "Could not access File: " + flFilePath + " .", e);
+ return false;
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "Could not open file in mode: rw", e);
+ return false;
+ } catch (SecurityException e) {
+ Log.w(TAG, "Access to File: " + flFilePath +
+ " was denied denied by SecurityManager.", e);
+ return false;
+ } finally {
+ if (flRandomAccessFile != null) {
+ try {
+ flRandomAccessFile.close();
+ } catch (IOException e) {
+ Log.w(TAG, "Failed to close File:" + flFilePath + ".", e);
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
}
diff --git a/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java b/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
index 9cdb288..bba75dc 100644
--- a/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
+++ b/tests/tests/security/src/android/security/cts/OpenSSLEarlyCCSTest.java
@@ -26,8 +26,6 @@
import android.test.InstrumentationTestCase;
import android.util.Log;
-import com.android.cts.security.R;
-
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
diff --git a/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java b/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
index 12fcee4..61a03a1 100644
--- a/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
+++ b/tests/tests/security/src/android/security/cts/OpenSSLHeartbleedTest.java
@@ -20,8 +20,6 @@
import android.test.InstrumentationTestCase;
import android.util.Log;
-import com.android.cts.security.R;
-
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.EOFException;
diff --git a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
index 069fa72..0b76cb5 100644
--- a/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
+++ b/tests/tests/security/src/android/security/cts/PackageSignatureTest.java
@@ -16,8 +16,6 @@
package android.security.cts;
-import com.android.cts.security.R;
-
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -35,10 +33,13 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
public class PackageSignatureTest extends AndroidTestCase {
private static final String TAG = PackageSignatureTest.class.getSimpleName();
+ private static final Pattern TEST_PACKAGE_PATTERN = Pattern.compile("android\\.[^\\.]+\\.cts");
public void testPackageSignatures() throws Exception {
Set<String> badPackages = new HashSet<String>();
@@ -109,8 +110,8 @@
private boolean isWhitelistedPackage(String packageName) {
// Don't check the signatures of CTS test packages on the device.
// devicesetup is the APK CTS loads to collect information needed in the final report
- return packageName.startsWith("com.android.cts")
- || WHITELISTED_PACKAGES.contains(packageName);
+ final Matcher matcher = TEST_PACKAGE_PATTERN.matcher(packageName);
+ return matcher.matches() || WHITELISTED_PACKAGES.contains(packageName);
}
private static final int DEFAULT_BUFFER_BYTES = 1024 * 4;
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 0f79860..6e6ae25 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -22,6 +22,8 @@
*/
package android.security.cts;
+import android.test.AndroidTestCase;
+import android.util.Log;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.media.MediaPlayer;
@@ -33,7 +35,7 @@
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
-import com.android.cts.security.R;
+import android.security.cts.R;
/**
diff --git a/tests/tests/telecom/AndroidTest.xml b/tests/tests/telecom/AndroidTest.xml
index 841bd6e..63fa208 100644
--- a/tests/tests/telecom/AndroidTest.xml
+++ b/tests/tests/telecom/AndroidTest.xml
@@ -14,6 +14,9 @@
limitations under the License.
-->
<configuration description="Configuration for telecom Tests">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
+ <option name="token" value="sim-card" />
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsTelecomTestCases.apk" />
diff --git a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
index d7fe239..8bb3cc1 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BaseTelecomTestWithMockServices.java
@@ -246,7 +246,8 @@
mTelecomManager.addNewIncomingCall(TEST_PHONE_ACCOUNT_HANDLE, extras);
try {
- if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
fail("No call added to InCallService.");
}
} catch (InterruptedException e) {
@@ -297,7 +298,8 @@
placeNewCallWithPhoneAccount(extras, videoState);
try {
- if (!mInCallCallbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
+ if (!mInCallCallbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
fail("No call added to InCallService.");
}
} catch (InterruptedException e) {
@@ -590,6 +592,25 @@
);
}
+ void assertNotAudioRoute(final InCallService incallService, final int route) {
+ waitUntilConditionIsTrueOrTimeout(
+ new Condition() {
+ @Override
+ public Object expected() {
+ return new Boolean(true);
+ }
+
+ @Override
+ public Object actual() {
+ final CallAudioState state = incallService.getCallAudioState();
+ return route != state.getRoute();
+ }
+ },
+ WAIT_FOR_STATE_CHANGE_TIMEOUT_MS,
+ "Phone's audio route should not be: " + route
+ );
+ }
+
void assertAudioRoute(final MockConnection connection, final int route) {
waitUntilConditionIsTrueOrTimeout(
new Condition() {
diff --git a/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
index 0b5fe61..eda193d 100644
--- a/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/BasicInCallServiceTest.java
@@ -77,7 +77,8 @@
mContext.startActivity(intent);
try {
- if (callbacks.lock.tryAcquire(3, TimeUnit.SECONDS)) {
+ if (callbacks.lock.tryAcquire(TestUtils.WAIT_FOR_CALL_ADDED_TIMEOUT_S,
+ TimeUnit.SECONDS)) {
return;
}
} catch (InterruptedException e) {
diff --git a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
index bba9a44..fa19751 100644
--- a/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/OutgoingCallTest.java
@@ -68,15 +68,11 @@
return;
}
- AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- int expectedRoute = am.isWiredHeadsetOn() ?
- CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
-
final Bundle extras = new Bundle();
extras.putBoolean(TelecomManager.EXTRA_START_CALL_WITH_SPEAKERPHONE, false);
placeAndVerifyCall(extras);
verifyConnectionForOutgoingCall();
- assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
+ assertNotAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_SPEAKER);
}
public void testStartCallWithSpeakerphoneNotProvided_SpeakerphoneOffByDefault() {
@@ -85,11 +81,9 @@
}
AudioManager am = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
- int expectedRoute = am.isWiredHeadsetOn() ?
- CallAudioState.ROUTE_WIRED_HEADSET : CallAudioState.ROUTE_EARPIECE;
placeAndVerifyCall();
verifyConnectionForOutgoingCall();
- assertAudioRoute(mInCallCallbacks.getService(), expectedRoute);
+ assertNotAudioRoute(mInCallCallbacks.getService(), CallAudioState.ROUTE_SPEAKER);
}
}
diff --git a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
index 3d9536e..6e12401 100644
--- a/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
+++ b/tests/tests/telecom/src/android/telecom/cts/TestUtils.java
@@ -33,6 +33,7 @@
static final String TAG = "TelecomCTSTests";
static final boolean HAS_TELECOM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
static final long WAIT_FOR_STATE_CHANGE_TIMEOUT_MS = 10000;
+ static final long WAIT_FOR_CALL_ADDED_TIMEOUT_S = 15;
// Non-final to allow modification by tests not in this package (e.g. permission-related
// tests in the Telecom2 test package.
diff --git a/tests/tests/telephony/AndroidTest.xml b/tests/tests/telephony/AndroidTest.xml
index 81fd49a..2e6011b 100644
--- a/tests/tests/telephony/AndroidTest.xml
+++ b/tests/tests/telephony/AndroidTest.xml
@@ -14,6 +14,9 @@
limitations under the License.
-->
<configuration description="Config for CTS Telephony test cases">
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.TokenRequirement">
+ <option name="token" value="sim-card" />
+ </target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsTelephonyTestCases.apk" />
diff --git a/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
index b7caabb..be29794 100644
--- a/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/CellInfoTest.java
@@ -93,39 +93,31 @@
// Verify lte cell information is within correct range.
private void verifyLteInfo(CellInfoLte lte) {
verifyRssiDbm(lte.getCellSignalStrength().getDbm());
- // Verify LTE neighbor information.
- if (!lte.isRegistered()) {
- // Only physical cell id is available for LTE neighbor.
- int pci = lte.getCellIdentity().getPci();
- // Physical cell id should be within [0, 503].
- assertTrue("getPci() out of range [0, 503]", pci >= 0 && pci <= 503);
- }
+ // Verify LTE physical cell id information.
+ // Only physical cell id is available for LTE neighbor.
+ int pci = lte.getCellIdentity().getPci();
+ // Physical cell id should be within [0, 503].
+ assertTrue("getPci() out of range [0, 503]", pci >= 0 && pci <= 503);
}
// Verify wcdma cell information is within correct range.
private void verifyWcdmaInfo(CellInfoWcdma wcdma) {
verifyRssiDbm(wcdma.getCellSignalStrength().getDbm());
- // Verify wcdma neighbor.
- if (!wcdma.isRegistered()) {
- // For wcdma neighbor, only primary scrambling code is available.
- // Primary scrambling code should be within [0, 511].
- int psc = wcdma.getCellIdentity().getPsc();
- assertTrue("getPsc() out of range [0, 511]", psc >= 0 && psc <= 511);
- }
+ // Verify wcdma primary scrambling code information.
+ // Primary scrambling code should be within [0, 511].
+ int psc = wcdma.getCellIdentity().getPsc();
+ assertTrue("getPsc() out of range [0, 511]", psc >= 0 && psc <= 511);
}
// Verify gsm cell information is within correct range.
private void verifyGsmInfo(CellInfoGsm gsm) {
verifyRssiDbm(gsm.getCellSignalStrength().getDbm());
- // Verify gsm neighbor.
- if (!gsm.isRegistered()) {
- // lac and cid are available in GSM neighbor information.
- // Local area code and cellid should be with [0, 65535].
- int lac = gsm.getCellIdentity().getLac();
- assertTrue("getLac() out of range [0, 65535]", lac >= 0 && lac <= 65535);
- int cid = gsm.getCellIdentity().getCid();
- assertTrue("getCid() out range [0, 65535]", cid >= 0 && cid <= 65535);
- }
+ // Verify gsm local area code and cellid.
+ // Local area code and cellid should be with [0, 65535].
+ int lac = gsm.getCellIdentity().getLac();
+ assertTrue("getLac() out of range [0, 65535]", lac >= 0 && lac <= 65535);
+ int cid = gsm.getCellIdentity().getCid();
+ assertTrue("getCid() out range [0, 65535]", cid >= 0 && cid <= 65535);
}
// Rssi(in dbm) should be within [MIN_RSSI, MAX_RSSI].
diff --git a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
index d90e394..2db9ba1 100644
--- a/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/SmsMessageTest.java
@@ -301,11 +301,19 @@
int[] result = SmsMessage.calculateLength(LONG_TEXT_WITH_32BIT_CHARS, false);
assertEquals(3, result[0]);
assertEquals(LONG_TEXT_WITH_32BIT_CHARS.length(), result[1]);
+ // 3 parts, each with (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2) 16-bit
+ // characters. We need to subtract one because a 32-bit character crosses the
+ // boundary of 2 parts.
+ int preMaxChars = 3 * SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2 - 1;
+ // If EMS is not supported, break down EMS into single segment SMS
+ // and add page info "x/y".
+ // In the case of UCS2 encoding type, we need 8 bytes for this
+ // but we only have 6 bytes from UDH, so truncate the limit for
+ // each segment by 2 bytes (1 char). This log sms has three segments,
+ // so truncate the limit by 3 char in total
+ int maxChars = SmsMessage.hasEmsSupport() ? preMaxChars : preMaxChars - 3;
assertRemaining(LONG_TEXT_WITH_32BIT_CHARS.length(), result[2],
- // 3 parts, each with (SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2) 16-bit
- // characters. We need to subtract one because a 32-bit character crosses the
- // boundary of 2 parts.
- 3 * SmsMessage.MAX_USER_DATA_BYTES_WITH_HEADER / 2 - 1);
+ maxChars);
assertEquals(SmsMessage.ENCODING_16BIT, result[3]);
}
diff --git a/tests/tests/text/src/android/text/format/cts/FormatterTest.java b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
index 4be3d2d3..6acfb84 100644
--- a/tests/tests/text/src/android/text/format/cts/FormatterTest.java
+++ b/tests/tests/text/src/android/text/format/cts/FormatterTest.java
@@ -39,7 +39,7 @@
assertEquals("99 B", Formatter.formatFileSize(mContext, 99));
assertEquals("100 B", Formatter.formatFileSize(mContext, 100));
assertEquals("900 B", Formatter.formatFileSize(mContext, 900));
- assertEquals("0.90 KB", Formatter.formatFileSize(mContext, 901));
+ assertEquals("0.88 KB", Formatter.formatFileSize(mContext, 901));
assertEquals("1.00 KB", Formatter.formatFileSize(mContext, bd.pow(1).longValue()));
@@ -54,7 +54,7 @@
assertEquals("1024 PB", Formatter.formatFileSize(mContext, bd.pow(6).longValue()));
// test Negative value
- assertEquals("-1.00 B", Formatter.formatFileSize(mContext, -1));
+ assertEquals("-1 B", Formatter.formatFileSize(mContext, -1));
}
public void testFormatIpAddress() {
diff --git a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
index f273efb..ea679c5 100644
--- a/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/PasswordTransformationMethodTest.java
@@ -19,6 +19,7 @@
import android.cts.util.PollingCheck;
import android.graphics.Rect;
+import android.os.ParcelFileDescriptor;
import android.provider.Settings.SettingNotFoundException;
import android.provider.Settings.System;
import android.test.ActivityInstrumentationTestCase2;
@@ -31,6 +32,10 @@
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.util.Scanner;
+
/**
* Test {@link PasswordTransformationMethod}.
*/
@@ -97,10 +102,39 @@
mEditText = (EditText) getActivity().findViewById(EDIT_TXT_ID);
assertTrue(mEditText.isFocused());
+ enableAppOps();
savePasswordPref();
switchShowPassword(true);
}
+ private void enableAppOps() {
+ StringBuilder cmd = new StringBuilder();
+ cmd.append("appops set ");
+ cmd.append(getInstrumentation().getContext().getPackageName());
+ cmd.append(" android:write_settings allow");
+ getInstrumentation().getUiAutomation().executeShellCommand(cmd.toString());
+
+ StringBuilder query = new StringBuilder();
+ query.append("appops get ");
+ query.append(getInstrumentation().getContext().getPackageName());
+ query.append(" android:write_settings");
+ String queryStr = query.toString();
+
+ String result = "No operations.";
+ while (result.contains("No operations")) {
+ ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation().executeShellCommand(
+ queryStr);
+ InputStream inputStream = new FileInputStream(pfd.getFileDescriptor());
+ result = convertStreamToString(inputStream);
+ }
+ }
+
+ private String convertStreamToString(InputStream is) {
+ try (Scanner scanner = new Scanner(is).useDelimiter("\\A")) {
+ return scanner.hasNext() ? scanner.next() : "";
+ }
+ }
+
@Override
protected void tearDown() throws Exception {
resumePasswordPref();
diff --git a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
index b839616..49196bd 100644
--- a/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
+++ b/tests/tests/text/src/android/text/method/cts/ScrollingMovementMethodTest.java
@@ -24,6 +24,7 @@
import android.text.SpannableString;
import android.text.method.MovementMethod;
import android.text.method.ScrollingMovementMethod;
+import android.util.DisplayMetrics;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
@@ -736,7 +737,8 @@
public void run() {
mTextView.setText("short");
mTextView.setSingleLine();
- int width = WidgetTestUtils.convertDipToPixels(getActivity(), LITTLE_SPACE);
+ DisplayMetrics dm = getActivity().getResources().getDisplayMetrics();
+ int width = (int) (LITTLE_SPACE * dm.scaledDensity);
getActivity().setContentView(mTextView,
new ViewGroup.LayoutParams(width, ViewGroup.LayoutParams.WRAP_CONTENT));
}
diff --git a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
index e6b91eb..e7d5ce2 100644
--- a/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
+++ b/tests/tests/text/src/android/text/util/cts/LinkifyTest.java
@@ -20,6 +20,7 @@
import android.test.AndroidTestCase;
import android.text.Spannable;
import android.text.SpannableString;
+import android.text.SpannableStringBuilder;
import android.text.style.URLSpan;
import android.text.util.Linkify;
import android.text.util.Linkify.MatchFilter;
@@ -349,4 +350,19 @@
assertFalse(Linkify.addLinks((Spannable) null, 0));
}
+
+ public void testAddLinks_acceptsUrlsWithCommasInRequestParameterValues() throws Exception {
+ String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
+ Spannable spannable = new SpannableString(url);
+
+ Linkify.addLinks(spannable, Linkify.WEB_URLS);
+
+ URLSpan[] urlSpans = spannable.getSpans(0, spannable.length(), URLSpan.class);
+ assertEquals("Web URL parsing should accept commas", url, urlSpans[0].getURL());
+ assertEquals("Spannable should start from beginning of the given URL", 0,
+ spannable.getSpanStart(urlSpans[0]));
+ assertEquals("Spannable should end at the end of the given URL", url.length(),
+ spannable.getSpanEnd(urlSpans[0]));
+ }
+
}
diff --git a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
index 5f62cee..478a3f6 100755
--- a/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
+++ b/tests/tests/uiautomation/src/android/app/uiautomation/cts/UiAutomationTest.java
@@ -251,14 +251,14 @@
final int frameCount = stats.getFrameCount();
for (int i = 0; i < frameCount; i++) {
final long expectedTimeNano = stats.getFramePostedTimeNano(i);
- assertTrue(expectedTimeNano > lastExpectedTimeNano);
+ assertTrue(expectedTimeNano >= lastExpectedTimeNano);
lastExpectedTimeNano = expectedTimeNano;
final long presentedTimeNano = stats.getFramePresentedTimeNano(i);
if (lastPresentedTimeNano == FrameStats.UNDEFINED_TIME_NANO) {
assertTrue(presentedTimeNano == FrameStats.UNDEFINED_TIME_NANO);
} else if (presentedTimeNano != FrameStats.UNDEFINED_TIME_NANO) {
- assertTrue(presentedTimeNano > lastPresentedTimeNano);
+ assertTrue(presentedTimeNano >= lastPresentedTimeNano);
}
lastPresentedTimeNano = presentedTimeNano;
@@ -266,7 +266,7 @@
if (lastPreparedTimeNano == FrameStats.UNDEFINED_TIME_NANO) {
assertTrue(preparedTimeNano == FrameStats.UNDEFINED_TIME_NANO);
} else if (preparedTimeNano != FrameStats.UNDEFINED_TIME_NANO) {
- assertTrue(preparedTimeNano > lastPreparedTimeNano);
+ assertTrue(preparedTimeNano >= lastPreparedTimeNano);
}
lastPreparedTimeNano = preparedTimeNano;
}
diff --git a/tests/tests/util/Android.mk b/tests/tests/util/Android.mk
index 3e92d10..b63e637 100644
--- a/tests/tests/util/Android.mk
+++ b/tests/tests/util/Android.mk
@@ -30,6 +30,4 @@
LOCAL_PACKAGE_NAME := CtsUtilTestCases
-LOCAL_SDK_VERSION := current
-
include $(BUILD_CTS_PACKAGE)
diff --git a/tests/tests/util/assets/Integrate.jar b/tests/tests/util/assets/Integrate.jar
new file mode 100644
index 0000000..16e9c55
--- /dev/null
+++ b/tests/tests/util/assets/Integrate.jar
Binary files differ
diff --git a/tests/tests/util/assets/Modified_Class.jar b/tests/tests/util/assets/Modified_Class.jar
new file mode 100644
index 0000000..d8113c7
--- /dev/null
+++ b/tests/tests/util/assets/Modified_Class.jar
Binary files differ
diff --git a/tests/tests/util/assets/Modified_Manifest_EntryAttributes.jar b/tests/tests/util/assets/Modified_Manifest_EntryAttributes.jar
new file mode 100644
index 0000000..bd1dbb1
--- /dev/null
+++ b/tests/tests/util/assets/Modified_Manifest_EntryAttributes.jar
Binary files differ
diff --git a/tests/tests/util/assets/Modified_Manifest_MainAttributes.jar b/tests/tests/util/assets/Modified_Manifest_MainAttributes.jar
new file mode 100644
index 0000000..5bc60e6
--- /dev/null
+++ b/tests/tests/util/assets/Modified_Manifest_MainAttributes.jar
Binary files differ
diff --git a/tests/tests/util/assets/Modified_SF_EntryAttributes.jar b/tests/tests/util/assets/Modified_SF_EntryAttributes.jar
new file mode 100644
index 0000000..7b76694
--- /dev/null
+++ b/tests/tests/util/assets/Modified_SF_EntryAttributes.jar
Binary files differ
diff --git a/tests/tests/util/assets/hyts_patch.jar b/tests/tests/util/assets/hyts_patch.jar
new file mode 100644
index 0000000..f3c51d0
--- /dev/null
+++ b/tests/tests/util/assets/hyts_patch.jar
Binary files differ
diff --git a/tests/tests/util/assets/removed.jar b/tests/tests/util/assets/removed.jar
new file mode 100644
index 0000000..2100322
--- /dev/null
+++ b/tests/tests/util/assets/removed.jar
Binary files differ
diff --git a/tests/tests/util/src/android/util/cts/LocaleListTest.java b/tests/tests/util/src/android/util/cts/LocaleListTest.java
index 1703591..f824aa8 100644
--- a/tests/tests/util/src/android/util/cts/LocaleListTest.java
+++ b/tests/tests/util/src/android/util/cts/LocaleListTest.java
@@ -16,6 +16,7 @@
package android.util.cts;
+import android.os.Parcel;
import android.util.LocaleList;
import android.test.AndroidTestCase;
@@ -191,4 +192,137 @@
assertTrue(ll.size() >= 1);
assertEquals(Locale.getDefault(), ll.getPrimary());
}
+
+ public void testParcelable() {
+ // Make sure an empty LocaleList can be marshalled/unmarshalled via Parcel.
+ assertEquals(LocaleList.getEmptyLocaleList(),
+ cloneViaParcel(LocaleList.getEmptyLocaleList()));
+
+ // Make sure a non-empty LocaleList can be marshalled/unmarshalled via Parcel.
+ LocaleList original = LocaleList.forLanguageTags("en-PH,en-US");
+ assertEquals(original, cloneViaParcel(original));
+ }
+
+ private static LocaleList cloneViaParcel(final LocaleList original) {
+ Parcel parcel = null;
+ try {
+ parcel = Parcel.obtain();
+ original.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ return LocaleList.CREATOR.createFromParcel(parcel);
+ } finally {
+ if (parcel != null) {
+ parcel.recycle();
+ }
+ }
+ }
+
+ public void testGetFirstMatch_noAssets() {
+ String[] noAssets = {};
+ assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(noAssets));
+ assertEquals(
+ Locale.forLanguageTag("fr-BE"),
+ LocaleList.forLanguageTags("fr-BE").getFirstMatch(noAssets));
+ assertEquals(
+ Locale.forLanguageTag("fr-BE"),
+ LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(noAssets));
+ }
+
+ public void testGetFirstMatch_oneAsset() {
+ String[] oneDutchAsset = {"nl"};
+ assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(oneDutchAsset));
+ assertEquals(
+ Locale.forLanguageTag("fr-BE"),
+ LocaleList.forLanguageTags("fr-BE").getFirstMatch(oneDutchAsset));
+ assertEquals(
+ Locale.forLanguageTag("nl-BE"),
+ LocaleList.forLanguageTags("nl-BE").getFirstMatch(oneDutchAsset));
+ assertEquals(
+ Locale.forLanguageTag("nl-BE"),
+ LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(oneDutchAsset));
+ assertEquals(
+ Locale.forLanguageTag("nl-BE"),
+ LocaleList.forLanguageTags("nl-BE,fr-BE").getFirstMatch(oneDutchAsset));
+ }
+
+ public void testGetFirstMatch_twoAssets() {
+ String[] FrenchAndDutchAssets = {"fr", "nl"};
+ assertNull(LocaleList.getEmptyLocaleList().getFirstMatch(FrenchAndDutchAssets));
+ assertEquals(
+ Locale.forLanguageTag("fr-BE"),
+ LocaleList.forLanguageTags("fr-BE").getFirstMatch(FrenchAndDutchAssets));
+ assertEquals(
+ Locale.forLanguageTag("nl-BE"),
+ LocaleList.forLanguageTags("nl-BE").getFirstMatch(FrenchAndDutchAssets));
+ assertEquals(
+ Locale.forLanguageTag("fr-BE"),
+ LocaleList.forLanguageTags("fr-BE,nl-BE").getFirstMatch(FrenchAndDutchAssets));
+ assertEquals(
+ Locale.forLanguageTag("nl-BE"),
+ LocaleList.forLanguageTags("nl-BE,fr-BE").getFirstMatch(FrenchAndDutchAssets));
+ }
+
+ public void testGetFirstMatch_oneChineseAsset() {
+ String[] oneChineseAsset = {"zh-CN"}; // Assumed to mean zh-Hans-CN
+ // The following Chinese examples would all match, so they will be chosen.
+ assertEquals(
+ Locale.forLanguageTag("zh"),
+ LocaleList.forLanguageTags("ko-KR,zh").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("zh-CN"),
+ LocaleList.forLanguageTags("ko-KR,zh-CN").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("zh-Hans"),
+ LocaleList.forLanguageTags("ko-KR,zh-Hans").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("zh-Hans-CN"),
+ LocaleList.forLanguageTags("ko-KR,zh-Hans-CN").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("zh-Hans-HK"),
+ LocaleList.forLanguageTags("ko-KR,zh-Hans-HK").getFirstMatch(oneChineseAsset));
+
+ // The following Chinese examples wouldn't match, so the first locale will be chosen
+ // instead.
+ assertEquals(
+ Locale.forLanguageTag("ko-KR"),
+ LocaleList.forLanguageTags("ko-KR,zh-TW").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("ko-KR"),
+ LocaleList.forLanguageTags("ko-KR,zh-Hant").getFirstMatch(oneChineseAsset));
+ assertEquals(
+ Locale.forLanguageTag("ko-KR"),
+ LocaleList.forLanguageTags("ko-KR,zh-Hant-TW").getFirstMatch(oneChineseAsset));
+ }
+
+ public void testGetFirstMatch_serbianCyrillic() {
+ String[] oneSerbianAsset = {"sr"}; // Assumed to mean sr-Cyrl-RS
+ // The following Serbian examples would all match, so they will be chosen.
+ assertEquals(
+ Locale.forLanguageTag("sr"),
+ LocaleList.forLanguageTags("hr-HR,sr").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("sr-RS"),
+ LocaleList.forLanguageTags("hr-HR,sr-RS").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("sr-Cyrl"),
+ LocaleList.forLanguageTags("hr-HR,sr-Cyrl").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("sr-Cyrl-RS"),
+ LocaleList.forLanguageTags("hr-HR,sr-Cyrl-RS").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("sr-Cyrl-ME"),
+ LocaleList.forLanguageTags("hr-HR,sr-Cyrl-ME").getFirstMatch(oneSerbianAsset));
+
+ // The following Serbian examples wouldn't match, so the first locale will be chosen
+ // instead.
+ assertEquals(
+ Locale.forLanguageTag("hr-HR"),
+ LocaleList.forLanguageTags("hr-HR,sr-ME").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("hr-HR"),
+ LocaleList.forLanguageTags("hr-HR,sr-Latn").getFirstMatch(oneSerbianAsset));
+ assertEquals(
+ Locale.forLanguageTag("hr-HR"),
+ LocaleList.forLanguageTags("hr-HR,sr-Latn-ME").getFirstMatch(oneSerbianAsset));
+ }
}
diff --git a/tests/tests/util/src/android/util/cts/PatternsTest.java b/tests/tests/util/src/android/util/cts/PatternsTest.java
new file mode 100644
index 0000000..61755ef
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/PatternsTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.cts;
+
+import android.util.Patterns;
+
+import junit.framework.TestCase;
+
+/**
+ * Test {@link Patterns}.
+ */
+public class PatternsTest extends TestCase {
+
+ public void testWebUrl_matchesUrlsWithCommasInRequestParameterValues() throws Exception {
+ String url = "https://android.com/path?ll=37.4221,-122.0836&z=17&pll=37.4221,-122.0836";
+ assertTrue("WEB_URL pattern should match commas", Patterns.WEB_URL.matcher(url).matches());
+ }
+}
diff --git a/tests/tests/util/src/android/util/cts/PropertyTest.java b/tests/tests/util/src/android/util/cts/PropertyTest.java
new file mode 100644
index 0000000..22ad2c4
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/PropertyTest.java
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.cts;
+
+import android.graphics.Point;
+import android.util.FloatProperty;
+import android.util.IntProperty;
+import android.util.Property;
+import junit.framework.TestCase;
+
+public class PropertyTest extends TestCase {
+
+ float mFloatValue = -1;
+ int mIntValue = -2;
+ Point mPointValue = new Point(-3, -4);
+
+ public void testProperty() throws Exception {
+ float testFloatValue = 5;
+ Point testPointValue = new Point(10, 20);
+
+ assertFalse(getFloatProp() == testFloatValue);
+ assertFalse(getPointProp().equals(testPointValue));
+ assertEquals(RAW_FLOAT_PROP.get(this), getFloatProp());
+ assertEquals(RAW_POINT_PROP.get(this), getPointProp());
+
+ RAW_FLOAT_PROP.set(this, testFloatValue);
+ assertEquals(RAW_FLOAT_PROP.get(this), mFloatValue);
+
+ RAW_POINT_PROP.set(this, testPointValue);
+ assertEquals(RAW_POINT_PROP.get(this), testPointValue);
+ }
+
+ public void testFloatProperty() throws Exception {
+ float testFloatValue = 5;
+
+ assertFalse(getFloatProp() == testFloatValue);
+ assertEquals(FLOAT_PROP.get(this), getFloatProp());
+
+ FLOAT_PROP.set(this, testFloatValue);
+ assertEquals(FLOAT_PROP.get(this), testFloatValue);
+ }
+
+ public void testIntProperty() throws Exception {
+ int testIntValue = 5;
+
+ assertFalse(getIntProp() == testIntValue);
+ assertEquals(INT_PROP.get(this).intValue(), getIntProp());
+
+ INT_PROP.set(this, testIntValue);
+ assertEquals(INT_PROP.get(this).intValue(), testIntValue);
+ }
+
+ // Utility methods to get/set instance values. Used by Property classes below.
+
+ private void setFloatProp(float value) {
+ mFloatValue = value;
+ }
+
+ private float getFloatProp() {
+ return mFloatValue;
+ }
+
+ private void setIntProp(int value) {
+ mIntValue = value;
+ }
+
+ private int getIntProp() {
+ return mIntValue;
+ }
+
+ private void setPointProp(Point value) {
+ mPointValue = value;
+ }
+
+ private Point getPointProp() {
+ return mPointValue;
+ }
+
+ // Properties. RAW subclass from the generic Property class, the others subclass from
+ // the primtive-friendly IntProperty and FloatProperty subclasses.
+
+ public static final Property<PropertyTest, Point> RAW_POINT_PROP =
+ new Property<PropertyTest, Point>(Point.class, "rawPoint") {
+ @Override
+ public void set(PropertyTest object, Point value) {
+ object.setPointProp(value);
+ }
+
+ @Override
+ public Point get(PropertyTest object) {
+ return object.getPointProp();
+ }
+ };
+
+ public static final Property<PropertyTest, Float> RAW_FLOAT_PROP =
+ new Property<PropertyTest, Float>(Float.class, "rawFloat") {
+ @Override
+ public void set(PropertyTest object, Float value) {
+ object.setFloatProp(value);
+ }
+
+ @Override
+ public Float get(PropertyTest object) {
+ return object.getFloatProp();
+ }
+ };
+
+ public static final Property<PropertyTest, Float> FLOAT_PROP =
+ new FloatProperty<PropertyTest>("float") {
+
+ @Override
+ public void setValue(PropertyTest object, float value) {
+ object.setFloatProp(value);
+ }
+
+ @Override
+ public Float get(PropertyTest object) {
+ return object.getFloatProp();
+ }
+ };
+
+ public static final Property<PropertyTest, Integer> INT_PROP =
+ new IntProperty<PropertyTest>("int") {
+
+ @Override
+ public void setValue(PropertyTest object, int value) {
+ object.setIntProp(value);
+ }
+
+ @Override
+ public Integer get(PropertyTest object) {
+ return object.getIntProp();
+ }
+ };
+}
diff --git a/tests/tests/util/src/android/util/cts/StrictJarFileTest.java b/tests/tests/util/src/android/util/cts/StrictJarFileTest.java
new file mode 100644
index 0000000..e7eedfd
--- /dev/null
+++ b/tests/tests/util/src/android/util/cts/StrictJarFileTest.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2013 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.util.cts;
+
+import android.test.AndroidTestCase;
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.InputStream;
+import java.io.FileOutputStream;
+import java.io.OutputStream;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.HashMap;
+import java.util.Iterator;
+import android.util.jar.StrictJarFile;
+import java.util.zip.ZipEntry;
+import libcore.io.Streams;
+
+public class StrictJarFileTest extends AndroidTestCase {
+
+ // A well formed jar file with 6 entries.
+ private static final String JAR_1 = "hyts_patch.jar";
+
+ private File resources;
+
+ @Override
+ protected void setUp() {
+ try {
+ resources = File.createTempFile("sjf_resources", "", null);
+ resources.delete();
+ resources.mkdirs();
+ } catch (IOException e) {
+ throw new RuntimeException("Unable to create temp folder", e);
+ }
+ resources.deleteOnExit();
+ }
+
+ public void testConstructor() throws Exception {
+ try {
+ StrictJarFile jarFile = new StrictJarFile("Wrong.file");
+ fail("Should throw IOException");
+ } catch (IOException e) {
+ // expected
+ }
+
+ copyFile(JAR_1);
+ String fileName = (new File(resources, JAR_1)).getCanonicalPath();
+ StrictJarFile jarFile = new StrictJarFile(fileName);
+ jarFile.close();
+ }
+
+ public void testIteration() throws Exception {
+ copyFile(JAR_1);
+ StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
+
+ Iterator<ZipEntry> it = jarFile.iterator();
+ HashMap<String, ZipEntry> entries = new HashMap<String, ZipEntry>();
+ while (it.hasNext()) {
+ final ZipEntry ze = it.next();
+ entries.put(ze.getName(), ze);
+ }
+
+ assertEquals(6, entries.size());
+ assertTrue(entries.containsKey("META-INF/"));
+
+ assertTrue(entries.containsKey("META-INF/MANIFEST.MF"));
+ ZipEntry ze = entries.get("META-INF/MANIFEST.MF");
+ assertEquals(62, ze.getSize());
+ assertEquals(ZipEntry.DEFLATED, ze.getMethod());
+ assertEquals(61, ze.getCompressedSize());
+
+ assertTrue(entries.containsKey("Blah.txt"));
+ ze = entries.get("Blah.txt");
+ assertEquals(4, ze.getSize());
+ assertEquals(ZipEntry.DEFLATED, ze.getMethod());
+ assertEquals(6, ze.getCompressedSize());
+ assertEquals("Blah", new String(Streams.readFully(jarFile.getInputStream(ze)),
+ Charset.forName("UTF-8")));
+
+ assertTrue(entries.containsKey("foo/"));
+ assertTrue(entries.containsKey("foo/bar/"));
+ assertTrue(entries.containsKey("foo/bar/A.class"));
+ ze = entries.get("foo/bar/A.class");
+ assertEquals(311, ze.getSize());
+ assertEquals(ZipEntry.DEFLATED, ze.getMethod());
+ assertEquals(225, ze.getCompressedSize());
+ }
+
+ public void testFindEntry() throws Exception {
+ copyFile(JAR_1);
+ StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
+
+ assertNull(jarFile.findEntry("foobar"));
+ assertNull(jarFile.findEntry("blah.txt"));
+ assertNotNull(jarFile.findEntry("Blah.txt"));
+ final ZipEntry ze = jarFile.findEntry("Blah.txt");
+ assertEquals(4, ze.getSize());
+ assertEquals(ZipEntry.DEFLATED, ze.getMethod());
+ assertEquals(6, ze.getCompressedSize());
+ assertEquals("Blah", new String(Streams.readFully(jarFile.getInputStream(ze)),
+ Charset.forName("UTF-8")));
+ }
+
+ public void testGetManifest() throws Exception {
+ copyFile(JAR_1);
+ StrictJarFile jarFile = new StrictJarFile(new File(resources, JAR_1).getAbsolutePath());
+
+ assertNotNull(jarFile.getManifest());
+ assertEquals("1.4.2 (IBM Corporation)", jarFile.getManifest().getMainAttributes().getValue("Created-By"));
+ }
+
+ public void testJarSigning_wellFormed() throws IOException {
+ copyFile("Integrate.jar");
+ StrictJarFile jarFile = new StrictJarFile(new File(resources, "Integrate.jar").getAbsolutePath());
+ Iterator<ZipEntry> entries = jarFile.iterator();
+ while (entries.hasNext()) {
+ ZipEntry zipEntry = entries.next();
+ jarFile.getInputStream(zipEntry).skip(Long.MAX_VALUE);
+ if ("Test.class".equals(zipEntry.getName())) {
+ assertNotNull(jarFile.getCertificates(zipEntry));
+ assertNotNull(jarFile.getCertificateChains(zipEntry));
+ }
+ }
+ }
+
+ public void testJarSigning_fudgedEntry() throws IOException {
+ copyFile("Integrate.jar");
+ StrictJarFile jarFile = new StrictJarFile(
+ new File(resources, "Integrate.jar").getAbsolutePath());
+
+ ZipEntry ze = jarFile.findEntry("Test.class");
+ jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
+
+ // Fudge the size so that certificates do not match.
+ ze.setSize(ze.getSize() - 1);
+ try {
+ jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ public void testJarSigning_modifiedClass() throws IOException {
+ copyFile("Modified_Class.jar");
+ StrictJarFile jarFile = new StrictJarFile(
+ new File(resources, "Modified_Class.jar").getAbsolutePath());
+
+ ZipEntry ze = jarFile.findEntry("Test.class");
+ try {
+ jarFile.getInputStream(ze).skip(Long.MAX_VALUE);
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+ public void testJarSigning_brokenMainAttributes() throws Exception {
+ assertThrowsOnInit("Modified_Manifest_MainAttributes.jar");
+ }
+
+ public void testJarSigning_brokenEntryAttributes() throws Exception {
+ assertThrowsOnInit("Modified_Manifest_EntryAttributes.jar");
+ }
+
+ public void testJarSigning_brokenSignatureFile() throws Exception {
+ assertThrowsOnInit("Modified_SF_EntryAttributes.jar");
+ }
+
+ public void testJarSigning_removedEntry() throws Exception {
+ assertThrowsOnInit("removed.jar");
+ }
+
+ private void assertThrowsOnInit(String name) throws Exception {
+ copyFile(name);
+ try {
+ StrictJarFile jarFile = new StrictJarFile(
+ new File(resources, name).getAbsolutePath());
+ fail();
+ } catch (SecurityException expected) {
+ }
+ }
+
+
+ public File copyFile(String file) {
+ File dest = new File(resources.toString() + "/" + file);
+
+ if (!dest.exists()) {
+ try {
+ InputStream in = getContext().getAssets().open(file);
+ FileOutputStream out = new FileOutputStream(dest);
+ byte[] buffer = new byte[8192];
+ int c;
+ while ((c = in.read(buffer)) != -1) {
+ out.write(buffer, 0, c);
+ }
+ out.close();
+ dest.deleteOnExit();
+ in.close();
+ } catch (IOException e) {
+ throw new RuntimeException(
+ "Unable to copy file from resource " + file + " to file " + dest, e);
+ }
+ }
+ return dest;
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/FocusFinderTest.java b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
index 7f47037..6b3b784 100644
--- a/tests/tests/view/src/android/view/cts/FocusFinderTest.java
+++ b/tests/tests/view/src/android/view/cts/FocusFinderTest.java
@@ -46,6 +46,10 @@
mTopRight = getActivity().topRightButton;
mBottomLeft = getActivity().bottomLeftButton;
mBottomRight = getActivity().bottomRightButton;
+ mTopLeft.setNextFocusLeftId(View.NO_ID);
+ mTopRight.setNextFocusLeftId(View.NO_ID);
+ mBottomLeft.setNextFocusLeftId(View.NO_ID);
+ mBottomRight.setNextFocusLeftId(View.NO_ID);
}
public void testGetInstance() {
@@ -169,4 +173,50 @@
assertEquals(0, deltas[0]);
assertEquals(-1, deltas[1]);
}
+
+ public void testFindNextAndPrevFocusAvoidingChain() {
+ mBottomRight.setNextFocusForwardId(mBottomLeft.getId());
+ mBottomLeft.setNextFocusForwardId(mTopRight.getId());
+ // Follow the chain
+ assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mBottomLeft);
+ assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+ assertNextFocus(mTopRight, View.FOCUS_BACKWARD, mBottomLeft);
+ assertNextFocus(mBottomLeft, View.FOCUS_BACKWARD, mBottomRight);
+
+ // Now go to the one not in the chain
+ assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+ assertNextFocus(mBottomRight, View.FOCUS_BACKWARD, mTopLeft);
+
+ // Now go back to the top of the chain
+ assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mBottomRight);
+ assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mTopRight);
+
+ // Now make the chain a circle -- this is the pathological case
+ mTopRight.setNextFocusForwardId(mBottomRight.getId());
+ // Fall back to the next one in a chain.
+ assertNextFocus(mTopLeft, View.FOCUS_FORWARD, mTopRight);
+ assertNextFocus(mTopLeft, View.FOCUS_BACKWARD, mBottomRight);
+
+ //Now do branching focus changes
+ mTopRight.setNextFocusForwardId(View.NO_ID);
+ mBottomRight.setNextFocusForwardId(mTopRight.getId());
+ assertNextFocus(mBottomRight, View.FOCUS_FORWARD, mTopRight);
+ assertNextFocus(mBottomLeft, View.FOCUS_FORWARD, mTopRight);
+ // From the tail, it jumps out of the chain
+ assertNextFocus(mTopRight, View.FOCUS_FORWARD, mTopLeft);
+
+ // Back from the head of a tree goes out of the tree
+ // We don't know which is the head of the focus chain since it is branching.
+ View prevFocus1 = mFocusFinder.findNextFocus(mLayout, mBottomLeft, View.FOCUS_BACKWARD);
+ View prevFocus2 = mFocusFinder.findNextFocus(mLayout, mBottomRight, View.FOCUS_BACKWARD);
+ assertTrue(prevFocus1 == mTopLeft || prevFocus2 == mTopLeft);
+
+ // From outside, it chooses an arbitrary head of the chain
+ View nextFocus = mFocusFinder.findNextFocus(mLayout, mTopLeft, View.FOCUS_FORWARD);
+ assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
+
+ // Going back from the tail of the split chain, it chooses an arbitrary head
+ nextFocus = mFocusFinder.findNextFocus(mLayout, mTopRight, View.FOCUS_BACKWARD);
+ assertTrue(nextFocus == mBottomRight || nextFocus == mBottomLeft);
+ }
}
diff --git a/tests/tests/view/src/android/view/cts/ViewGroupTest.java b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
index 48afc2b..1b18fe9 100644
--- a/tests/tests/view/src/android/view/cts/ViewGroupTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewGroupTest.java
@@ -739,7 +739,10 @@
MockViewGroup vg = new MockViewGroup(mContext);
LayoutParams p = new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.MATCH_PARENT);
- assertSame(p, vg.generateLayoutParams(p));
+ LayoutParams generatedParams = vg.generateLayoutParams(p);
+ assertEquals(generatedParams.getClass(), p.getClass());
+ assertEquals(p.width, generatedParams.width);
+ assertEquals(p.height, generatedParams.height);
}
public void testGetChildDrawingOrder() {
diff --git a/tests/tests/view/src/android/view/cts/ViewTest.java b/tests/tests/view/src/android/view/cts/ViewTest.java
index 1e4aa26..314bd2a 100644
--- a/tests/tests/view/src/android/view/cts/ViewTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewTest.java
@@ -16,6 +16,7 @@
package android.view.cts;
+import android.view.ViewTreeObserver;
import android.view.cts.R;
import com.android.internal.view.menu.ContextMenuBuilder;
@@ -45,6 +46,7 @@
import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.Pair;
import android.util.SparseArray;
import android.util.Xml;
import android.view.ActionMode;
@@ -84,9 +86,12 @@
import android.widget.LinearLayout;
import android.widget.ListView;
+import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link View}.
@@ -146,6 +151,37 @@
}
}
+ // Test that validates that Views can be constructed on a thread that
+ // does not have a Looper. Necessary for async inflation
+ private Pair<Class<?>, Throwable> sCtorException = null;
+ public void testConstructor2() throws Exception {
+ final Object[] args = new Object[] { mActivity, null };
+ final CountDownLatch latch = new CountDownLatch(1);
+ sCtorException = null;
+ new Thread() {
+ public void run() {
+ final Class<?>[] ctorSignature = new Class[] {
+ Context.class, AttributeSet.class};
+ for (Class<?> clazz : ASYNC_INFLATE_VIEWS) {
+ try {
+ Constructor<?> constructor = clazz.getConstructor(ctorSignature);
+ constructor.setAccessible(true);
+ constructor.newInstance(args);
+ } catch (Throwable t) {
+ sCtorException = new Pair<Class<?>, Throwable>(clazz, t);
+ break;
+ }
+ }
+ latch.countDown();
+ }
+ }.start();
+ latch.await();
+ if (sCtorException != null) {
+ throw new AssertionError("Failed to inflate "
+ + sCtorException.first.getName(), sCtorException.second);
+ }
+ }
+
public void testGetContext() {
View view = new View(mActivity);
assertSame(mActivity, view.getContext());
@@ -2230,6 +2266,71 @@
assertTrue(listener.hasOnClick());
}
+ private void checkBounds(final ViewGroup viewGroup, final View view,
+ final CountDownLatch countDownLatch, final int left, final int top,
+ final int width, final int height) {
+ viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ assertEquals(left, view.getLeft());
+ assertEquals(top, view.getTop());
+ assertEquals(width, view.getWidth());
+ assertEquals(height, view.getHeight());
+ countDownLatch.countDown();
+ viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+
+ public void testAddRemoveAffectsWrapContentLayout() throws Throwable {
+ final int childWidth = 100;
+ final int childHeight = 200;
+ final int parentHeight = 400;
+ final MockLinearLayout parent = new MockLinearLayout(mActivity);
+ ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT, parentHeight);
+ parent.setLayoutParams(parentParams);
+ final MockView child = new MockView(mActivity);
+ child.setBackgroundColor(Color.GREEN);
+ ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+ child.setLayoutParams(childParams);
+ final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.viewlayout_root);
+
+ // Idea:
+ // Add the wrap_content parent view to the hierarchy (removing other views as they
+ // are not needed), test that parent is 0xparentHeight
+ // Add the child view to the parent, test that parent has same width as child
+ // Remove the child view from the parent, test that parent is 0xparentHeight
+ final CountDownLatch countDownLatch1 = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ viewGroup.removeAllViews();
+ viewGroup.addView(parent);
+ checkBounds(viewGroup, parent, countDownLatch1, 0, 0, 0, parentHeight);
+ }
+ });
+ countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+
+ final CountDownLatch countDownLatch2 = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ parent.addView(child);
+ checkBounds(viewGroup, parent, countDownLatch2, 0, 0, childWidth, parentHeight);
+ }
+ });
+ countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+
+ final CountDownLatch countDownLatch3 = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ parent.removeView(child);
+ checkBounds(viewGroup, parent, countDownLatch3, 0, 0, 0, parentHeight);
+ }
+ });
+ countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+ }
+
@UiThreadTest
public void testDispatchKeyEvent() {
MockView view = (MockView) mActivity.findViewById(R.id.mock_view);
@@ -4095,4 +4196,75 @@
hasRun = true;
}
}
+
+ private static Class<?> ASYNC_INFLATE_VIEWS[] = {
+ android.app.FragmentBreadCrumbs.class,
+// DISABLED because it doesn't have a AppWidgetHostView(Context, AttributeSet)
+// constructor, so it's not inflate-able
+// android.appwidget.AppWidgetHostView.class,
+ android.gesture.GestureOverlayView.class,
+ android.inputmethodservice.ExtractEditText.class,
+ android.inputmethodservice.KeyboardView.class,
+// android.media.tv.TvView.class,
+// android.opengl.GLSurfaceView.class,
+// android.view.SurfaceView.class,
+ android.view.TextureView.class,
+ android.view.ViewStub.class,
+// android.webkit.WebView.class,
+ android.widget.AbsoluteLayout.class,
+ android.widget.AdapterViewFlipper.class,
+ android.widget.AnalogClock.class,
+ android.widget.AutoCompleteTextView.class,
+ android.widget.Button.class,
+ android.widget.CalendarView.class,
+ android.widget.CheckBox.class,
+ android.widget.CheckedTextView.class,
+ android.widget.Chronometer.class,
+ android.widget.DatePicker.class,
+ android.widget.DialerFilter.class,
+ android.widget.DigitalClock.class,
+ android.widget.EditText.class,
+ android.widget.ExpandableListView.class,
+ android.widget.FrameLayout.class,
+ android.widget.Gallery.class,
+ android.widget.GridView.class,
+ android.widget.HorizontalScrollView.class,
+ android.widget.ImageButton.class,
+ android.widget.ImageSwitcher.class,
+ android.widget.ImageView.class,
+ android.widget.LinearLayout.class,
+ android.widget.ListView.class,
+ android.widget.MediaController.class,
+ android.widget.MultiAutoCompleteTextView.class,
+ android.widget.NumberPicker.class,
+ android.widget.ProgressBar.class,
+ android.widget.QuickContactBadge.class,
+ android.widget.RadioButton.class,
+ android.widget.RadioGroup.class,
+ android.widget.RatingBar.class,
+ android.widget.RelativeLayout.class,
+ android.widget.ScrollView.class,
+ android.widget.SeekBar.class,
+// DISABLED because it has required attributes
+// android.widget.SlidingDrawer.class,
+ android.widget.Spinner.class,
+ android.widget.StackView.class,
+ android.widget.Switch.class,
+ android.widget.TabHost.class,
+ android.widget.TabWidget.class,
+ android.widget.TableLayout.class,
+ android.widget.TableRow.class,
+ android.widget.TextClock.class,
+ android.widget.TextSwitcher.class,
+ android.widget.TextView.class,
+ android.widget.TimePicker.class,
+ android.widget.ToggleButton.class,
+ android.widget.TwoLineListItem.class,
+// android.widget.VideoView.class,
+ android.widget.ViewAnimator.class,
+ android.widget.ViewFlipper.class,
+ android.widget.ViewSwitcher.class,
+ android.widget.ZoomButton.class,
+ android.widget.ZoomControls.class,
+ };
}
diff --git a/tests/tests/view/src/android/view/cts/WindowTest.java b/tests/tests/view/src/android/view/cts/WindowTest.java
index ad9f2ca..3b1cb04 100644
--- a/tests/tests/view/src/android/view/cts/WindowTest.java
+++ b/tests/tests/view/src/android/view/cts/WindowTest.java
@@ -16,6 +16,7 @@
package android.view.cts;
+import android.view.ContextThemeWrapper;
import android.view.cts.R;
import android.app.Instrumentation;
@@ -292,7 +293,7 @@
int screenHeight = dm.heightPixels;
assertTrue(decor.getWidth() >= screenWidth);
assertTrue(decor.getHeight() >= screenHeight);
- assertSame(mWindow.getContext(), decor.getContext());
+ assertTrue(decor.getContext() instanceof ContextThemeWrapper);
}
/**
@@ -868,7 +869,6 @@
public void addContentView(View view, ViewGroup.LayoutParams params) {
}
- @Override
public void clearContentView() {
}
@@ -1029,6 +1029,16 @@
}
@Override
+ public void setDecorCaptionShade(int decorCaptionShade) {
+
+ }
+
+ @Override
+ public void setResizingCaptionDrawable(Drawable drawable) {
+
+ }
+
+ @Override
public int getNavigationBarColor() {
return 0;
}
diff --git a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
index fb34983..9184881 100644
--- a/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
+++ b/tests/tests/view/src/android/view/inputmethod/cts/EditorInfoTest.java
@@ -21,6 +21,7 @@
import android.os.Parcel;
import android.test.AndroidTestCase;
import android.text.TextUtils;
+import android.util.LocaleList;
import android.util.Printer;
import android.view.inputmethod.EditorInfo;
@@ -48,6 +49,7 @@
String value = "bundleValue";
b.putString(key, value);
info.extras = b;
+ info.locales = LocaleList.forLanguageTags("en-PH,en-US");
assertEquals(0, info.describeContents());
@@ -70,6 +72,7 @@
assertEquals(info.actionLabel.toString(), targetInfo.actionLabel.toString());
assertEquals(info.label.toString(), targetInfo.label.toString());
assertEquals(info.extras.getString(key), targetInfo.extras.getString(key));
+ assertEquals(info.locales, targetInfo.locales);
TestPrinter printer = new TestPrinter();
String prefix = "TestEditorInfo";
diff --git a/tests/tests/webkit/AndroidTest.xml b/tests/tests/webkit/AndroidTest.xml
index 0b2d748..b2945f2 100644
--- a/tests/tests/webkit/AndroidTest.xml
+++ b/tests/tests/webkit/AndroidTest.xml
@@ -15,6 +15,7 @@
-->
<configuration description="Config for CTS Webkit test cases">
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.WifiCheck" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.LocationCheck" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.ApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsWebkitTestCases.apk" />
@@ -22,4 +23,5 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.webkit.cts" />
</test>
+
</configuration>
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index 3a3e102..1267ccb 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -88,7 +88,7 @@
return;
}
final WebViewClient webViewClient = new WebViewClient();
- assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), null));
+ assertFalse(webViewClient.shouldOverrideUrlLoading(mOnUiThread.getWebView(), new String()));
}
// Verify shouldoverrideurlloading called on top level navigation
diff --git a/tests/tests/widget/Android.mk b/tests/tests/widget/Android.mk
index 888c0e6..fa2b60a 100644
--- a/tests/tests/widget/Android.mk
+++ b/tests/tests/widget/Android.mk
@@ -21,7 +21,7 @@
# and when built explicitly put it in the data partition
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES += android-common ctsdeviceutil ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES += mockito-target android-common ctsdeviceutil ctstestrunner
LOCAL_JAVA_LIBRARIES := android.test.runner
diff --git a/tests/tests/widget/res/layout/linearlayout_layout.xml b/tests/tests/widget/res/layout/linearlayout_layout.xml
index c70937d..8881552 100644
--- a/tests/tests/widget/res/layout/linearlayout_layout.xml
+++ b/tests/tests/widget/res/layout/linearlayout_layout.xml
@@ -15,6 +15,7 @@
* limitations under the License.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/linearlayout_root"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
diff --git a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
index af4c9d4..039ca70 100644
--- a/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/CheckedTextViewTest.java
@@ -16,6 +16,7 @@
package android.widget.cts;
+import android.os.Parcelable;
import android.widget.cts.R;
@@ -277,6 +278,24 @@
assertNotNull(checkedTextView.getCheckMarkDrawable());
}
+ public void testAccessInstanceState() {
+ CheckedTextView checkedTextView = new MockCheckedTextView(mActivity);
+ Parcelable state;
+
+ assertFalse(checkedTextView.isChecked());
+ assertFalse(checkedTextView.getFreezesText());
+
+ state = checkedTextView.onSaveInstanceState();
+ assertNotNull(state);
+ assertFalse(checkedTextView.getFreezesText());
+
+ checkedTextView.setChecked(true);
+
+ checkedTextView.onRestoreInstanceState(state);
+ assertFalse(checkedTextView.isChecked());
+ assertTrue(checkedTextView.isLayoutRequested());
+ }
+
public void testOnDraw() {
// Do not test. Implementation details.
}
diff --git a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
index 1547b9a..5774b53 100644
--- a/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/FrameLayout_LayoutParamsTest.java
@@ -16,6 +16,7 @@
package android.widget.cts;
+import android.view.Gravity;
import android.widget.cts.R;
@@ -75,4 +76,47 @@
// expected, test success.
}
}
+
+ public void testCopyConstructor() {
+ FrameLayout.LayoutParams copy;
+
+ final FrameLayout.LayoutParams fllp = new FrameLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ fllp.gravity = Gravity.BOTTOM;
+ fllp.leftMargin = 5;
+ fllp.topMargin = 10;
+ fllp.rightMargin = 15;
+ fllp.bottomMargin = 20;
+
+ copy = new FrameLayout.LayoutParams(fllp);
+ assertEquals("Width", fllp.width, copy.width);
+ assertEquals("Height", fllp.height, copy.height);
+ assertEquals("Gravity", fllp.gravity, copy.gravity);
+ assertEquals("Left margin", fllp.leftMargin, copy.leftMargin);
+ assertEquals("Top margin", fllp.topMargin, copy.topMargin);
+ assertEquals("Right margin", fllp.rightMargin, copy.rightMargin);
+ assertEquals("Bottom margin", fllp.bottomMargin, copy.bottomMargin);
+
+ final MarginLayoutParams mlp = new MarginLayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+ mlp.leftMargin = 5;
+ mlp.topMargin = 10;
+ mlp.rightMargin = 15;
+ mlp.bottomMargin = 20;
+
+ copy = new FrameLayout.LayoutParams(mlp);
+ assertEquals("Width", mlp.width, copy.width);
+ assertEquals("Height", mlp.height, copy.height);
+ assertEquals("Left margin", fllp.leftMargin, copy.leftMargin);
+ assertEquals("Top margin", fllp.topMargin, copy.topMargin);
+ assertEquals("Right margin", fllp.rightMargin, copy.rightMargin);
+ assertEquals("Bottom margin", fllp.bottomMargin, copy.bottomMargin);
+
+ final ViewGroup.LayoutParams vglp = new ViewGroup.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
+
+ copy = new FrameLayout.LayoutParams(vglp);
+ assertEquals("Width", vglp.width, copy.width);
+ assertEquals("Height", vglp.height, copy.height);
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
index 29aa03b..a7bca5c 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageSwitcherTest.java
@@ -170,7 +170,7 @@
if (target != null) {
target.close();
}
- } catch (IOException _) {
+ } catch (IOException ignored) {
// Ignore the IOException.
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
index 945e49c..e0d821d 100644
--- a/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/ImageViewTest.java
@@ -95,7 +95,7 @@
if (target != null) {
target.close();
}
- } catch (IOException _) {
+ } catch (IOException ignored) {
// Ignore the IOException.
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
index 78a8eee..76fa782 100644
--- a/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/LinearLayoutTest.java
@@ -16,6 +16,9 @@
package android.widget.cts;
+import android.graphics.Color;
+import android.view.View;
+import android.view.ViewTreeObserver;
import org.xmlpull.v1.XmlPullParser;
import android.app.Activity;
@@ -33,6 +36,9 @@
import android.widget.cts.R;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
/**
* Test {@link LinearLayout}.
*/
@@ -327,6 +333,78 @@
assertEquals(parent.getWidth(), rightView.getRight());
}
+ private void checkBounds(final ViewGroup viewGroup, final View view,
+ final CountDownLatch countDownLatch, final int left, final int top,
+ final int width, final int height) {
+ viewGroup.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
+ @Override
+ public boolean onPreDraw() {
+ assertEquals(left, view.getLeft());
+ assertEquals(top, view.getTop());
+ assertEquals(width, view.getWidth());
+ assertEquals(height, view.getHeight());
+ countDownLatch.countDown();
+ viewGroup.getViewTreeObserver().removeOnPreDrawListener(this);
+ return true;
+ }
+ });
+ }
+
+ public void testVisibilityAffectsLayout() throws Throwable {
+ // Toggling view visibility between GONE/VISIBLE can affect the position of
+ // other children in that container. This test verifies that these changes
+ // on the first child of a LinearLayout affects the position of a second child
+ final int childWidth = 100;
+ final int childHeight = 200;
+ final LinearLayout parent = new LinearLayout(mActivity);
+ ViewGroup.LayoutParams parentParams = new ViewGroup.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
+ parent.setLayoutParams(parentParams);
+ final View child1 = new View(mActivity);
+ child1.setBackgroundColor(Color.GREEN);
+ ViewGroup.LayoutParams childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+ child1.setLayoutParams(childParams);
+ final View child2 = new View(mActivity);
+ child2.setBackgroundColor(Color.RED);
+ childParams = new ViewGroup.LayoutParams(childWidth, childHeight);
+ child2.setLayoutParams(childParams);
+ final ViewGroup viewGroup = (ViewGroup) mActivity.findViewById(R.id.linearlayout_root);
+
+ final CountDownLatch countDownLatch1 = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ viewGroup.removeAllViews();
+ viewGroup.addView(parent);
+ parent.addView(child1);
+ parent.addView(child2);
+ checkBounds(viewGroup, child1, countDownLatch1, 0, 0, childWidth, childHeight);
+ checkBounds(viewGroup, child2, countDownLatch1,
+ childWidth, 0, childWidth, childHeight);
+ }
+ });
+ countDownLatch1.await(500, TimeUnit.MILLISECONDS);
+
+ final CountDownLatch countDownLatch2 = new CountDownLatch(1);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ child1.setVisibility(View.GONE);
+ checkBounds(viewGroup, child2, countDownLatch2, 0, 0, childWidth, childHeight);
+ }
+ });
+ countDownLatch2.await(500, TimeUnit.MILLISECONDS);
+
+ final CountDownLatch countDownLatch3 = new CountDownLatch(2);
+ runTestOnUiThread(new Runnable() {
+ public void run() {
+ child1.setVisibility(View.VISIBLE);
+ checkBounds(viewGroup, child1, countDownLatch3, 0, 0, childWidth, childHeight);
+ checkBounds(viewGroup, child2, countDownLatch3,
+ childWidth, 0, childWidth, childHeight);
+ }
+ });
+ countDownLatch3.await(500, TimeUnit.MILLISECONDS);
+ }
+
private class MockListView extends ListView {
private final static int DEFAULT_CHILD_BASE_LINE = 1;
diff --git a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
index d365158..713604d 100644
--- a/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
+++ b/tests/tests/widget/src/android/widget/cts/MediaControllerTest.java
@@ -182,7 +182,7 @@
if (target != null) {
target.close();
}
- } catch (final IOException _) {
+ } catch (final IOException ignored) {
// Ignore the IOException.
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
index 223920b..206b794 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupMenuTest.java
@@ -16,7 +16,7 @@
package android.widget.cts;
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
import android.app.Activity;
import android.app.Instrumentation;
@@ -24,6 +24,7 @@
import android.view.Gravity;
import android.widget.PopupMenu;
+import android.widget.cts.R;
public class PopupMenuTest extends
ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
@@ -45,6 +46,7 @@
PopupMenu popupMenu = new PopupMenu(mActivity,
mActivity.findViewById(R.id.anchor_middle_left));
assertEquals(Gravity.NO_GRAVITY, popupMenu.getGravity());
+
popupMenu.setGravity(Gravity.TOP);
assertEquals(Gravity.TOP, popupMenu.getGravity());
}
@@ -52,7 +54,7 @@
public void testOnDismissListener() {
final PopupMenu popupMenu = new PopupMenu(mActivity,
mActivity.findViewById(R.id.anchor_middle_left));
- TestPopupDismissListener listener = new TestPopupDismissListener();
+ PopupMenu.OnDismissListener listener = mock(PopupMenu.OnDismissListener.class);
popupMenu.setOnDismissListener(listener);
mInstrumentation.runOnMainSync(new Runnable() {
@@ -61,7 +63,7 @@
}
});
mInstrumentation.waitForIdleSync();
- assertEquals(0, listener.getDismissCount());
+ verify(listener, never()).onDismiss(popupMenu);
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
@@ -69,7 +71,7 @@
}
});
mInstrumentation.waitForIdleSync();
- assertEquals(1, listener.getDismissCount());
+ verify(listener, times(1)).onDismiss(popupMenu);
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
@@ -77,19 +79,6 @@
}
});
mInstrumentation.waitForIdleSync();
- assertEquals(1, listener.getDismissCount());
- }
-
- private class TestPopupDismissListener implements PopupMenu.OnDismissListener {
- int mDismissCount;
-
- @Override
- public void onDismiss(PopupMenu menu) {
- mDismissCount++;
- }
-
- int getDismissCount() {
- return mDismissCount;
- }
+ verify(listener, times(1)).onDismiss(popupMenu);
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index fe62d98..ff580e3 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -16,8 +16,9 @@
package android.widget.cts;
-import android.widget.cts.R;
+import static org.mockito.Mockito.*;
+import org.mockito.InOrder;
import android.app.Activity;
import android.app.Instrumentation;
@@ -25,24 +26,26 @@
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
-import android.os.Debug;
import android.os.SystemClock;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.transition.Transition;
+import android.transition.Transition.TransitionListener;
import android.transition.TransitionValues;
import android.view.Display;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.WindowManager;
import android.view.View.OnTouchListener;
+import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
+import android.view.WindowManager;
import android.widget.ImageView;
+import android.widget.PopupWindow.OnDismissListener;
import android.widget.PopupWindow;
import android.widget.TextView;
-import android.widget.PopupWindow.OnDismissListener;
+
+import android.widget.cts.R;
public class PopupWindowTest extends
ActivityInstrumentationTestCase2<MockPopupWindowCtsActivity> {
@@ -425,20 +428,20 @@
mPopupWindow = new PopupWindow(new TextView(mActivity));
mPopupWindow.setOnDismissListener(null);
- MockOnDismissListener onDismissListener = new MockOnDismissListener();
+ OnDismissListener onDismissListener = mock(OnDismissListener.class);
mPopupWindow.setOnDismissListener(onDismissListener);
showPopup();
dismissPopup();
- assertEquals(1, onDismissListener.getOnDismissCalledCount());
+ verify(onDismissListener, times(1)).onDismiss();
showPopup();
dismissPopup();
- assertEquals(2, onDismissListener.getOnDismissCalledCount());
+ verify(onDismissListener, times(2)).onDismiss();
mPopupWindow.setOnDismissListener(null);
showPopup();
dismissPopup();
- assertEquals(2, onDismissListener.getOnDismissCalledCount());
+ verify(onDismissListener, times(2)).onDismiss();
}
public void testUpdate() {
@@ -485,23 +488,34 @@
}
public void testEnterExitTransition() {
- mPopupWindow = createPopupWindow(createPopupContent());
- final View anchorView = mActivity.findViewById(R.id.anchor_upper);
+ TransitionListener enterListener = mock(TransitionListener.class);
+ Transition enterTransition = new BaseTransition();
+ enterTransition.addListener(enterListener);
- final MockTransition enterTransition = new MockTransition();
- final MockTransition exitTransition = new MockTransition();
+ TransitionListener exitListener = mock(TransitionListener.class);
+ Transition exitTransition = new BaseTransition();
+ enterTransition.addListener(enterListener);
+
+ OnDismissListener dismissListener = mock(OnDismissListener.class);
+
+ mPopupWindow = createPopupWindow(createPopupContent());
mPopupWindow.setEnterTransition(enterTransition);
mPopupWindow.setExitTransition(exitTransition);
+ mPopupWindow.setOnDismissListener(dismissListener);
+ verify(enterListener, never()).onTransitionStart(any(Transition.class));
+ verify(exitListener, never()).onTransitionStart(any(Transition.class));
+ verify(dismissListener, never()).onDismiss();
+ final View anchorView = mActivity.findViewById(R.id.anchor_upper);
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
mPopupWindow.showAsDropDown(anchorView, 0, 0);
}
});
mInstrumentation.waitForIdleSync();
-
- assertEquals(1, enterTransition.getTransitionCount());
- assertEquals(0, exitTransition.getTransitionCount());
+ verify(enterListener, times(1)).onTransitionStart(enterTransition);
+ verify(exitListener, never()).onTransitionStart(any(Transition.class));
+ verify(dismissListener, never()).onDismiss();
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
@@ -509,9 +523,13 @@
}
});
mInstrumentation.waitForIdleSync();
+ verify(enterListener, times(1)).onTransitionStart(enterTransition);
+ verify(exitListener, times(1)).onTransitionStart(exitTransition);
+ verify(dismissListener, times(1)).onDismiss();
- assertEquals(1, enterTransition.getTransitionCount());
- assertEquals(1, exitTransition.getTransitionCount());
+ InOrder inOrder = inOrder(exitListener, dismissListener);
+ inOrder.verify(exitListener).onTransitionEnd(exitTransition);
+ inOrder.verify(dismissListener).onDismiss();
}
public void testUpdatePositionAndDimension() {
@@ -774,7 +792,9 @@
public void testSetTouchInterceptor() {
mPopupWindow = new PopupWindow(new TextView(mActivity));
- MockOnTouchListener onTouchListener = new MockOnTouchListener();
+ OnTouchListener onTouchListener = mock(OnTouchListener.class);
+ when(onTouchListener.onTouch(any(View.class), any(MotionEvent.class))).thenReturn(true);
+
mPopupWindow.setTouchInterceptor(onTouchListener);
mPopupWindow.setFocusable(true);
mPopupWindow.setOutsideTouchable(true);
@@ -794,20 +814,20 @@
MotionEvent event = MotionEvent.obtain(downTime, eventTime,
MotionEvent.ACTION_DOWN, x, y, 0);
getInstrumentation().sendPointerSync(event);
- assertEquals(1, onTouchListener.getOnTouchCalledCount());
+ verify(onTouchListener, times(1)).onTouch(any(View.class), any(MotionEvent.class));
downTime = SystemClock.uptimeMillis();
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_UP, x, y, 0);
getInstrumentation().sendPointerSync(event);
- assertEquals(2, onTouchListener.getOnTouchCalledCount());
+ verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
mPopupWindow.setTouchInterceptor(null);
downTime = SystemClock.uptimeMillis();
eventTime = SystemClock.uptimeMillis();
event = MotionEvent.obtain(downTime, eventTime, MotionEvent.ACTION_DOWN, x, y, 0);
getInstrumentation().sendPointerSync(event);
- assertEquals(2, onTouchListener.getOnTouchCalledCount());
+ verify(onTouchListener, times(2)).onTouch(any(View.class), any(MotionEvent.class));
}
public void testSetWindowLayoutMode() {
@@ -829,107 +849,12 @@
assertEquals(LayoutParams.MATCH_PARENT, p.height);
}
- /**
- * The listener interface for receiving OnDismiss events. The class that is
- * interested in processing a OnDismiss event implements this interface, and
- * the object created with that class is registered with a component using
- * the component's <code>setOnDismissListener<code> method. When
- * the OnDismiss event occurs, that object's appropriate
- * method is invoked.
- */
- private static class MockOnDismissListener implements OnDismissListener {
+ private static class BaseTransition extends Transition {
+ @Override
+ public void captureStartValues(TransitionValues transitionValues) {}
- /** The Ondismiss called count. */
- private int mOnDismissCalledCount;
-
- /**
- * Gets the onDismiss() called count.
- *
- * @return the on dismiss called count
- */
- public int getOnDismissCalledCount() {
- return mOnDismissCalledCount;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see android.widget.PopupWindow.OnDismissListener#onDismiss()
- */
- public void onDismiss() {
- mOnDismissCalledCount++;
- }
-
- }
-
- /**
- * The listener interface for receiving touch events.
- */
- private static class MockOnTouchListener implements OnTouchListener {
-
- /** The onTouch called count. */
- private int mOnTouchCalledCount;
-
- /**
- * Gets the onTouch() called count.
- *
- * @return the onTouch() called count
- */
- public int getOnTouchCalledCount() {
- return mOnTouchCalledCount;
- }
-
- /*
- * (non-Javadoc)
- *
- * @see android.widget.PopupWindow.OnTouchListener#onDismiss()
- */
- public boolean onTouch(View v, MotionEvent event) {
- mOnTouchCalledCount++;
- return true;
- }
- }
-
- private static class MockTransition extends Transition {
- private int mTransitionCount;
-
- private MockTransition() {
- addListener(new Transition.TransitionListener() {
- @Override
- public void onTransitionStart(Transition transition) {
-
- }
-
- public void onTransitionEnd(Transition transition) {
- mTransitionCount++;
- }
-
- @Override
- public void onTransitionCancel(Transition transition) {
-
- }
-
- @Override
- public void onTransitionPause(Transition transition) {
-
- }
-
- @Override
- public void onTransitionResume(Transition transition) {
-
- }
- });
- }
-
- public void captureStartValues(TransitionValues transitionValues) {
- }
-
- public void captureEndValues(TransitionValues transitionValues) {
- }
-
- int getTransitionCount() {
- return mTransitionCount;
- }
+ @Override
+ public void captureEndValues(TransitionValues transitionValues) {}
}
private View createPopupContent() {
@@ -953,11 +878,6 @@
return window;
}
- /**
- * Show PopupWindow.
- */
- // FIXME: logcat info complains that there is window leakage due to that mPopupWindow is not
- // clean up. Need to fix it.
private void showPopup() {
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
@@ -972,14 +892,12 @@
mInstrumentation.waitForIdleSync();
}
- /**
- * Dismiss PopupWindow.
- */
private void dismissPopup() {
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
- if (mPopupWindow == null || !mPopupWindow.isShowing())
+ if (mPopupWindow == null || !mPopupWindow.isShowing()) {
return;
+ }
mPopupWindow.dismiss();
}
});
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index 6b7d737..605dbb6 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -633,7 +633,7 @@
if (target != null) {
target.close();
}
- } catch (IOException _) {
+ } catch (IOException ignored) {
// Ignore the IOException.
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 0ada600..c044252 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -16,6 +16,8 @@
package android.widget.cts;
+import android.text.Html;
+import android.text.Spanned;
import android.widget.cts.R;
import org.xmlpull.v1.XmlPullParserException;
@@ -1267,6 +1269,50 @@
}
}
+ @UiThreadTest
+ public void testSetText_setsMovementMethodWhenLinksClickableAndTextContainsClickableSpans() {
+ Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+ mTextView = new TextView(mActivity);
+
+ mTextView.setLinksClickable(false);
+ mTextView.setText(text);
+ assertNull("TextView.setText should not set movement method if linksClickable is false",
+ mTextView.getMovementMethod());
+
+ mTextView.setLinksClickable(true);
+ mTextView.setText(text);
+ assertNotNull("TextView.setText should set movement method if linksClickable is true " +
+ "and text contains clickable spans", mTextView.getMovementMethod());
+ }
+
+ public void testRemoveSelectionWithSelectionHandles() {
+ initTextViewForTyping();
+
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mTextView.setTextIsSelectable(true);
+ mTextView.setText("abcd", BufferType.EDITABLE);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+
+ // Long click on the text selects all text and shows selection handlers. The view has an
+ // attribute layout_width="wrap_content", so clicked location (the center of the view)
+ // should be on the text.
+ TouchUtils.longClickView(this, mTextView);
+
+ mActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ Selection.removeSelection((Spannable) mTextView.getText());
+ }
+ });
+
+ // Make sure that a crash doesn't happen with {@link Selection#removeSelection}.
+ mInstrumentation.waitForIdleSync();
+ }
+
public void testUndo_insert() {
initTextViewForTyping();
@@ -1700,6 +1746,64 @@
mInstrumentation.waitForIdleSync();
}
+ public void testCopyAndPaste_byKey() {
+ initTextViewForTyping();
+
+ // Type "abc".
+ mInstrumentation.sendStringSync("abc");
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ // Select "bc"
+ Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Copy "bc"
+ sendKeys(KeyEvent.KEYCODE_COPY);
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ // Set cursor between 'b' and 'c'.
+ Selection.setSelection((Spannable) mTextView.getText(), 2, 2);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Paste "bc"
+ sendKeys(KeyEvent.KEYCODE_PASTE);
+ assertEquals("abbcc", mTextView.getText().toString());
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ Selection.selectAll((Spannable) mTextView.getText());
+ KeyEvent copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_COPY, 0, KeyEvent.META_SHIFT_LEFT_ON);
+ // Shift + copy doesn't perform copy.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+ Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+ mTextView.onTextContextMenuItem(android.R.id.paste);
+ assertEquals("bcabbcc", mTextView.getText().toString());
+
+ Selection.selectAll((Spannable) mTextView.getText());
+ copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+ KeyEvent.META_CTRL_LEFT_ON);
+ // Control + copy doesn't perform copy.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+ Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+ mTextView.onTextContextMenuItem(android.R.id.paste);
+ assertEquals("bcbcabbcc", mTextView.getText().toString());
+
+ Selection.selectAll((Spannable) mTextView.getText());
+ copyWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_COPY, 0,
+ KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+ // Control + Shift + copy doesn't perform copy.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_COPY, copyWithMeta);
+ Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+ mTextView.onTextContextMenuItem(android.R.id.paste);
+ assertEquals("bcbcbcabbcc", mTextView.getText().toString());
+ }
+ });
+ }
+
public void testCutAndPaste() {
initTextViewForTyping();
mActivity.runOnUiThread(new Runnable() {
@@ -1725,6 +1829,57 @@
mInstrumentation.waitForIdleSync();
}
+ public void testCutAndPaste_byKey() {
+ initTextViewForTyping();
+
+ // Type "abc".
+ mInstrumentation.sendStringSync("abc");
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ // Select "bc"
+ Selection.setSelection((Spannable) mTextView.getText(), 1, 3);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Cut "bc"
+ sendKeys(KeyEvent.KEYCODE_CUT);
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ assertEquals("a", mTextView.getText().toString());
+ // Move cursor to the head
+ Selection.setSelection((Spannable) mTextView.getText(), 0, 0);
+ }
+ });
+ mInstrumentation.waitForIdleSync();
+ // Paste "bc"
+ sendKeys(KeyEvent.KEYCODE_PASTE);
+ assertEquals("bca", mTextView.getText().toString());
+
+ mActivity.runOnUiThread(new Runnable() {
+ public void run() {
+ Selection.selectAll((Spannable) mTextView.getText());
+ KeyEvent cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN,
+ KeyEvent.KEYCODE_CUT, 0, KeyEvent.META_SHIFT_LEFT_ON);
+ // Shift + cut doesn't perform cut.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+ assertEquals("bca", mTextView.getText().toString());
+
+ cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+ KeyEvent.META_CTRL_LEFT_ON);
+ // Control + cut doesn't perform cut.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+ assertEquals("bca", mTextView.getText().toString());
+
+ cutWithMeta = new KeyEvent(0, 0, KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_CUT, 0,
+ KeyEvent.META_SHIFT_LEFT_ON | KeyEvent.META_CTRL_LEFT_ON);
+ // Control + Shift + cut doesn't perform cut.
+ mTextView.onKeyDown(KeyEvent.KEYCODE_CUT, cutWithMeta);
+ assertEquals("bca", mTextView.getText().toString());
+ }
+ });
+ }
+
private static boolean hasSpansAtMiddleOfText(final TextView textView, final Class<?> type) {
final Spannable spannable = (Spannable)textView.getText();
final int at = spannable.length() / 2;
@@ -2428,6 +2583,160 @@
}
}
+ @UiThreadTest
+ public void testAppend_doesNotAddLinksWhenAppendedTextDoesNotContainLinks() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text without URL");
+
+ mTextView.append(" another text without URL");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be zero", 0, urlSpans.length);
+ assertEquals("text without URL another text without URL", text.toString());
+ }
+
+ @UiThreadTest
+ public void testAppend_doesNotAddLinksWhenAutoLinkIsNotEnabled() {
+ mTextView = new TextView(mActivity);
+ mTextView.setText("text without URL");
+
+ mTextView.append(" text with URL http://android.com");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be zero", 0, urlSpans.length);
+ assertEquals("text without URL text with URL http://android.com", text.toString());
+ }
+
+ @UiThreadTest
+ public void testAppend_addsLinksWhenAutoLinkIsEnabled() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text without URL");
+
+ mTextView.append(" text with URL http://android.com");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be one after appending a URL", 1, urlSpans.length);
+ assertEquals("URLSpan URL should be same as the appended URL",
+ urlSpans[0].getURL(), "http://android.com");
+ assertEquals("text without URL text with URL http://android.com", text.toString());
+ }
+
+ @UiThreadTest
+ public void testAppend_addsLinksEvenWhenThereAreUrlsSetBefore() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text with URL http://android.com/before");
+
+ mTextView.append(" text with URL http://android.com");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be two after appending another URL", 2, urlSpans.length);
+ assertEquals("First URLSpan URL should be same",
+ urlSpans[0].getURL(), "http://android.com/before");
+ assertEquals("URLSpan URL should be same as the appended URL",
+ urlSpans[1].getURL(), "http://android.com");
+ assertEquals("text with URL http://android.com/before text with URL http://android.com",
+ text.toString());
+ }
+
+ @UiThreadTest
+ public void testAppend_setsMovementMethodWhenTextContainsUrlAndAutoLinkIsEnabled() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text without a URL");
+
+ mTextView.append(" text with a url: http://android.com");
+
+ assertNotNull("MovementMethod should not be null when text contains url",
+ mTextView.getMovementMethod());
+ assertTrue("MovementMethod should be instance of LinkMovementMethod when text contains url",
+ mTextView.getMovementMethod() instanceof LinkMovementMethod);
+ }
+
+ @UiThreadTest
+ public void testAppend_setsMovementMethodWhenLinksClickableAndTextContainsClickableSpans() {
+ Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+ mTextView = new TextView(mActivity);
+
+ mTextView.setLinksClickable(false);
+ mTextView.append(text);
+ assertNull("TextView.append should not set movement method if linksClickable is false",
+ mTextView.getMovementMethod());
+
+ mTextView.setText("");
+ mTextView.setLinksClickable(true);
+ mTextView.append(text);
+ assertNotNull("TextView.append should set movement method if linksClickable is true " +
+ "and text contains clickable spans", mTextView.getMovementMethod());
+ }
+
+ @UiThreadTest
+ public void testAppend_setMovementMethodForExistingTextWhenLinksClickableIsTrueDuringAppend() {
+ Spanned text = Html.fromHtml("<a href='http://android.com'>link</a>");
+ mTextView = new TextView(mActivity);
+ mTextView.setLinksClickable(false);
+ mTextView.setText(text);
+
+ mTextView.setLinksClickable(true);
+ mTextView.append("");
+
+ assertNotNull("TextView.append should set movement method if existing text contains " +
+ "links but new text does not", mTextView.getMovementMethod());
+ }
+
+ @UiThreadTest
+ public void testAppend_addsLinksWhenTextIsSpannableAndContainsUrlAndAutoLinkIsEnabled() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text without a URL");
+
+ mTextView.append(new SpannableString(" text with a url: http://android.com"));
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be one after appending a URL", 1, urlSpans.length);
+ assertEquals("URLSpan URL should be same as the appended URL",
+ urlSpans[0].getURL(), "http://android.com");
+ }
+
+ @UiThreadTest
+ public void testAppend_addsLinkIfAppendedTextCompletesPartialUrlAtTheEndOfExistingText() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text with a partial url android.");
+
+ mTextView.append("com");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should be one after appending to partial URL",
+ 1, urlSpans.length);
+ assertEquals("URLSpan URL should be same as the appended URL",
+ urlSpans[0].getURL(), "http://android.com");
+ }
+
+ @UiThreadTest
+ public void testAppend_addsLinkIfAppendedTextUpdatesUrlAtTheEndOfExistingText() {
+ mTextView = new TextView(mActivity);
+ mTextView.setAutoLinkMask(Linkify.ALL);
+ mTextView.setText("text with a url http://android.com");
+
+ mTextView.append("/textview");
+
+ Spannable text = (Spannable) mTextView.getText();
+ URLSpan[] urlSpans = text.getSpans(0, text.length(), URLSpan.class);
+ assertEquals("URLSpan count should still be one after extending a URL", 1, urlSpans.length);
+ assertEquals("URLSpan URL should be same as the new URL",
+ urlSpans[0].getURL(), "http://android.com/textview");
+ }
+
+
public void testAccessTransformationMethod() {
// check the password attribute in xml
mTextView = findTextView(R.id.textview_password);
diff --git a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
index dd8b2f9..b5fa019 100644
--- a/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
+++ b/tests/tvprovider/src/android/tvprovider/cts/TvProviderPerfTest.java
@@ -158,12 +158,12 @@
// Query a channel
try (final Cursor cursor = mContentResolver.query(Channels.CONTENT_URI,
projection, null, null, null)) {
- final Uri channelUri = TvContract.buildChannelUri(cursor.getLong(0));
applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
@Override
public void run(int i) {
assertTrue(cursor.moveToNext());
- try (Cursor c = mContentResolver.query(channelUri, null, null, null, null)) {
+ try (Cursor c = mContentResolver.query(TvContract.buildChannelUri(
+ cursor.getLong(0)), null, null, null, null)) {
while (c.moveToNext()) {
// Do nothing. Just iterate all the items.
}
@@ -324,12 +324,12 @@
// Query a program
try (final Cursor cursor = mContentResolver.query(Programs.CONTENT_URI,
projection, null, null, null)) {
- final Uri programUri = TvContract.buildProgramUri(cursor.getLong(0));
applyBatchTimes = MeasureTime.measure(QUERY_RUNS, new MeasureRun() {
@Override
public void run(int i) {
assertTrue(cursor.moveToNext());
- try (Cursor c = mContentResolver.query(programUri, null, null, null, null)) {
+ try (Cursor c = mContentResolver.query(TvContract.buildProgramUri(
+ cursor.getLong(0)), null, null, null, null)) {
while (c.moveToNext()) {
// Do nothing. Just iterate all the items.
}
diff --git a/tools/cts-device-info/Android.mk b/tools/cts-device-info/Android.mk
index b54c7a7..d479d9f 100644
--- a/tools/cts-device-info/Android.mk
+++ b/tools/cts-device-info/Android.mk
@@ -23,7 +23,8 @@
DEVICE_INFO_PERMISSIONS :=
-DEVICE_INFO_ACTIVITIES :=
+DEVICE_INFO_ACTIVITIES := \
+ com.android.compatibility.common.deviceinfo.GlesStubActivity
LOCAL_PACKAGE_NAME := CtsDeviceInfo
diff --git a/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
index 78d4249..1b48ddf 100644
--- a/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
+++ b/tools/cts-java-scanner-doclet/src/com/android/cts/javascannerdoclet/CtsJavaScannerDoclet.java
@@ -65,6 +65,10 @@
static final String JUNIT_TEST_CASE_CLASS_NAME = "junit.framework.testcase";
+ private static final String TIMEOUT_ANNOTATION = "com.android.cts.util.TimeoutReq";
+ private static final String SUPPRESS_ANNOTATION =
+ "android.test.suitebuilder.annotation.Suppress";
+
public static boolean start(RootDoc root) {
ClassDoc[] classes = root.classes();
if (classes == null) {
@@ -93,10 +97,11 @@
continue;
}
+ boolean suppressed = false;
AnnotationDesc[] annotations = method.annotations();
for (AnnotationDesc annot : annotations) {
String atype = annot.annotationType().toString();
- if (atype.equals("com.android.cts.util.TimeoutReq")) {
+ if (atype.equals(TIMEOUT_ANNOTATION)) {
ElementValuePair[] cpairs = annot.elementValues();
for (ElementValuePair pair : cpairs) {
AnnotationTypeElementDoc elem = pair.element();
@@ -105,8 +110,13 @@
timeout = ((Integer) value.value());
}
}
+ } else if (atype.equals(SUPPRESS_ANNOTATION)) {
+ suppressed = true;
}
}
+ if (suppressed) {
+ continue;
+ }
} else {
/* JUnit4 */
boolean isTest = false;
diff --git a/tools/cts-media/copy_media.sh b/tools/cts-media/copy_media.sh
index cf0d099..cfec807 100755
--- a/tools/cts-media/copy_media.sh
+++ b/tools/cts-media/copy_media.sh
@@ -17,15 +17,15 @@
max_resolution=3
if [ $# -eq 0 ]; then
echo "assuming default resolution"
-elif [ "$1" == "-s" ]; then
+elif [ "$1" = "-s" ]; then
adb_options=""$1" "$2""
-elif [ "$1" == "720x480" ]; then
+elif [ "$1" = "720x480" ]; then
max_resolution=1
-elif [ "$1" == "1280x720" ]; then
+elif [ "$1" = "1280x720" ]; then
max_resolution=2
-elif [ "$1" == "1920x1080" ]; then
+elif [ "$1" = "1920x1080" ]; then
max_resolution=3
-elif [ "$1" == "all" ]; then
+elif [ "$1" = "all" ]; then
max_resolution=3
else
echo "Usage: copy_media.sh [720x480|1280x720|1920x1080] [-s serial]"
diff --git a/tools/cts-media/get_achievable_rates.py b/tools/cts-media/get_achievable_rates.py
new file mode 100755
index 0000000..9dde743
--- /dev/null
+++ b/tools/cts-media/get_achievable_rates.py
@@ -0,0 +1,402 @@
+#!/usr/bin/python
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT 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 argparse, math, re, sys
+import xml.etree.ElementTree as ET
+from collections import defaultdict, namedtuple
+import itertools
+
+
+def createLookup(values, key):
+ """Creates a lookup table for a collection of values based on keys.
+
+ Arguments:
+ values: a collection of arbitrary values. Must be iterable.
+ key: a function of one argument that returns the key for a value.
+
+ Returns:
+ A dict mapping keys (as generated by the key argument) to lists of
+ values. All values in the lists have the same key, and are in the order
+ they appeared in the collection.
+ """
+ lookup = defaultdict(list)
+ for v in values:
+ lookup[key(v)].append(v)
+ return lookup
+
+
+def _intify(value):
+ """Returns a value converted to int if possible, else the original value."""
+ try:
+ return int(value)
+ except ValueError:
+ return value
+
+
+class Size(namedtuple('Size', ['width', 'height'])):
+ """A namedtuple with width and height fields."""
+ def __str__(self):
+ return '%dx%d' % (self.width, self.height)
+
+
+class _VideoResultBase(object):
+ """Helper methods for results. Not for use by applications.
+
+ Attributes:
+ codec: The name of the codec (string) or None
+ size: Size representing the video size or None
+ mime: The mime-type of the codec (string) or None
+ rates: The measured achievable frame rates
+ is_decoder: True iff codec is a decoder.
+ """
+
+ def __init__(self, is_decoder):
+ self.codec = None
+ self.mime = None
+ self.size = None
+ self._rates_from_failure = []
+ self._rates_from_message = []
+ self.is_decoder = is_decoder
+
+ def _inited(self):
+ """Returns true iff codec, mime and size was set."""
+ return None not in (self.codec, self.mime, self.size)
+
+ def __len__(self):
+ # don't report any result if codec name, mime type and size is unclear
+ if not self._inited():
+ return 0
+ return len(self.rates)
+
+ @property
+ def rates(self):
+ return self._rates_from_failure or self._rates_from_message
+
+ def _parseDict(self, value):
+ """Parses a MediaFormat from its string representation sans brackets."""
+ return dict((k, _intify(v))
+ for k, v in re.findall(r'([^ =]+)=([^ [=]+(?:|\[[^\]]+\]))(?:, |$)', value))
+
+ def _cleanFormat(self, format):
+ """Removes internal fields from a parsed MediaFormat."""
+ format.pop('what', None)
+ format.pop('image-data', None)
+
+ MESSAGE_PATTERN = r'(?P<key>\w+)=(?P<value>\{[^}]*\}|[^ ,{}]+)'
+
+ def _parsePartialResult(self, message_match):
+ """Parses a partial test result conforming to the message pattern.
+
+ Returns:
+ A tuple of string key and int, string or dict value, where dict has
+ string keys mapping to int or string values.
+ """
+ key, value = message_match.group('key', 'value')
+ if value.startswith('{'):
+ value = self._parseDict(value[1:-1])
+ if key.endswith('Format'):
+ self._cleanFormat(value)
+ else:
+ value = _intify(value)
+ return key, value
+
+ def _parseValuesFromBracket(self, line):
+ """Returns the values enclosed in brackets without the brackets.
+
+ Parses a line matching the pattern "<tag>: [<values>]" and returns <values>.
+
+ Raises:
+ ValueError: if the line does not match the pattern.
+ """
+ try:
+ return re.match(r'^[^:]+: *\[(?P<values>.*)\]\.$', line).group('values')
+ except AttributeError:
+ raise ValueError('line does not match "tag: [value]": %s' % line)
+
+ def _parseRawData(self, line):
+ """Parses the raw data line for video performance tests.
+
+ Yields:
+ Dict objects corresponding to parsed results, mapping string keys to
+ int, string or dict values.
+ """
+ try:
+ values = self._parseValuesFromBracket(line)
+ result = {}
+ for m in re.finditer(self.MESSAGE_PATTERN + r'(?P<sep>,? +|$)', values):
+ key, value = self._parsePartialResult(m)
+ result[key] = value
+ if m.group('sep') != ' ':
+ yield result
+ result = {}
+ except ValueError:
+ print >> sys.stderr, 'could not parse line %s' % repr(line)
+
+ def _tryParseMeasuredFrameRate(self, line):
+ """Parses a line starting with 'Measured frame rate:'."""
+ if line.startswith('Measured frame rate: '):
+ try:
+ values = self._parseValuesFromBracket(line)
+ values = re.split(r' *, *', values)
+ self._rates_from_failure = list(map(float, values))
+ except ValueError:
+ print >> sys.stderr, 'could not parse line %s' % repr(line)
+
+ def parse(self, test):
+ """Parses the ValueArray and FailedScene lines of a test result.
+
+ Arguments:
+ test: An ElementTree <Test> element.
+ """
+ failure = test.find('FailedScene')
+ if failure is not None:
+ trace = failure.find('StackTrace')
+ if trace is not None:
+ for line in re.split(r'[\r\n]+', trace.text):
+ self._parseFailureLine(line)
+ details = test.find('Details')
+ if details is not None:
+ for array in details.iter('ValueArray'):
+ message = array.get('message')
+ self._parseMessage(message, array)
+
+ def _parseFailureLine(self, line):
+ raise NotImplementedError
+
+ def _parseMessage(self, message, array):
+ raise NotImplementedError
+
+ def getData(self):
+ """Gets the parsed test result data.
+
+ Yields:
+ Result objects containing at least codec, size, mime and rates attributes."""
+ yield self
+
+
+class VideoEncoderDecoderTestResult(_VideoResultBase):
+ """Represents a result from a VideoEncoderDecoderTest performance case."""
+
+ def __init__(self, unused_m):
+ super(VideoEncoderDecoderTestResult, self).__init__(is_decoder=False)
+
+ # If a VideoEncoderDecoderTest succeeds, it provides the results in the
+ # message of a ValueArray. If fails, it provides the results in the failure
+ # using raw data. (For now it also includes some data in the ValueArrays even
+ # if it fails, which we ignore.)
+
+ def _parseFailureLine(self, line):
+ """Handles parsing a line from the failure log."""
+ self._tryParseMeasuredFrameRate(line)
+ if line.startswith('Raw data: '):
+ for result in self._parseRawData(line):
+ fmt = result['EncOutputFormat']
+ self.size = Size(fmt['width'], fmt['height'])
+ self.codec = result['codec']
+ self.mime = fmt['mime']
+
+ def _parseMessage(self, message, array):
+ """Handles parsing a message from ValueArrays."""
+ if message.startswith('codec='):
+ result = dict(self._parsePartialResult(m)
+ for m in re.finditer(self.MESSAGE_PATTERN + '(?: |$)', message))
+ if 'EncInputFormat' in result:
+ self.codec = result['codec']
+ fmt = result['EncInputFormat']
+ self.size = Size(fmt['width'], fmt['height'])
+ self.mime = result['EncOutputFormat']['mime']
+ self._rates_from_message.append(1000000./result['min'])
+
+
+class VideoDecoderPerfTestResult(_VideoResultBase):
+ """Represents a result from a VideoDecoderPerfTest performance case."""
+
+ # If a VideoDecoderPerfTest succeeds, it provides the results in the message
+ # of a ValueArray. If fails, it provides the results in the failure only
+ # using raw data.
+
+ def __init__(self, unused_m):
+ super(VideoDecoderPerfTestResult, self).__init__(is_decoder=True)
+
+ def _parseFailureLine(self, line):
+ """Handles parsing a line from the failure log."""
+ self._tryParseMeasuredFrameRate(line)
+ # if the test failed, we can only get the codec/size/mime from the raw data.
+ if line.startswith('Raw data: '):
+ for result in self._parseRawData(line):
+ fmt = result['DecOutputFormat']
+ self.size = Size(fmt['width'], fmt['height'])
+ self.codec = result['codec']
+ self.mime = result['mime']
+
+ def _parseMessage(self, message, array):
+ """Handles parsing a message from ValueArrays."""
+ if message.startswith('codec='):
+ result = dict(self._parsePartialResult(m)
+ for m in re.finditer(self.MESSAGE_PATTERN + '(?: |$)', message))
+ if result.get('decodeto') == 'surface':
+ self.codec = result['codec']
+ fmt = result['DecOutputFormat']
+ self.size = Size(fmt['width'], fmt['height'])
+ self.mime = result['mime']
+ self._rates_from_message.append(1000000. / result['min'])
+
+
+class Results(object):
+ """Container that keeps all test results."""
+ def __init__(self):
+ self._results = [] # namedtuples
+ self._device = None
+
+ VIDEO_ENCODER_DECODER_TEST_REGEX = re.compile(
+ 'test(.*)(\d{4})x(\d{4})(Goog|Other)$')
+
+ VIDEO_DECODER_PERF_TEST_REGEX = re.compile(
+ 'test(VP[89]|H26[34]|MPEG4|HEVC)(\d+)x(\d+)(.*)$')
+
+ TestCaseSpec = namedtuple('TestCaseSpec', 'package path class_ regex result_class')
+
+ def _getTestCases(self):
+ return [
+ self.TestCaseSpec(package='CtsDeviceVideoPerf',
+ path='TestSuite/TestSuite/TestSuite/TestSuite/TestCase',
+ class_='VideoEncoderDecoderTest',
+ regex=self.VIDEO_ENCODER_DECODER_TEST_REGEX,
+ result_class=VideoEncoderDecoderTestResult),
+ self.TestCaseSpec(package='CtsMediaTestCases',
+ path='TestSuite/TestSuite/TestSuite/TestCase',
+ class_='VideoDecoderPerfTest',
+ regex=self.VIDEO_DECODER_PERF_TEST_REGEX,
+ result_class=VideoDecoderPerfTestResult)
+ ]
+
+ def _verifyDeviceInfo(self, device):
+ assert self._device in (None, device), "expected %s device" % self._device
+ self._device = device
+
+ def importXml(self, xml):
+ self._verifyDeviceInfo(xml.find('DeviceInfo/BuildInfo').get('buildName'))
+
+ packages = createLookup(self._getTestCases(), lambda tc: tc.package)
+
+ for pkg in xml.iter('TestPackage'):
+ tests_in_package = packages.get(pkg.get('name'))
+ if not tests_in_package:
+ continue
+ paths = createLookup(tests_in_package, lambda tc: tc.path)
+ for path, tests_in_path in paths.items():
+ classes = createLookup(tests_in_path, lambda tc: tc.class_)
+ for tc in pkg.iterfind(path):
+ tests_in_class = classes.get(tc.get('name'))
+ if not tests_in_class:
+ continue
+ for test in tc.iter('Test'):
+ for tc in tests_in_class:
+ m = tc.regex.match(test.get('name'))
+ if m:
+ result = tc.result_class(m)
+ result.parse(test)
+ self._results.append(result)
+
+ def importFile(self, path):
+ print >> sys.stderr, 'Importing "%s"...' % path
+ try:
+ return self.importXml(ET.parse(path))
+ except ET.ParseError:
+ raise ValueError('not a valid XML file')
+
+ def getData(self):
+ for result in self._results:
+ for data in result.getData():
+ yield data
+
+ def dumpXml(self, results):
+ yield '<?xml version="1.0" encoding="utf-8" ?>'
+ yield '<!-- Copyright 2015 The Android Open Source Project'
+ yield ''
+ yield ' Licensed under the Apache License, Version 2.0 (the "License");'
+ yield ' you may not use this file except in compliance with the License.'
+ yield ' You may obtain a copy of the License at'
+ yield ''
+ yield ' http://www.apache.org/licenses/LICENSE-2.0'
+ yield ''
+ yield ' Unless required by applicable law or agreed to in writing, software'
+ yield ' distributed under the License is distributed on an "AS IS" BASIS,'
+ yield ' WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.'
+ yield ' See the License for the specific language governing permissions and'
+ yield ' limitations under the License.'
+ yield '-->'
+ yield ''
+ yield '<MediaCodecs>'
+ last_section = None
+ Comp = namedtuple('Comp', 'is_decoder google mime name')
+ by_comp = createLookup(results,
+ lambda e: Comp(is_decoder=e.is_decoder, google='.google.' in e.codec, mime=e.mime, name=e.codec))
+ for comp in sorted(by_comp):
+ section = 'Decoders' if comp.is_decoder else 'Encoders'
+ if section != last_section:
+ if last_section:
+ yield ' </%s>' % last_section
+ yield ' <%s>' % section
+ last_section = section
+ yield ' <MediaCodec name="%s" type="%s" update="true">' % (comp.name, comp.mime)
+ by_size = createLookup(by_comp[comp], lambda e: e.size)
+ for size in sorted(by_size):
+ values = list(itertools.chain(*(e.rates for e in by_size[size])))
+ min_, max_ = min(values), max(values)
+ med_ = int(math.sqrt(min_ * max_))
+ yield ' <Limit name="measured-frame-rate-%s" range="%d-%d" />' % (size, med_, med_)
+ yield ' </MediaCodec>'
+ if last_section:
+ yield ' </%s>' % last_section
+ yield '</MediaCodecs>'
+
+
+class Main(object):
+ """Executor of this utility."""
+
+ def __init__(self):
+ self._result = Results()
+
+ self._parser = argparse.ArgumentParser('get_achievable_framerates')
+ self._parser.add_argument('result_xml', nargs='+')
+
+ def _parseArgs(self):
+ self._args = self._parser.parse_args()
+
+ def _importXml(self, xml):
+ self._result.importFile(xml)
+
+ def _report(self):
+ for line in self._result.dumpXml(r for r in self._result.getData() if r):
+ print line
+
+ def run(self):
+ self._parseArgs()
+ try:
+ for xml in self._args.result_xml:
+ try:
+ self._importXml(xml)
+ except (ValueError, IOError, AssertionError) as e:
+ print >> sys.stderr, e
+ raise KeyboardInterrupt
+ self._report()
+ except KeyboardInterrupt:
+ print >> sys.stderr, 'Interrupted.'
+
+if __name__ == '__main__':
+ Main().run()
+
diff --git a/tools/cts-tradefed/etc/cts-tradefed_v2 b/tools/cts-tradefed/etc/cts-tradefed_v2
index 7e10ab2..d1cf0cc 100755
--- a/tools/cts-tradefed/etc/cts-tradefed_v2
+++ b/tools/cts-tradefed/etc/cts-tradefed_v2
@@ -35,9 +35,9 @@
checkPath java
# check java version
-JAVA_VERSION=$(java -version 2>&1 | head -n 2 | grep '[ "]1\.[67][\. "$$]')
+JAVA_VERSION=$(java -version 2>&1 | head -n 2 | grep '[ "]1\.[678][\. "$$]')
if [ "${JAVA_VERSION}" == "" ]; then
- echo "Wrong java version. 1.6 or 1.7 is required."
+ echo "Wrong java version. 1.6, 1.7 or 1.8 is required."
exit
fi
diff --git a/tools/cts-tradefed/res/config/cts-camera.xml b/tools/cts-tradefed/res/config/cts-camera.xml
new file mode 100644
index 0000000..5bc395d
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-camera.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS-camera from a pre-existing CTS installation">
+
+ <include name="cts" />
+
+ <option name="compatibility:plan" value="cts-camera" />
+
+ <!-- All camera CTS tests -->
+ <option name="compatibility:include-filter" value="CtsCameraTestCases" />
+
+ <!-- Other camera related CTS tests -->
+ <option name="compatibility:include-filter"
+ value="CtsAppTestCases android.app.cts.SystemFeaturesTest#testCameraFeatures"/>
+ <option name="compatibility:include-filter"
+ value="CtsPermissionTestCases android.permission.cts.CameraPermissionTest"/>
+ <option name="compatibility:include-filter"
+ value="CtsPermissionTestCases android.permission.cts.Camera2PermissionTest"/>
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts-filtered-sample.xml b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
new file mode 100644
index 0000000..73b98c5
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-filtered-sample.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Runs CTS from a pre-existing CTS installation">
+
+ <include name="common-compatibility-config" />
+
+ <option name="compatibility:plan" value="cts-filtered-sample" />
+
+ <!-- Tell all AndroidJUnitTests to only run the medium sized tests -->
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:size:medium" />
+
+ <!-- Tell 64bit CtsContentTestCases which timeout to use -->
+ <option name="compatibility:module-arg" value="arm64-v8a CtsContentTestCases:test-timeout:600" />
+
+ <!-- Include CtsGestureTestCases but only run the tests on arm32 -->
+ <option name="compatibility:include-filter" value="armeabi-v7a CtsGestureTestCases" />
+
+ <!-- Exclude CtsMediaStressTestCases -->
+ <option name="compatibility:exclude-filter" value="CtsMediaStressTestCases" />
+
+ <!-- Include CtsUtilTestCases but only run the small tests -->
+ <option name="compatibility:module-arg" value="CtsUtilTestCases:size:small" />
+
+</configuration>
diff --git a/tools/cts-tradefed/res/config/cts.xml b/tools/cts-tradefed/res/config/cts.xml
index 724c52e..87e678b 100644
--- a/tools/cts-tradefed/res/config/cts.xml
+++ b/tools/cts-tradefed/res/config/cts.xml
@@ -17,30 +17,11 @@
<include name="everything" />
+ <option name="compatibility:plan" value="cts" />
+
<option name="enable-root" value="false" />
- <!-- Example Filters
- <option name="compatibility-test:include-filter" value="arm64-v8a CtsSampleDeviceTestCases" />
- <option name="compatibility-test:exclude-filter" value="CtsSampleHostTestCases" />
- -->
- <option name="compatibility-test:plan" value="cts" />
-
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.SettingsPreparer">
- <option name="device-setting" value="install_non_market_apps"/>
- <option name="setting-type" value="secure"/>
- <option name="set-value" value="1"/> <!-- Installs from non-market apps allowed -->
- </target_preparer>
-
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.SettingsPreparer">
- <option name="device-setting" value="stay_on_while_plugged_in"/>
- <option name="setting-type" value="global"/>
- <!-- The following values encode the conditions in which the device stays awake -->
- <option name="expected-values" value="2" /> <!-- Stay awake when charging via USB only -->
- <option name="expected-values" value="3" /> <!-- Stay awake when charging via USB or AC -->
- <option name="expected-values" value="6" /> <!-- Stay awake when charging via USB or Wireless -->
- <option name="expected-values" value="7" /> <!-- Stay awake when charging via USB or AC or Wireless -->
- <option name="set-value" value="2"/>
- </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.StayAwakePreparer" />
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.PropertyCheck">
<option name="property-name" value="ro.build.type" />
diff --git a/tools/cts-tradefed/tests/run_tests.sh b/tools/cts-tradefed/tests/run_tests.sh
new file mode 100755
index 0000000..6a96928
--- /dev/null
+++ b/tools/cts-tradefed/tests/run_tests.sh
@@ -0,0 +1,28 @@
+#!/bin/bash
+
+# Copyright (C) 2015 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Helper script for running unit tests for compatibility libraries
+
+CTS_DIR=$(dirname ${0})/../../..
+source ${CTS_DIR}/test_defs.sh
+
+JARS="
+ compatibility-common-util-hostsidelib\
+ compatibility-host-util\
+ cts-tradefed-tests_v2\
+ cts-tradefed_v2"
+
+run_tests "com.android.compatibility.tradefed.CtsTradefedTest" "${JARS}" "${@}"
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
index 2dcf1c9..6469a01 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/tradefed/CtsTradefedTest.java
@@ -17,7 +17,7 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
-import com.android.tradefed.build.IFolderBuildInfo;
+import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.util.FileUtil;
import junit.framework.TestCase;
@@ -44,7 +44,7 @@
File tests = new File(base, "testcases");
tests.mkdirs();
CompatibilityBuildProvider provider = new CompatibilityBuildProvider();
- IFolderBuildInfo info = (IFolderBuildInfo) provider.getBuild();
+ IBuildInfo info = provider.getBuild();
CompatibilityBuildHelper helper = new CompatibilityBuildHelper(info);
helper.init(SUITE_PLAN, DYNAMIC_CONFIG_URL);
assertEquals("Incorrect suite full name", SUITE_FULL_NAME, helper.getSuiteFullName());
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
index ed09b8e..c680c2a 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestCase.java
@@ -46,4 +46,8 @@
public int compareTo(TestCase another) {
return getName().compareTo(another.getName());
}
+
+ public int countTests() {
+ return mTests.size();
+ }
}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
index 466f8d7..1d71e1f 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/TestSuite.java
@@ -66,4 +66,15 @@
public int compareTo(TestSuite another) {
return getName().compareTo(another.getName());
}
+
+ public int countTests() {
+ int count = 0;
+ for (TestSuite suite : mSuites.values()) {
+ count += suite.countTests();
+ }
+ for (TestCase testCase : mCases) {
+ count += testCase.countTests();
+ }
+ return count;
+ }
}
diff --git a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
index 96c83a9..f139053 100644
--- a/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
+++ b/tools/cts-xml-generator/src/com/android/cts/xmlgenerator/XmlGenerator.java
@@ -166,6 +166,9 @@
StringBuilder nameCollector) {
Collection<TestSuite> sorted = sortCollection(suites);
for (TestSuite suite : sorted) {
+ if (suite.countTests() == 0) {
+ continue;
+ }
writer.append("<TestSuite name=\"").append(suite.getName()).println("\">");
String namePart = suite.getName();
@@ -187,6 +190,9 @@
StringBuilder nameCollector) {
Collection<TestCase> sorted = sortCollection(cases);
for (TestCase testCase : sorted) {
+ if (testCase.countTests() == 0) {
+ continue;
+ }
String name = testCase.getName();
writer.append("<TestCase name=\"").append(name).println("\">");
nameCollector.append('.').append(name);
diff --git a/apps/CtsVerifier/res/xml/device_admin.xml b/tools/tradefed-host/res/config/basic-reporters.xml
similarity index 62%
copy from apps/CtsVerifier/res/xml/device_admin.xml
copy to tools/tradefed-host/res/config/basic-reporters.xml
index 49d705a..d52a85b 100644
--- a/apps/CtsVerifier/res/xml/device_admin.xml
+++ b/tools/tradefed-host/res/config/basic-reporters.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2011 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,14 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
- <uses-policies>
- <limit-password />
- <watch-login />
- <reset-password />
- <force-lock />
- <wipe-data />
- <expire-password />
- </uses-policies>
-</device-admin>
+<configuration description="Configuration with basic cts reporters" >
+ <result_reporter class="com.android.cts.tradefed.result.CtsTestLogReporter" />
+ <result_reporter class="com.android.cts.tradefed.result.IssueReporter" />
+</configuration>
diff --git a/tools/tradefed-host/res/config/cts.xml b/tools/tradefed-host/res/config/cts.xml
index 416b400..794605c 100644
--- a/tools/tradefed-host/res/config/cts.xml
+++ b/tools/tradefed-host/res/config/cts.xml
@@ -22,7 +22,5 @@
<test class="com.android.cts.tradefed.testtype.CtsTest" />
<logger class="com.android.tradefed.log.FileLogger" />
<result_reporter class="com.android.cts.tradefed.result.CtsXmlResultReporter" />
- <result_reporter class="com.android.cts.tradefed.result.CtsTestLogReporter" />
- <result_reporter class="com.android.cts.tradefed.result.IssueReporter" />
-
+ <template-include name="reporters" default="basic-reporters" />
</configuration>
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
index db35b15..07caaef 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/result/CtsXmlResultReporter.java
@@ -436,6 +436,9 @@
serializer.attribute(ns, "endtime", endTime);
serializer.attribute(ns, "version", CTS_RESULT_FILE_VERSION);
serializer.attribute(ns, "suite", mSuiteName);
+ if (mReferenceUrl != null) {
+ serializer.attribute(ns, "referenceUrl", mReferenceUrl);
+ }
mResults.serialize(serializer, mBuildInfo.getBuildId());
// TODO: not sure why, but the serializer doesn't like this statement
//serializer.endTag(ns, RESULT_TAG);
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
index 91cdceb..f11c76d 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/testtype/GeeTest.java
@@ -48,7 +48,7 @@
private static final String ANDROID_PATH_SEPARATOR = "/";
private static final String GTEST_FLAG_FILTER = "--gtest_filter=";
- private int mMaxTestTimeMs = 1 * 60 * 1000;
+ private int mMaxTestTimeMs = 1 * 90 * 1000;
private CtsBuildHelper mCtsBuild;
private ITestDevice mDevice;
diff --git a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
index 1441f8f..361b91c 100644
--- a/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
+++ b/tools/tradefed-host/tests/src/com/android/cts/tradefed/result/CtsXmlResultReporterTest.java
@@ -47,8 +47,9 @@
*/
public class CtsXmlResultReporterTest extends TestCase {
+ private static final String TEST_SUMMARY_URL = "http://www.google.com?q=android";
private static final List<TestSummary> SUMMARY_LIST =
- new ArrayList<>(Arrays.asList(new TestSummary("TEST_SUMMARY_URL")));
+ new ArrayList<>(Arrays.asList(new TestSummary(TEST_SUMMARY_URL)));
private CtsXmlResultReporter mResultReporter;
private ByteArrayOutputStream mOutputStream;
private File mBuildDir;
@@ -115,7 +116,7 @@
"<?xml-stylesheet type=\"text/xsl\" href=\"cts_result.xsl\"?>";
final String expectedTestOutput = String.format(
"<TestResult testPlan=\"NA\" starttime=\"ignore\" endtime=\"ignore\" " +
- "version=\"%s\" suite=\"%s\"> ", CTS_RESULT_FILE_VERSION, "CTS" );
+ "version=\"%s\" suite=\"%s\"> ", CTS_RESULT_FILE_VERSION, "CTS");
final String expectedSummaryOutput =
"<Summary failed=\"0\" notExecuted=\"0\" timeout=\"0\" pass=\"0\" />";
final String expectedEndTag = "</TestResult>";
@@ -127,7 +128,7 @@
assertTrue(String.format("test output did not contain expected test result [%s]. Got %s",
expectedTestOutput, actualOutput), actualOutput.contains(expectedTestOutput));
assertTrue(String.format("test output did not contain expected test summary [%s]. Got %s",
- expectedTestOutput, actualOutput), actualOutput.contains(expectedSummaryOutput));
+ expectedSummaryOutput, actualOutput), actualOutput.contains(expectedSummaryOutput));
assertTrue(String.format("test output did not contain expected TestResult end tag. Got %s",
actualOutput), actualOutput.endsWith(expectedEndTag));
EasyMock.verify(mMockBuild);
@@ -145,10 +146,15 @@
mResultReporter.testStarted(testId);
mResultReporter.testEnded(testId, emptyMap);
mResultReporter.testRunEnded(3000, emptyMap);
- mResultReporter.invocationEnded(1);
mResultReporter.putSummary(SUMMARY_LIST);
+ mResultReporter.invocationEnded(1);
String output = getOutput();
// TODO: consider doing xml based compare
+ final String expectedTestOutput = String.format(
+ "<TestResult testPlan=\"NA\" starttime=\"ignore\" endtime=\"ignore\" " +
+ "version=\"%s\" suite=\"%s\" referenceUrl=\"%s\"> ",
+ CTS_RESULT_FILE_VERSION, "CTS", TEST_SUMMARY_URL);
+ assertTrue("Found output: " + output, output.contains(expectedTestOutput));
assertTrue(output.contains(
"<Summary failed=\"0\" notExecuted=\"0\" timeout=\"0\" pass=\"1\" />"));
assertTrue(output.contains("<TestPackage name=\"\" appPackageName=\"run\" abi=\"" +
diff --git a/tools/utils/buildCts.py b/tools/utils/buildCts.py
index 535560f..cfdcb59 100755
--- a/tools/utils/buildCts.py
+++ b/tools/utils/buildCts.py
@@ -20,6 +20,7 @@
import os
import re
import shutil
+import string
import subprocess
import sys
import xml.dom.minidom as dom
@@ -37,6 +38,16 @@
f.close()
return lines
+def ReadDeqpTestList(testRoot, file):
+ """Reads a file, converts test names from deqp to CTS format, and returns
+ its contents as a line list.
+ """
+ REPO_ROOT = os.path.join(testRoot, "../../..")
+ f = open(os.path.join(REPO_ROOT, "external/deqp/android/cts", file), 'r');
+ lines = [string.join(line.strip().rsplit('.',1),'#') for line in f.readlines()]
+ f.close()
+ return lines
+
def GetMakeFileVars(makefile_path):
"""Extracts variable definitions from the given make file.
@@ -127,12 +138,12 @@
plan = tools.TestPlan(packages)
plan.Include(r'android\.core\.tests.*')
- plan.Exclude(r'android\.core\.tests\.libcore.\package.\harmony*')
+ plan.Exclude(r'android\.core\.tests\.libcore\.package\.harmony*')
self.__WritePlan(plan, 'Java')
# TODO: remove this once the tests are fixed and merged into Java plan above.
plan = tools.TestPlan(packages)
- plan.Include(r'android\.core\.tests\.libcore.\package.\harmony*')
+ plan.Include(r'android\.core\.tests\.libcore\.package\.harmony*')
self.__WritePlan(plan, 'Harmony')
plan = tools.TestPlan(packages)
@@ -222,6 +233,20 @@
plan.ExcludeTests(package, test_list)
self.__WritePlan(plan, 'CTS-hardware')
+ # CTS - sub plan for camera tests which is public, large
+ plan = tools.TestPlan(packages)
+ plan.Exclude('.*')
+ plan.Include(r'android\.camera$')
+ misc_camera_tests = BuildCtsMiscCameraList()
+ for package, test_list in misc_camera_tests.iteritems():
+ plan.Include(package+'$')
+ plan.IncludeTests(package, test_list)
+ for package, test_list in flaky_tests.iteritems():
+ plan.ExcludeTests(package, test_list)
+ for package, test_list in releasekey_tests.iteritems():
+ plan.ExcludeTests(package, test_list)
+ self.__WritePlan(plan, 'CTS-camera')
+
# CTS - sub plan for media tests which is public, large
plan = tools.TestPlan(packages)
plan.Exclude('.*')
@@ -261,8 +286,21 @@
plan = tools.TestPlan(packages)
plan.Exclude('.*')
plan.Include(r'com\.drawelements\.')
+ plan.IncludeTests('com.drawelements.deqp.egl', ReadDeqpTestList(self.test_root, 'mnc/egl-master.txt'))
+ plan.IncludeTests('com.drawelements.deqp.gles2', ReadDeqpTestList(self.test_root, 'mnc/gles2-master.txt'))
+ plan.IncludeTests('com.drawelements.deqp.gles3', ReadDeqpTestList(self.test_root, 'mnc/gles3-master.txt'))
+ plan.IncludeTests('com.drawelements.deqp.gles31', ReadDeqpTestList(self.test_root, 'mnc/gles31-master.txt'))
self.__WritePlan(plan, 'CTS-DEQP')
+ plan = tools.TestPlan(packages)
+ plan.Exclude('.*')
+ plan.Include(r'com\.drawelements\.')
+ plan.ExcludeTests('com.drawelements.deqp.egl', ReadDeqpTestList(self.test_root, 'mnc/egl-master.txt'))
+ plan.ExcludeTests('com.drawelements.deqp.gles2', ReadDeqpTestList(self.test_root, 'mnc/gles2-master.txt'))
+ plan.ExcludeTests('com.drawelements.deqp.gles3', ReadDeqpTestList(self.test_root, 'mnc/gles3-master.txt'))
+ plan.ExcludeTests('com.drawelements.deqp.gles31', ReadDeqpTestList(self.test_root, 'mnc/gles31-master.txt'))
+ self.__WritePlan(plan, 'CTS-DEQP-for-next-rel')
+
# CTS - sub plan for new test packages added for staging
plan = tools.TestPlan(packages)
for package, test_list in small_tests.iteritems():
@@ -327,6 +365,7 @@
'android.accounts' : [],
'android.admin' : [],
'android.animation' : [],
+ 'android.appsecurity' : [],
'android.bionic' : [],
'android.bluetooth' : [],
'android.calendarcommon' : [],
@@ -364,7 +403,6 @@
'android.signature' : [],
'android.simplecpu' : [],
'android.speech' : [],
- 'android.tests.appsecurity' : [],
'android.text' : [],
'android.textureview' : [],
'android.theme' : [],
@@ -433,7 +471,7 @@
""" Construct a defaultdict that maps package name to a list of tests
that flaky during dev cycle and cause other subsequent tests to fail. """
return {
- 'android.hardware' : [
+ 'android.camera' : [
'android.hardware.cts.CameraTest#testVideoSnapshot',
'android.hardware.cts.CameraGLTest#testCameraToSurfaceTextureMetadata',
'android.hardware.cts.CameraGLTest#testSetPreviewTextureBothCallbacks',
@@ -507,6 +545,19 @@
],
'' : []}
+def BuildCtsMiscCameraList():
+ """ Construct a defaultdict that maps package name to a list of tests
+ that are relevant to camera but does not reside in camera test package """
+ return {
+ 'android.app' : [
+ 'android.app.cts.SystemFeaturesTest#testCameraFeatures',
+ ],
+ 'android.permission' : [
+ 'android.permission.cts.CameraPermissionTest',
+ 'android.permission.cts.Camera2PermissionTest',
+ ],
+ '' : []}
+
def LogGenerateDescription(name):
print 'Generating test description for package %s' % name
diff --git a/tools/utils/java-cert-list-generator.sh b/tools/utils/java-cert-list-generator.sh
index b8cee18..33e9aaa 100755
--- a/tools/utils/java-cert-list-generator.sh
+++ b/tools/utils/java-cert-list-generator.sh
@@ -50,7 +50,7 @@
static final String[] CERTIFICATE_DATA = {
STARTCLASS
-CERT_DIRECTORY=$ANDROID_BUILD_TOP/libcore/luni/src/main/files/cacerts
+CERT_DIRECTORY=$ANDROID_BUILD_TOP/system/ca-certificates/files/
for FILE in `ls $CERT_DIRECTORY`; do
FINGERPRINT=`cat $CERT_DIRECTORY/$FILE | grep "SHA1 Fingerprint=" | cut -d '=' -f 2`
echo " \"${FINGERPRINT}\","
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index ded63bf..7578fa9 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -99,13 +99,16 @@
$(hide) cd $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/classes && zip -q -r ../../android.core.vm-tests-tf.jar .
$(hide) cd $(dir $@) && zip -q -r android.core.vm-tests-tf.jar tests
else # LOCAL_JACK_ENABLED
-$(vmteststf_jar) : $(vmteststf_dep_jars) $(JACK_JAR) $(JILL_JAR) $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)/classes.jack $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
+oj_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-oj,,COMMON)/classes.jack
+libart_jack := $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)/classes.jack
+$(vmteststf_jar): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
+$(vmteststf_jar) : $(vmteststf_dep_jars) $(JACK_JAR) $(JILL_JAR) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
$(hide) rm -rf $(dir $@) && mkdir -p $(dir $@)
$(hide) mkdir -p $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/dot/junit $(dir $(PRIVATE_INTERMEDIATES_DEXCORE_JAR))
# generated and compile the host side junit tests
@echo "Write generated Main_*.java files to $(PRIVATE_INTERMEDIATES_MAIN_FILES)"
$(hide) java -cp $(PRIVATE_CLASS_PATH) util.build.JackBuildDalvikSuite $(PRIVATE_SRC_FOLDER) $(PRIVATE_INTERMEDIATES) \
- $(call intermediates-dir-for,JAVA_LIBRARIES,core-libart,,COMMON)/classes.jack:$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar \
+ $(PRIVATE_DALVIK_SUITE_CLASSPATH) \
$(PRIVATE_INTERMEDIATES_MAIN_FILES) $(PRIVATE_INTERMEDIATES_CLASSES) $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES) $$RUN_VM_TESTS_RTO
@echo "Generate $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)"
$(hide) jar -cf $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)-class.jar \
@@ -117,6 +120,8 @@
$(hide) cd $(PRIVATE_INTERMEDIATES_DEXCORE_JAR).tmp && zip -q -r $(abspath $(PRIVATE_INTERMEDIATES_DEXCORE_JAR)) .
$(hide) cd $(PRIVATE_INTERMEDIATES_HOSTJUNIT_FILES)/classes && zip -q -r ../../android.core.vm-tests-tf.jar .
$(hide) cd $(dir $@) && zip -q -r android.core.vm-tests-tf.jar tests
+oj_jack :=
+libart_jack :=
endif # LOCAL_JACK_ENABLED
# Clean up temp vars