Merge "Adds tests for PreferenceDataStore funcionality."
diff --git a/apps/CtsVerifier/Android.mk b/apps/CtsVerifier/Android.mk
index 6d3693f..97344e2 100644
--- a/apps/CtsVerifier/Android.mk
+++ b/apps/CtsVerifier/Android.mk
@@ -92,6 +92,7 @@
notification-bot := $(call intermediates-dir-for,APPS,NotificationBot)/package.apk
permission-app := $(call intermediates-dir-for,APPS,CtsPermissionApp)/package.apk
+usb-companion := $(call intermediates-dir-for,APPS,CtsVerifierUSBCompanion)/package.apk
# Builds and launches CTS Verifier on a device.
.PHONY: cts-verifier
@@ -130,20 +131,15 @@
# $(hide) $(ACP) -fp cts/apps/CtsVerifier/assets/scripts/execute_power_tests.py $@
cts : $(verifier-zip)
-ifeq ($(HOST_OS),linux)
-$(verifier-zip) : $(HOST_OUT)/bin/cts-usb-accessory
-endif
$(verifier-zip) : $(HOST_OUT)/CameraITS
$(verifier-zip) : $(notification-bot)
$(verifier-zip) : $(permission-app)
+$(verifier-zip) : $(usb-companion)
$(verifier-zip) : $(call intermediates-dir-for,APPS,CtsVerifier)/package.apk | $(ACP)
$(hide) mkdir -p $(verifier-dir)
$(hide) $(ACP) -fp $< $(verifier-dir)/CtsVerifier.apk
$(ACP) -fp $(notification-bot) $(verifier-dir)/NotificationBot.apk
$(ACP) -fp $(permission-app) $(verifier-dir)/CtsPermissionApp.apk
-ifeq ($(HOST_OS),linux)
- $(hide) $(ACP) -fp $(HOST_OUT)/bin/cts-usb-accessory $(verifier-dir)/cts-usb-accessory
-endif
$(hide) $(ACP) -fpr $(HOST_OUT)/CameraITS $(verifier-dir)
$(hide) cd $(cts-dir) && zip -rq $(verifier-dir-name) $(verifier-dir-name)
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index f3a37cf..15ce007 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1694,23 +1694,26 @@
<activity android:name=".usb.accessory.UsbAccessoryTestActivity"
android:label="@string/usb_accessory_test"
- android:configChanges="keyboardHidden|orientation|screenSize"
- android:launchMode="singleTop">
+ 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>
- <intent-filter>
- <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
- </intent-filter>
- <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
- android:resource="@xml/accessory_filter" />
<meta-data android:name="test_category" android:value="@string/test_category_hardware" />
<meta-data android:name="test_required_features" android:value="android.hardware.usb.accessory" />
<meta-data android:name="test_excluded_features"
android:value="android.hardware.type.watch" />
</activity>
+ <activity android:name=".usb.accessory.AccessoryAttachmentHandler">
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
+ </activity>
+
<activity android:name=".usb.device.UsbDeviceTestActivity"
android:label="@string/usb_device_test"
android:configChanges="keyboardHidden|orientation|screenSize">
@@ -2580,7 +2583,7 @@
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_other" />
<meta-data android:name="test_excluded_features"
- android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch" />
+ android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
</activity>
<activity android:name=".tv.MockTvInputSetupActivity">
@@ -2787,6 +2790,28 @@
android:name="com.android.cts.verifier.sensors.sixdof.Activities.TestActivity"
android:label="@string/title_activity_cts">
</activity>
+
+ <activity android:name=".voicemail.VoicemailBroadcastActivity"
+ android:label="@string/voicemail_broadcast_test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.cts.intent.category.MANUAL_TEST" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ <data android:scheme="tel" />
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.DIAL" />
+ </intent-filter>
+ <meta-data android:name="test_category" android:value="@string/test_category_telephony"/>
+ </activity>
+
+ <receiver android:name=".voicemail.VoicemailBroadcastReceiver">
+ <intent-filter>
+ <action android:name="android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION" />
+ </intent-filter>
+ </receiver>
</application>
</manifest>
diff --git a/apps/CtsVerifier/res/drawable/ic_usb_48.xml b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
new file mode 100644
index 0000000..eebb4fb
--- /dev/null
+++ b/apps/CtsVerifier/res/drawable/ic_usb_48.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0">
+ <path
+ android:pathData="M30,14v8h2v4h-6V10h4l-6,-8 -6,8h4v16h-6v-4.14c1.41,-0.73 2.4,-2.16 2.4,-3.86 0,-2.43 -1.97,-4.4 -4.4,-4.4 -2.43,0 -4.4,1.97 -4.4,4.4 0,1.7 0.99,3.13 2.4,3.86V26c0,2.21 1.79,4 4,4h6v6.1c-1.42,0.73 -2.4,2.19 -2.4,3.9 0,2.43 1.97,4.4 4.4,4.4 2.43,0 4.4,-1.97 4.4,-4.4 0,-1.71 -0.98,-3.17 -2.4,-3.9V30h6c2.21,0 4,-1.79 4,-4v-4h2v-8h-8z"
+ android:fillColor="#757575"/>
+</vector>
diff --git a/apps/CtsVerifier/res/layout-land/usb_main.xml b/apps/CtsVerifier/res/layout-land/usb_main.xml
deleted file mode 100644
index 139b54b..0000000
--- a/apps/CtsVerifier/res/layout-land/usb_main.xml
+++ /dev/null
@@ -1,87 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT 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"
- >
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- >
- <LinearLayout android:orientation="vertical"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_weight="1"
- >
- <TextView android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/usb_sent_messages"
- style="?android:attr/listSeparatorTextViewStyle"
- />
- <FrameLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- >
- <ListView android:id="@+id/usb_sent_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <TextView android:id="@+id/usb_empty_sent_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/usb_no_messages"
- android:visibility="gone"
- />
- </FrameLayout>
- </LinearLayout>
- <include layout="@layout/vertical_divider" />
- <LinearLayout android:orientation="vertical"
- android:layout_width="1px"
- android:layout_height="match_parent"
- android:layout_weight="1"
- >
- <TextView android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/usb_received_messages"
- style="?android:attr/listSeparatorTextViewStyle"
- />
- <FrameLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- >
- <ListView android:id="@+id/usb_received_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <TextView android:id="@+id/usb_empty_received_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/usb_no_messages"
- android:visibility="gone"
- />
- </FrameLayout>
- </LinearLayout>
- </LinearLayout>
-
- <include layout="@layout/pass_fail_buttons" />
-
-</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
index 2e43b5f..d02ef0b 100644
--- a/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_frequency_unprocessed_activity.xml
@@ -1,18 +1,11 @@
<?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.
--->
+<!-- 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"
@@ -23,54 +16,285 @@
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:id="@+id/scrollView"
- >
+ android:id="@+id/scrollView">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:orientation="vertical"
- >
+ android:orientation="vertical">
- <TextView
+ <TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="vertical"
android:gravity="bottom"
- android:id="@+id/audio_frequency_unprocessed_defined"/>
-
- <ProgressBar
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:id="@+id/audio_frequency_unprocessed_progress_bar" />
+ android:id="@+id/audio_frequency_unprocessed_defined" />
<LinearLayout
- android:layout_width="wrap_content"
+ android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
- android:id="@+id/audio_frequency_unprocessed_layout_test1"
+ android:id="@+id/unprocessed_layout_test_tone"
>
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_unprocessed_instructions2"
- android:id="@+id/audio_frequency_unprocessed_instructions2" />
-
- <Button
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/audio_frequency_unprocessed_test1_btn"
- android:id="@+id/audio_frequency_unprocessed_test1_btn" />
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:colorAccent" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:text="@string/audio_frequency_unprocessed_results_text"
- android:id="@+id/audio_frequency_unprocessed_results1_text" />
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:text="@string/unprocessed_test_tone_instructions"
+ android:id="@+id/unprocessed_test_tone_instructions" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="2">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_test_tone_btn"
+ android:id="@+id/unprocessed_test_tone_btn" />
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/unprocessed_test_tone_progress_bar" />
+
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:colorAccent" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_play"
+ android:id="@+id/unprocessed_play_tone_btn" />
+ </LinearLayout>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/unprocessed_test_tone_result"
+ android:id="@+id/unprocessed_test_tone_result" />
</LinearLayout>
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/unprocessed_layout_test_noise">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:colorAccent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:text="@string/unprocessed_test_noise_instructions"
+ android:id="@+id/unprocessed_test_noise_instructions" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="2">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_test_noise_btn"
+ android:id="@+id/unprocessed_test_noise_btn" />
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/unprocessed_test_noise_progress_bar" />
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:colorAccent" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_play"
+ android:id="@+id/unprocessed_play_noise_btn" />
+ </LinearLayout>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/unprocessed_test_noise_result"
+ android:id="@+id/unprocessed_test_noise_result" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/unprocessed_layout_test_usb_background">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:colorAccent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:text="@string/unprocessed_test_usb_background_instructions"
+ android:id="@+id/unprocessed_test_usb_background_instructions" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="2">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_test_usb_background_btn"
+ android:id="@+id/unprocessed_test_usb_background_btn" />
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/unprocessed_test_usb_background_progress_bar" />
+ </LinearLayout>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/unprocessed_test_usb_background_result"
+ android:id="@+id/unprocessed_test_usb_background_result" />
+ </LinearLayout>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:id="@+id/unprocessed_layout_test_usb_noise">
+
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:colorAccent" />
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"
+ android:gravity="bottom"
+ android:text="@string/unprocessed_test_usb_noise_instructions"
+ android:id="@+id/unprocessed_test_usb_noise_instructions" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="horizontal">
+
+ <LinearLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="2">
+
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_test_usb_noise_btn"
+ android:id="@+id/unprocessed_test_usb_noise_btn" />
+ <ProgressBar
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:id="@+id/unprocessed_test_usb_noise_progress_bar" />
+ </LinearLayout>
+
+ <View
+ android:layout_width="1dp"
+ android:layout_height="match_parent"
+ android:background="?android:colorAccent" />
+
+ <LinearLayout
+ android:layout_width="0dp"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:layout_weight="1">
+ <Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:soundEffectsEnabled="false"
+ android:text="@string/unprocessed_play"
+ android:id="@+id/unprocessed_play_usb_noise_btn" />
+ </LinearLayout>
+ </LinearLayout>
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/unprocessed_test_usb_noise_result"
+ android:id="@+id/unprocessed_test_usb_noise_result" />
+ </LinearLayout>
+ <View
+ android:layout_width="match_parent"
+ android:layout_height="1dp"
+ android:background="?android:colorAccent" />
+
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/unprocessed_test_global_result"
+ android:id="@+id/unprocessed_test_global_result" />
<include layout="@layout/pass_fail_buttons" />
</LinearLayout>
diff --git a/apps/CtsVerifier/res/layout/pwa_widgets.xml b/apps/CtsVerifier/res/layout/pwa_widgets.xml
index e5ebddb..cb611b9 100644
--- a/apps/CtsVerifier/res/layout/pwa_widgets.xml
+++ b/apps/CtsVerifier/res/layout/pwa_widgets.xml
@@ -12,19 +12,16 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
- <TextureView
- android:id="@+id/texture_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
<LinearLayout
+ android:id="@+id/test_controls"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layout_gravity="top">
<LinearLayout
android:layout_width="match_parent"
@@ -55,4 +52,10 @@
</LinearLayout>
</LinearLayout>
-</LinearLayout>
+ <TextureView
+ android:id="@+id/texture_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_below="@id/test_controls" />
+
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/usb_main.xml b/apps/CtsVerifier/res/layout/usb_main.xml
index 5c16612..d693ae5 100644
--- a/apps/CtsVerifier/res/layout/usb_main.xml
+++ b/apps/CtsVerifier/res/layout/usb_main.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
+<!-- Copyright (C) 2016 The Android Open 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,55 +14,40 @@
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"
- >
- <TextView android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/usb_sent_messages"
- style="?android:attr/listSeparatorTextViewStyle"
- />
- <FrameLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- >
- <ListView android:id="@+id/usb_sent_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <TextView android:id="@+id/usb_empty_sent_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/usb_no_messages"
- android:visibility="gone"
- />
- </FrameLayout>
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <TextView android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/usb_received_messages"
- style="?android:attr/listSeparatorTextViewStyle"
- />
- <FrameLayout android:orientation="vertical"
+ <LinearLayout android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"
+ android:orientation="vertical"
+ android:padding="16dp">
+
+ <ImageView android:layout_width="32dp"
+ android:layout_height="32dp"
+ android:src="@drawable/ic_usb_48"
+ android:tint="@color/primary"
+ android:scaleType="fitCenter"
+ android:layout_marginBottom="16dp" />
+
+ <ProgressBar android:id="@+id/progress_bar"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_weight="1"
- >
- <ListView android:id="@+id/usb_received_messages"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="16dp"
+ android:visibility="gone" />
+
+ <ScrollView android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_weight="1">
+
+ <TextView android:id="@+id/status"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- />
- <TextView android:id="@+id/usb_empty_received_messages"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:gravity="center"
- android:text="@string/usb_no_messages"
- android:visibility="gone"
- />
- </FrameLayout>
+ android:layout_height="wrap_content" />
+
+ </ScrollView>
+
+ </LinearLayout>
<include layout="@layout/pass_fail_buttons" />
diff --git a/apps/CtsVerifier/res/layout/usb_message_row.xml b/apps/CtsVerifier/res/layout/usb_message_row.xml
deleted file mode 100644
index 3bb228a..0000000
--- a/apps/CtsVerifier/res/layout/usb_message_row.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- style="@style/MessageRow"
- />
diff --git a/apps/CtsVerifier/res/layout/voicemail_broadcast.xml b/apps/CtsVerifier/res/layout/voicemail_broadcast.xml
new file mode 100644
index 0000000..5ce102a
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/voicemail_broadcast.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <TextView
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:text="@string/voicemail_broadcast_instructions"/>
+ <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/set_default_dialer_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/voicemail_set_default_dialer_description"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/set_default_dialer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/voicemail_set_default_dialer_button"/>
+
+ <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/leave_voicemail_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:id="@+id/leave_voicemail_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/voicemail_leave_voicemail"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <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/restore_default_dialer_image"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/fs_indeterminate"
+ android:layout_marginRight="@dimen/js_padding"/>
+ <TextView
+ android:id="@+id/restore_default_dialer_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/voicemail_restore_default_dialer_description"
+ android:textSize="16dp"/>
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/restore_default_dialer"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/voicemail_restore_default_dialer_button"/>
+
+ <include layout="@layout/pass_fail_buttons" />
+</LinearLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/raw/onekhztone.mp3 b/apps/CtsVerifier/res/raw/onekhztone.mp3
new file mode 100644
index 0000000..c0e6660
--- /dev/null
+++ b/apps/CtsVerifier/res/raw/onekhztone.mp3
Binary files differ
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index f51da52..54f6558 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -38,6 +38,7 @@
<string name="test_category_features">Features</string>
<string name="test_category_deskclock">Clock</string>
<string name="test_category_jobscheduler">Job Scheduler</string>
+ <string name="test_category_telephony">Telephony</string>
<string name="test_category_tv">TV</string>
<string name="test_category_other">Other</string>
<string name="clear">Clear</string>
@@ -1069,35 +1070,29 @@
<!-- Strings for USB accessory test activity -->
<string name="usb_accessory_test">USB Accessory Test</string>
- <string name="sensor_power_test">Sensor Power Test</string>
<string name="usb_accessory_test_info">
- 1. Connect your Android device to a computer and ensure that the connection is set
- to charging only from the Android device.
- \n\n2.Run the \'cts-usb-accessory\' program included with the CTS Verifier bundle.
- \n\n3. If you have not started the CTS Verifier, press \'OK\' when asked to open the CTS
- Verifier when the accessory is connected. \n\nIf you are already in this test,
- then you can press \'Cancel\' but press \'OK\' in the next dialog asking whether to allow
- CTS Verifier to access the accessory.
- \n\n4. You should see the accessory and the CTS Verifier display a series of messages
- which indicates that the accessory support is working properly, and then you will
- be presented with more instructions.
+ 1. Install the Cts Verifier USB Companion app on a separate helper device.
+ \n\n2. Start the accessory test companion in the Cts Verifier USB Companion.
+ \n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+ \n\n4. Confirm access to the USB device on the helper device.
+ \n\n5. Confirm access to the USB accessory on this device
+ \n\n6. Confirm access to the USB device on the helper again.
+ \n\n7. Test will run and complete automatically in a less than 30 seconds.
+ \n\n8. Cancel all further dialogs on this device
</string>
- <string name="usb_not_available_title">USB accessory feature is not available?</string>
- <string name="usb_not_available_message">If your device is supposed to support USB accessories, your API implementation is not behaving correctly!</string>
- <string name="usb_received_messages">Received Messages</string>
- <string name="usb_reconnect_title">Disconnect and Reconnect</string>
- <string name="usb_disconnect_message">Please disconnect the Android device and the computer.</string>
- <string name="usb_connect_message">Please connect the Android device and the computer. Do not interact with the device until prompted.</string>
- <string name="usb_reconnect_timeout">Test failed because reconnect timed out. You can interact with the device again.</string>
- <string name="usb_reconnect_abort">Abort Test</string>
- <string name="usb_wait_for_done">Could not find USB accessory. Try waiting longer.</string>
- <string name="usb_sent_messages">Sent Messages</string>
- <string name="usb_no_messages">No messages</string>
- <string name="usb_message_thread_started">Starting message processing...</string>
- <string name="usb_message_thread_exception">Exception occurred while processing a message...</string>
- <string name="usb_message_thread_ended">Stopping message processing...</string>
- <string name="usb_test_passed">Test passed, pass button enabled! You can interact with the device again.</string>
- <string name="usb_file_descriptor_error">Could not open file descriptor for USB accessory... try reconnecting and restarting the accessory?</string>
+ <string name="usb_accessory_test_step1">
+ In this specific order:
+ \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+ \n2. Start the accessory test companion in the Cts Verifier USB Companion.
+ \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to the helper device. If using an Type-C cable make sure that the helper device is set as "supply power to the attached device".
+ \n4. Confirm access to the USB device on the helper device. Only confirm once.
+ \n5. Confirm access to the USB accessory on this device.
+ \n6. Confirm access to the USB device on the helper device again.
+ \n\nResult: A progress indicator should appear or test will finish.
+ </string>
+ <string name="usb_accessory_test_step2">
+ Test is running and will complete automatically in less than 30 seconds.
+ </string>
<!-- String for the USB device test activity -->
<string name="usb_device_test">USB Device Test</string>
@@ -1106,10 +1101,29 @@
\n\n2. Start the device test companion in the Cts Verifier USB Companion.
\n\n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
\n\n4. Confirm access to the USB device on this device.
- \n\n5. Confirm access to the USB accessory on the helper device
+ \n\n5. Confirm access to the USB accessory on the helper device.
\n\n6. Confirm access to the USB device on this device again.
- \n\n7. Test will run and complete automatically in a few seconds
- \n\n8. Cancel all further dialogs on the helper device
+ \n\n7. Test will run and complete automatically in a less than 30 seconds.
+ \n\n8. Cancel all further dialogs on the helper device.
+ </string>
+ <string name="usb_device_test_step1">
+ In this specific order:
+ \n1. Install the Cts Verifier USB Companion app on a separate helper device.
+ \n2. Start the device test companion in the Cts Verifier USB Companion.
+ \n3. Connect the two devices. If using a OTG adapter make sure the adapter is directly connected to this device. If using an Type-C cable make sure that this device is set as "supply power to the attached device".
+ \n\nResult: A dialog should show up on this device asking for access to a USB device.
+ </string>
+ <string name="usb_device_test_step2">
+ Confirm access to the USB device on this device.
+ \n\nResult: Dialogs should show up on this device and on the helper device asking for access to a USB device/accessory.
+ </string>
+ <string name="usb_device_test_step3">
+ 1. Confirm access to the USB accessory on the helper device.
+ \n2. Confirm access to the USB device on this device again.
+ \n\nResult: A progress indicator should appear or test will finish.
+ </string>
+ <string name="usb_device_test_step4">
+ Test is running and will complete automatically in a less than 30 seconds.
</string>
<string name="usb_device_unexpected">Usb companion device is not as expected %1$s. Please retry test.</string>
@@ -1439,6 +1453,12 @@
<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="nls_snooze">Check the service can be snoozed.</string>
+ <string name="nls_unsnooze">Check the service can be unsnoozed.</string>
+ <string name="nls_hints">Check that the listener can set hints.</string>
+ <string name="nls_snooze_one">Check that service can snooze a notification.</string>
+ <string name="nls_snooze_one_time">Check that service can snooze a notification for a given time.</string>
+ <string name="nls_unsnooze_one">Check that service can unsnooze a notification.</string>
<string name="nas_note_missed_enqueued">Check that notification was not enqueued.</string>
<string name="cp_test">Condition Provider test</string>
<string name="cp_service_name">Condition Provider for CTS Verifier</string>
@@ -2449,10 +2469,6 @@
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>
@@ -2466,7 +2482,8 @@
- You cannot edit, add or remove any existing VPNs.\n
- Trying to perform any of the above actions will trigger a support message.\n\n
2. Press Check VPN to check programmatic Vpn test.\n
- - Check Vpn setup\n\n
+ - Check Vpn setup is not allowed\n
+ - If prompted to allow a VPN connection, press OK.\n\n
Use the Back button to return to this page.
</string>
<string name="device_owner_user_vpn_restriction_set">Set VPN restriction</string>
@@ -2666,7 +2683,7 @@
<string name="password_quality_complex">Complex</string>
<string name="set_permitted_accessibility_services">Set permitted accessibility services</string>
<string name="permitted_accessibility_services_set_step">
- Disallow \'Dummy Accessibility service\' from permitted accessibility services by turning on
+ Check that \'Dummy Accessibility service\' is not enabled in Settings and disallow \'Dummy Accessibility service\' from permitted accessibility services by turning on
the switch below.
</string>
<string name="set_permitted_accessibility_services_action">
@@ -2677,7 +2694,7 @@
</string>
<string name="set_permitted_input_methods">Set permitted input methods</string>
<string name="permitted_input_methods_set_step">
- Disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
+ Check that \'Dummy Input method\' is not enabled in Settings and disallow \'Dummy Input method\' from permitted input methods by turning on the switch below.
</string>
<string name="set_permitted_input_methods_action">
Enabling \'Dummy Input Method\' in the list of accessibility services
@@ -2938,7 +2955,7 @@
<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_passed">Test Result: Successful</string>
<string name="audio_general_test_failed">Test Result: Not Optimal</string>
<string name="audio_general_default_false_string">false</string>
<string name="audio_general_default_true_string">true</string>
@@ -3032,18 +3049,40 @@
<!-- Audio Frequency Unprocessed Test -->
<string name="audio_frequency_unprocessed_test">Audio Frequency Unprocessed Test</string>
<string name="audio_frequency_unprocessed_info">
- This test requires an external broadband noise source (or click/impulse).
- Please be prepared to activate the noise source when asked to.
- The system will measure frequency response of the built in microphone using the UNPROCESSED
- audio source.
+ This test requires an external USB reference microphone, external speakers and a Sound Pressure Level meter.
+ You can play the test signals from the device under test or from a secondary device.
+ Follow the instructions on the screen to measure the frequency response for the built in microphone
+ using UNPROCESSED audio source.
+ If the Audio Frequency Unprocessed feature is defined in this system, success in all tests is mandatory to pass.
+ If the feature is not defined, measurements are still needed, but success in all of them is not mandatory to pass.
</string>
- <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Test is mandatory</string>
- <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Test is optional</string>
- <string name="audio_frequency_unprocessed_instructions2">
- Once you press the [TEST] button, you have 5 seconds to play a broadband sound (click or white noise).
- </string>
- <string name="audio_frequency_unprocessed_test1_btn">Test 1</string>
- <string name="audio_frequency_unprocessed_results_text">Results...</string>
+ <string name="audio_frequency_unprocessed_defined">Audio Frequency Unprocessed feature is defined. Success in all tests is mandatory to pass</string>
+ <string name="audio_frequency_unprocessed_not_defined">Audio Frequency Unprocessed feature is NOT defined. Success in all test is NOT mandatory to pass</string>
+
+ <string name="unprocessed_play">Play</string>
+ <string name="unprocessed_stop">Stop</string>
+
+ <string name="unprocessed_test_tone_instructions">TEST TONE: Press [PLAY] to play tone at 1 Khz. Measure sound SPL to be 94 dB
+ right next to microphone under test. Press [TEST]</string>
+ <string name="unprocessed_test_tone_btn">Test</string>
+ <string name="unprocessed_test_tone_result">Results...</string>
+
+ <string name="unprocessed_test_noise_instructions">TEST NOISE: Position speakers 40 cms from device under test.
+ Press [PLAY] to play broadband white noise. Press [TEST]</string>
+ <string name="unprocessed_test_noise_btn">Test</string>
+ <string name="unprocessed_test_noise_result">Results...</string>
+
+ <string name="unprocessed_test_usb_background_instructions">TEST USB BACKGROUND: Connect USB microphone and position it right next to microphone under test.
+ No source of noise should be active during this test. Press [TEST]</string>
+ <string name="unprocessed_test_usb_background_btn">Test</string>
+ <string name="unprocessed_test_usb_background_result">Results...</string>
+
+ <string name="unprocessed_test_usb_noise_instructions">TEST USB NOISE: Connect USB microphone and position it right next to microphone under test.
+ Position speakers 40 cms from device under test. Press [PLAY] to play broadband white noise. Press [TEST]</string>
+ <string name="unprocessed_test_usb_noise_btn">Test</string>
+ <string name="unprocessed_test_usb_noise_result">Results...</string>
+
+ <string name="unprocessed_test_global_result">Global Results...</string>
<!-- Strings for 6DoF test -->
<string name="six_dof_test">6DoF Test</string>
@@ -3179,4 +3218,17 @@
<item>@string/phase3_description</item>
</string-array>
+ <!-- Strings for voicemail broadcast test -->
+ <string name="voicemail_broadcast_test">Voicemail Broadcast Test</string>
+ <string name="voicemail_broadcast_instructions">This test verifies that the default dialer can intercept the voicemail notification. The test must be conducted on a SIM with visual voicemail disabled</string>
+ <string name="voicemail_set_default_dialer_description">Before the test, the CTS verifier should be set to the default dialer</string>
+ <string name="voicemail_set_default_dialer_button">Set CTS verifier as default dialer"</string>
+ <string name="voicemail_leave_voicemail">Send a voicemail to the device, CTS verifier should receive a voicemail notification broadcast</string>
+ <string name="voicemail_broadcast_received">Voicemail broadcast Received</string>
+ <string name="voicemail_restore_default_dialer_description">(Optional) restore the default dialer setting</string>
+ <string name="voicemail_restore_default_dialer_no_default_description">(Optional) restore the default dialer by going to settings-> apps -> cogwheel -> Phone app</string>
+ <string name="voicemail_restore_default_dialer_button">Restore the default dialer"</string>
+ <string name="voicemail_default_dialer_already_set">Default dialer already set</string>
+ <string name="voicemail_default_dialer_already_restored">Default dialer already restored</string>
+
</resources>
diff --git a/apps/CtsVerifier/res/xml/accessory_filter.xml b/apps/CtsVerifier/res/xml/accessory_filter.xml
index 21caaa4..4a1d779 100644
--- a/apps/CtsVerifier/res/xml/accessory_filter.xml
+++ b/apps/CtsVerifier/res/xml/accessory_filter.xml
@@ -14,5 +14,5 @@
limitations under the License.
-->
<resources>
- <usb-accessory manufacturer="Android CTS" model="CTS USB Accessory" version="1.0" />
+ <usb-accessory />
</resources>
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
index 56275c5..009dd58 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioFrequencyUnprocessedActivity.java
@@ -22,11 +22,11 @@
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.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
-
import android.media.AudioDeviceCallback;
import android.media.AudioDeviceInfo;
import android.media.AudioFormat;
@@ -34,17 +34,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;
@@ -59,25 +55,63 @@
private static final String TAG = "AudioFrequencyUnprocessedActivity";
private static final int TEST_STARTED = 900;
- private static final int TEST_ENDED = 901;
- private static final int TEST_MESSAGE = 902;
- private static final int TEST1_MESSAGE = 903;
- private static final int TEST1_ENDED = 904;
- private static final double MIN_ENERGY_BAND_1 = -50.0; //dB Full Scale
- private static final double MAX_ENERGY_BAND_1_BASE = -60.0; //dB Full Scale
- private static final double MIN_FRACTION_POINTS_IN_BAND = 0.3;
+ private static final int TEST_MESSAGE = 903;
+ private static final int TEST_ENDED = 904;
+ private static final int TEST_ENDED_ERROR = 905;
+ private static final double MIN_FRACTION_POINTS_IN_BAND = 0.5;
+
+ private static final double TONE_RMS_EXPECTED = -36.0;
+ private static final double TONE_RMS_MAX_ERROR = 3.0;
+
private static final double MAX_VAL = Math.pow(2, 15);
private static final double CLIP_LEVEL = (MAX_VAL-10) / MAX_VAL;
+ private static final int SOURCE_TONE = 0;
+ private static final int SOURCE_NOISE = 1;
+
+ private static final int TEST_NONE = -1;
+ private static final int TEST_TONE = 0;
+ private static final int TEST_NOISE = 1;
+ private static final int TEST_USB_BACKGROUND = 2;
+ private static final int TEST_USB_NOISE = 3;
+ private static final int TEST_COUNT = 4;
+ private int mCurrentTest = TEST_NONE;
+ private boolean mTestsDone[] = new boolean[TEST_COUNT];
+
+ private static final int TEST_DURATION_DEFAULT = 2000;
+ private static final int TEST_DURATION_TONE = TEST_DURATION_DEFAULT;
+ private static final int TEST_DURATION_NOISE = TEST_DURATION_DEFAULT;
+ private static final int TEST_DURATION_USB_BACKGROUND = TEST_DURATION_DEFAULT;
+ private static final int TEST_DURATION_USB_NOISE = TEST_DURATION_DEFAULT;
+
final OnBtnClickListener mBtnClickListener = new OnBtnClickListener();
Context mContext;
- Button mTest1Button; //execute test 1
- Button mTest2Button; //user to start test
- String mUsbDevicesInfo; //usb device info for report
- LinearLayout mLayoutTest1;
- TextView mTest1Result;
- ProgressBar mProgressBar;
+ LinearLayout mLayoutTestTone;
+ Button mButtonTestTone;
+ ProgressBar mProgressTone;
+ TextView mResultTestTone;
+ Button mButtonPlayTone;
+
+ LinearLayout mLayoutTestNoise;
+ Button mButtonTestNoise;
+ ProgressBar mProgressNoise;
+ TextView mResultTestNoise;
+ Button mButtonPlayNoise;
+
+ LinearLayout mLayoutTestUsbBackground;
+ Button mButtonTestUsbBackground;
+ ProgressBar mProgressUsbBackground;
+ TextView mResultTestUsbBackground;
+
+ LinearLayout mLayoutTestUsbNoise;
+ Button mButtonTestUsbNoise;
+ ProgressBar mProgressUsbNoise;
+ TextView mResultTestUsbNoise;
+ Button mButtonPlayUsbNoise;
+
+ TextView mGlobalResultText;
+ TextView mTextViewUnprocessedStatus;
private boolean mIsRecording = false;
private final Object mRecordingLock = new Object();
@@ -95,6 +129,8 @@
PipeShort mPipe = new PipeShort(65536);
+ SoundPlayerObject mSPlayer;
+
private boolean mSupportsUnprocessed = false;
private DspBufferComplex mC;
@@ -102,25 +138,27 @@
private DspWindow mWindow;
private DspFftServer mFftServer;
- private VectorAverage mFreqAverageMain = new VectorAverage();
- private VectorAverage mFreqAverageBuiltIn = new VectorAverage();
+ private VectorAverage mFreqAverageTone = new VectorAverage();
+ private VectorAverage mFreqAverageNoise = new VectorAverage();
+ private VectorAverage mFreqAverageUsbBackground = new VectorAverage();
+ private VectorAverage mFreqAverageUsbNoise = new VectorAverage();
- int mBands = 4;
- AudioBandSpecs[] bandSpecsArray = new AudioBandSpecs[mBands];
- private TextView mTextViewUnprocessedStatus;
+ //RMS for tone:
+ private double mRMS;
+ private double mRMSMax;
- private class OnBtnClickListener implements OnClickListener {
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.audio_frequency_unprocessed_test1_btn:
- setMaxLevel();
- testMaxLevel();
- startTest1();
- break;
- }
- }
- }
+ private double mRMSTone;
+ private double mRMSMaxTone;
+
+ int mBands = 3;
+ int mBandsTone = 3;
+ int mBandsBack = 3;
+ AudioBandSpecs[] mBandSpecsMic = new AudioBandSpecs[mBands];
+ AudioBandSpecs[] mBandSpecsTone = new AudioBandSpecs[mBandsTone];
+ AudioBandSpecs[] mBandSpecsBack = new AudioBandSpecs[mBandsBack];
+ private Results mResultsMic;
+ private Results mResultsTone;
+ private Results mResultsBack;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -139,13 +177,51 @@
getResources().getText(R.string.audio_frequency_unprocessed_not_defined));
}
- mTest1Button = (Button)findViewById(R.id.audio_frequency_unprocessed_test1_btn);
- mTest1Button.setOnClickListener(mBtnClickListener);
- mTest1Result = (TextView)findViewById(R.id.audio_frequency_unprocessed_results1_text);
- mLayoutTest1 = (LinearLayout) findViewById(R.id.audio_frequency_unprocessed_layout_test1);
- mProgressBar = (ProgressBar)findViewById(R.id.audio_frequency_unprocessed_progress_bar);
- showWait(false);
- enableLayout(mLayoutTest1, true);
+ mSPlayer = new SoundPlayerObject();
+ playerSetSource(SOURCE_TONE);
+
+ // Test tone
+ mLayoutTestTone = (LinearLayout) findViewById(R.id.unprocessed_layout_test_tone);
+ mButtonTestTone = (Button) findViewById(R.id.unprocessed_test_tone_btn);
+ mButtonTestTone.setOnClickListener(mBtnClickListener);
+ mProgressTone = (ProgressBar) findViewById(R.id.unprocessed_test_tone_progress_bar);
+ mResultTestTone = (TextView) findViewById(R.id.unprocessed_test_tone_result);
+ mButtonPlayTone = (Button) findViewById(R.id.unprocessed_play_tone_btn);
+ mButtonPlayTone.setOnClickListener(mBtnClickListener);
+ showWait(mProgressTone, false);
+
+ //Test Noise
+ mLayoutTestNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_noise);
+ mButtonTestNoise = (Button) findViewById(R.id.unprocessed_test_noise_btn);
+ mButtonTestNoise.setOnClickListener(mBtnClickListener);
+ mProgressNoise = (ProgressBar) findViewById(R.id.unprocessed_test_noise_progress_bar);
+ mResultTestNoise = (TextView) findViewById(R.id.unprocessed_test_noise_result);
+ mButtonPlayNoise = (Button) findViewById(R.id.unprocessed_play_noise_btn);
+ mButtonPlayNoise.setOnClickListener(mBtnClickListener);
+ showWait(mProgressNoise, false);
+
+ //USB Background
+ mLayoutTestUsbBackground = (LinearLayout)
+ findViewById(R.id.unprocessed_layout_test_usb_background);
+ mButtonTestUsbBackground = (Button) findViewById(R.id.unprocessed_test_usb_background_btn);
+ mButtonTestUsbBackground.setOnClickListener(mBtnClickListener);
+ mProgressUsbBackground = (ProgressBar)
+ findViewById(R.id.unprocessed_test_usb_background_progress_bar);
+ mResultTestUsbBackground = (TextView)
+ findViewById(R.id.unprocessed_test_usb_background_result);
+ showWait(mProgressUsbBackground, false);
+
+ mLayoutTestUsbNoise = (LinearLayout) findViewById(R.id.unprocessed_layout_test_usb_noise);
+ mButtonTestUsbNoise = (Button) findViewById(R.id.unprocessed_test_usb_noise_btn);
+ mButtonTestUsbNoise.setOnClickListener(mBtnClickListener);
+ mProgressUsbNoise = (ProgressBar)findViewById(R.id.unprocessed_test_usb_noise_progress_bar);
+ mResultTestUsbNoise = (TextView) findViewById(R.id.unprocessed_test_usb_noise_result);
+ mButtonPlayUsbNoise = (Button) findViewById(R.id.unprocessed_play_usb_noise_btn);
+ mButtonPlayUsbNoise.setOnClickListener(mBtnClickListener);
+ showWait(mProgressUsbNoise, false);
+
+ setButtonPlayStatus(-1);
+ mGlobalResultText = (TextView) findViewById(R.id.unprocessed_test_global_result);
//Init FFT stuff
mAudioShortArray2 = new short[mBlockSizeSamples*2];
@@ -162,29 +238,141 @@
setInfoResources(R.string.audio_frequency_unprocessed_test,
R.string.audio_frequency_unprocessed_info, -1);
- //Init bands for BuiltIn/Reference test
- bandSpecsArray[0] = new AudioBandSpecs(
- 2, 500, /* frequency start,stop */
- 30.0, -50, /* start top,bottom value */
- 30.0, -4.0 /* stop top,bottom value */);
+ //Init bands for Mic test
+ mBandSpecsMic[0] = new AudioBandSpecs(
+ 5, 100, /* frequency start,stop */
+ 20.0, -20.0, /* start top,bottom value */
+ 20.0, -20.0 /* stop top,bottom value */);
- bandSpecsArray[1] = new AudioBandSpecs(
- 500,4000, /* frequency start,stop */
- 4.0, -4.0, /* start top,bottom value */
- 4.0, -4.0 /* stop top,bottom value */);
+ mBandSpecsMic[1] = new AudioBandSpecs(
+ 100, 7000, /* frequency start,stop */
+ 10.0, -10.0, /* start top,bottom value */
+ 10.0, -10.0 /* stop top,bottom value */);
- bandSpecsArray[2] = new AudioBandSpecs(
- 4000, 12000, /* frequency start,stop */
- 4.0, -4.0, /* start top,bottom value */
- 5.0, -5.0 /* stop top,bottom value */);
+ mBandSpecsMic[2] = new AudioBandSpecs(
+ 7000, 20000, /* frequency start,stop */
+ 30.0, -30.0, /* start top,bottom value */
+ 30.0, -30.0 /* stop top,bottom value */);
- bandSpecsArray[3] = new AudioBandSpecs(
- 12000, 20000, /* frequency start,stop */
- 5.0, -5.0, /* start top,bottom value */
- 5.0, -30.0 /* stop top,bottom value */);
+ //Init bands for Tone test
+ mBandSpecsTone[0] = new AudioBandSpecs(
+ 5, 900, /* frequency start,stop */
+ -10.0, -100.0, /* start top,bottom value */
+ -10.0, -100.0 /* stop top,bottom value */);
+
+ mBandSpecsTone[1] = new AudioBandSpecs(
+ 900, 1100, /* frequency start,stop */
+ 10.0, -50.0, /* start top,bottom value */
+ 10.0, -10.0 /* stop top,bottom value */);
+
+ mBandSpecsTone[2] = new AudioBandSpecs(
+ 1100, 20000, /* frequency start,stop */
+ -30.0, -120.0, /* start top,bottom value */
+ -30.0, -120.0 /* stop top,bottom value */);
+
+ //Init bands for Background test
+ mBandSpecsBack[0] = new AudioBandSpecs(
+ 5, 100, /* frequency start,stop */
+ 10.0, -120.0, /* start top,bottom value */
+ -10.0, -120.0 /* stop top,bottom value */);
+
+ mBandSpecsBack[1] = new AudioBandSpecs(
+ 100, 7000, /* frequency start,stop */
+ -10.0, -120.0, /* start top,bottom value */
+ -50.0, -120.0 /* stop top,bottom value */);
+
+ mBandSpecsBack[2] = new AudioBandSpecs(
+ 7000, 20000, /* frequency start,stop */
+ -50.0, -120.0, /* start top,bottom value */
+ -50.0, -120.0 /* stop top,bottom value */);
mSupportsUnprocessed = supportsUnprocessed();
Log.v(TAG, "Supports unprocessed: " + mSupportsUnprocessed);
+
+ mResultsMic = new Results("mic_response", mBands);
+ mResultsTone = new Results("tone_response", mBandsTone);
+ mResultsBack = new Results("background_response", mBandsBack);
+ }
+
+ private void playerToggleButton(int buttonId, int sourceId) {
+ if (playerIsPlaying()) {
+ playerStopAll();
+ } else {
+ playerSetSource(sourceId);
+ playerTransport(true);
+ setButtonPlayStatus(buttonId);
+ }
+ }
+
+ private class OnBtnClickListener implements OnClickListener {
+ @Override
+ public void onClick(View v) {
+ int id = v.getId();
+ switch (id) {
+ case R.id.unprocessed_test_tone_btn:
+ startTest(TEST_TONE);
+ break;
+ case R.id.unprocessed_play_tone_btn:
+ playerToggleButton(id, SOURCE_TONE);
+ break;
+ case R.id.unprocessed_test_noise_btn:
+ startTest(TEST_NOISE);
+ break;
+ case R.id.unprocessed_play_noise_btn:
+ playerToggleButton(id, SOURCE_NOISE);
+ break;
+ case R.id.unprocessed_test_usb_background_btn:
+ startTest(TEST_USB_BACKGROUND);
+ break;
+ case R.id.unprocessed_test_usb_noise_btn:
+ startTest(TEST_USB_NOISE);
+ break;
+ case R.id.unprocessed_play_usb_noise_btn:
+ playerToggleButton(id, SOURCE_NOISE);
+ break;
+ }
+ }
+ }
+
+ private void setButtonPlayStatus(int playResId) {
+ String play = getResources().getText(R.string.unprocessed_play).toString();
+ String stop = getResources().getText(R.string.unprocessed_stop).toString();
+
+ mButtonPlayTone.setText(playResId == R.id.unprocessed_play_tone_btn ? stop : play);
+ mButtonPlayNoise.setText(playResId == R.id.unprocessed_play_noise_btn ? stop : play);
+ mButtonPlayUsbNoise.setText(playResId ==
+ R.id.unprocessed_play_usb_noise_btn ? stop : play);
+ }
+
+ private void playerSetSource(int sourceIndex) {
+ switch (sourceIndex) {
+ case SOURCE_TONE:
+ mSPlayer.setSoundWithResId(getApplicationContext(), R.raw.onekhztone);
+ break;
+ default:
+ case SOURCE_NOISE:
+ mSPlayer.setSoundWithResId(getApplicationContext(),
+ R.raw.stereo_mono_white_noise_48);
+ break;
+ }
+ }
+
+ private void playerTransport(boolean play) {
+ if (!mSPlayer.isAlive()) {
+ mSPlayer.start();
+ }
+ mSPlayer.play(play);
+ }
+
+ private boolean playerIsPlaying() {
+ return mSPlayer.isPlaying();
+ }
+
+ private void playerStopAll() {
+ if (mSPlayer.isAlive() && mSPlayer.isPlaying()) {
+ mSPlayer.play(false);
+ setButtonPlayStatus(-1);
+ }
}
/**
@@ -197,14 +385,66 @@
}
}
- /**
- * show active progress bar
- */
- private void showWait(boolean show) {
+ private void showWait(ProgressBar pb, boolean show) {
if (show) {
- mProgressBar.setVisibility(View.VISIBLE);
+ pb.setVisibility(View.VISIBLE);
} else {
- mProgressBar.setVisibility(View.INVISIBLE);
+ pb.setVisibility(View.INVISIBLE);
+ }
+ }
+
+ private String getTestString(int testId) {
+ String name = "undefined";
+ switch(testId) {
+ case TEST_TONE:
+ name = "BuiltIn_tone";
+ break;
+ case TEST_NOISE:
+ name = "BuiltIn_noise";
+ break;
+ case TEST_USB_BACKGROUND:
+ name = "USB_background";
+ break;
+ case TEST_USB_NOISE:
+ name = "USB_noise";
+ break;
+ }
+ return name;
+ }
+
+ private void showWait(int testId, boolean show) {
+ switch(testId) {
+ case TEST_TONE:
+ showWait(mProgressTone, show);
+ break;
+ case TEST_NOISE:
+ showWait(mProgressNoise, show);
+ break;
+ case TEST_USB_BACKGROUND:
+ showWait(mProgressUsbBackground, show);
+ break;
+ case TEST_USB_NOISE:
+ showWait(mProgressUsbNoise, show);
+ break;
+ }
+ }
+
+ private void showMessage(int testId, String msg) {
+ if (msg != null && msg.length() > 0) {
+ switch(testId) {
+ case TEST_TONE:
+ mResultTestTone.setText(msg);
+ break;
+ case TEST_NOISE:
+ mResultTestNoise.setText(msg);
+ break;
+ case TEST_USB_BACKGROUND:
+ mResultTestUsbBackground.setText(msg);
+ break;
+ case TEST_USB_NOISE:
+ mResultTestUsbNoise.setText(msg);
+ break;
+ }
}
}
@@ -224,47 +464,320 @@
return unprocessedSupport;
}
- /**
- * Start the loopback audio test
- */
- private void startTest1() {
+ private void computeAllResults() {
+ StringBuilder sb = new StringBuilder();
+
+ boolean allDone = true;
+
+ for (int i=0; i<TEST_COUNT; i++) {
+ allDone = allDone & mTestsDone[i];
+ sb.append(String.format("%s : %s\n", getTestString(i),
+ mTestsDone[i] ? "DONE" :" NOT DONE"));
+ }
+
+ if (allDone) {
+ sb.append(computeResults());
+ } else {
+ sb.append("Please execute all tests for results\n");
+ }
+ mGlobalResultText.setText(sb.toString());
+ }
+
+ private void processSpectrum(Results results, AudioBandSpecs[] bandsSpecs, int anchorBand) {
+ int points = results.mValuesLog.length;
+ int bandCount = bandsSpecs.length;
+ int currentBand = 0;
+ for (int i = 0; i < points; i++) {
+ double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
+ if (freq > bandsSpecs[currentBand].mFreqStop) {
+ currentBand++;
+ if (currentBand >= bandCount)
+ break;
+ }
+
+ if (freq >= bandsSpecs[currentBand].mFreqStart) {
+ results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
+ results.mPointsPerBand[currentBand]++;
+ }
+ }
+
+ for (int b = 0; b < bandCount; b++) {
+ if (results.mPointsPerBand[b] > 0) {
+ results.mAverageEnergyPerBand[b] =
+ results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
+ }
+ }
+
+ //set offset relative to band anchor band level
+ for (int b = 0; b < bandCount; b++) {
+ if (anchorBand > -1 && anchorBand < bandCount) {
+ bandsSpecs[b].setOffset(results.mAverageEnergyPerBand[anchorBand]);
+ } else {
+ bandsSpecs[b].setOffset(0);
+ }
+ }
+
+ //test points in band.
+ currentBand = 0;
+ for (int i = 0; i < points; i++) {
+ double freq = (double) mSamplingRate * i / (double) mBlockSizeSamples;
+ if (freq > bandsSpecs[currentBand].mFreqStop) {
+ currentBand++;
+ if (currentBand >= bandCount)
+ break;
+ }
+
+ if (freq >= bandsSpecs[currentBand].mFreqStart) {
+ double value = results.mValuesLog[i];
+ if (bandsSpecs[currentBand].isInBounds(freq, value)) {
+ results.mInBoundPointsPerBand[currentBand]++;
+ }
+ }
+ }
+ }
+
+ private String computeResults() {
+ StringBuilder sb = new StringBuilder();
+
+ int points = mFreqAverageNoise.getSize();
+ //mFreqAverageNoise size is determined by the latest data writen to it.
+ //Currently, this data is always mBlockSizeSamples/2.
+ if (points < 1) {
+ return "error: not enough points";
+ }
+
+ double[] tone = new double[points];
+ double[] noise = new double[points];
+ double[] reference = new double[points];
+ double[] background = new double[points];
+
+ mFreqAverageTone.getData(tone, false);
+ mFreqAverageNoise.getData(noise, false);
+ mFreqAverageUsbNoise.getData(reference, false);
+ mFreqAverageUsbBackground.getData(background, false);
+
+ //Convert to dB
+ double[] toneDb = new double[points];
+ double[] noiseDb = new double[points];
+ double[] referenceDb = new double[points];
+ double[] backgroundDb = new double[points];
+
+ double[] compensatedNoiseDb = new double[points];
+
+ for (int i = 0; i < points; i++) {
+ toneDb[i] = 20 * Math.log10(tone[i]);
+ noiseDb[i] = 20 * Math.log10(noise[i]);
+ referenceDb[i] = 20 * Math.log10(reference[i]);
+ backgroundDb[i] = 20 * Math.log10(background[i]);
+
+ compensatedNoiseDb[i] = noiseDb[i] - referenceDb[i];
+ }
+
+ mResultsMic.reset();
+ mResultsTone.reset();
+ mResultsBack.reset();
+
+ mResultsMic.mValuesLog = compensatedNoiseDb;
+ mResultsTone.mValuesLog = toneDb;
+ mResultsBack.mValuesLog = backgroundDb;
+
+ processSpectrum(mResultsMic, mBandSpecsMic, 1);
+ processSpectrum(mResultsTone, mBandSpecsTone, 1);
+ processSpectrum(mResultsBack, mBandSpecsBack, -1); //no reference for offset
+
+ //Tone test
+ boolean toneTestSuccess = true;
+ {
+ //rms level should be -36 dbfs +/- 3 db?
+ double rmsMaxDb = 20 * Math.log10(mRMSMaxTone);
+ sb.append(String.format("RMS level of tone: %.2f dBFS\n", rmsMaxDb));
+ sb.append(String.format("Target RMS level: %.2f dBFS +/- %.2f dB\n",
+ TONE_RMS_EXPECTED,
+ TONE_RMS_MAX_ERROR));
+ if (Math.abs(rmsMaxDb - TONE_RMS_EXPECTED) > TONE_RMS_MAX_ERROR) {
+ toneTestSuccess = false;
+ sb.append("RMS level test FAILED\n");
+ } else {
+ sb.append(" RMS level test SUCCESSFUL\n");
+ }
+ //check the spectrum is really a tone around 1 khz
+ }
+
+ sb.append("\n");
+ sb.append(mResultsTone.toString());
+ if (mResultsTone.testAll()) {
+ sb.append(" 1 Khz Tone Frequency Response Test SUCCESSFUL\n");
+ } else {
+ sb.append(" 1 Khz Tone Frequency Response Test FAILED\n");
+ }
+ sb.append("\n");
+
+ sb.append("\n");
+ sb.append(mResultsBack.toString());
+ if (mResultsBack.testAll()) {
+ sb.append(" Background environment Test SUCCESSFUL\n");
+ } else {
+ sb.append(" Background environment Test FAILED\n");
+ }
+
+ sb.append("\n");
+ sb.append(mResultsMic.toString());
+ if (mResultsMic.testAll()) {
+ sb.append(" Frequency Response Test SUCCESSFUL\n");
+ } else {
+ sb.append(" Frequency Response Test FAILED\n");
+ }
+ sb.append("\n");
+
+ recordTestResults(mResultsTone);
+ recordTestResults(mResultsMic);
+
+ boolean allTestsPassed = false;
+ if (mResultsMic.testAll() && mResultsTone.testAll() && toneTestSuccess &&
+ mResultsBack.testAll()) {
+ allTestsPassed = true;
+ String strSuccess = getResources().getString(R.string.audio_general_test_passed);
+ sb.append(strSuccess);
+ } else {
+ String strFailed = getResources().getString(R.string.audio_general_test_failed);
+ sb.append(strFailed);
+ }
+
+ sb.append("\n");
+ if (mSupportsUnprocessed) { //test is mandatory
+ sb.append(getResources().getText(
+ R.string.audio_frequency_unprocessed_defined).toString());
+ if (allTestsPassed) {
+ getPassButton().setEnabled(true);
+ } else {
+ getPassButton().setEnabled(false);
+ }
+ } else {
+ //test optional
+ sb.append(getResources().getText(
+ R.string.audio_frequency_unprocessed_not_defined).toString());
+ getPassButton().setEnabled(true);
+ }
+ return sb.toString();
+ }
+
+ Thread mTestThread;
+ private void startTest(int testId) {
if (mTestThread != null && !mTestThread.isAlive()) {
mTestThread = null; //kill it.
}
if (mTestThread == null) {
+ mRMS = 0;
+ mRMSMax = 0;
Log.v(TAG,"Executing test Thread");
- mTestThread = new Thread(mTest1Runnable);
+ switch(testId) {
+ case TEST_TONE:
+ mTestThread = new Thread(new TestRunnable(TEST_TONE) {
+ public void run() {
+ super.run();
+ if (!mUsbMicConnected) {
+ sendMessage(mTestId, TEST_MESSAGE,
+ "Testing Built in Microphone: Tone");
+ mRMSTone = 0;
+ mRMSMaxTone = 0;
+ mFreqAverageTone.reset();
+ mFreqAverageTone.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+ record(TEST_DURATION_TONE);
+ sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+ mTestsDone[mTestId] = true;
+ } else {
+ sendMessage(mTestId, TEST_ENDED_ERROR,
+ "Please Unplug USB Microphone");
+ mTestsDone[mTestId] = false;
+ }
+ }
+ });
+ break;
+ case TEST_NOISE:
+ mTestThread = new Thread(new TestRunnable(TEST_NOISE) {
+ public void run() {
+ super.run();
+ if (!mUsbMicConnected) {
+ sendMessage(mTestId, TEST_MESSAGE,
+ "Testing Built in Microphone: Noise");
+ mFreqAverageNoise.reset();
+ mFreqAverageNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+ record(TEST_DURATION_NOISE);
+ sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+ mTestsDone[mTestId] = true;
+ } else {
+ sendMessage(mTestId, TEST_ENDED_ERROR,
+ "Please Unplug USB Microphone");
+ mTestsDone[mTestId] = false;
+ }
+ }
+ });
+ break;
+ case TEST_USB_BACKGROUND:
+ playerStopAll();
+ mTestThread = new Thread(new TestRunnable(TEST_USB_BACKGROUND) {
+ public void run() {
+ super.run();
+ if (mUsbMicConnected) {
+ sendMessage(mTestId, TEST_MESSAGE,
+ "Testing USB Microphone: background");
+ mFreqAverageUsbBackground.reset();
+ mFreqAverageUsbBackground.setCaptureType(
+ VectorAverage.CAPTURE_TYPE_AVERAGE);
+ record(TEST_DURATION_USB_BACKGROUND);
+ sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+ mTestsDone[mTestId] = true;
+ } else {
+ sendMessage(mTestId, TEST_ENDED_ERROR,
+ "USB Microphone not detected.");
+ mTestsDone[mTestId] = false;
+ }
+ }
+ });
+ break;
+ case TEST_USB_NOISE:
+ mTestThread = new Thread(new TestRunnable(TEST_USB_NOISE) {
+ public void run() {
+ super.run();
+ if (mUsbMicConnected) {
+ sendMessage(mTestId, TEST_MESSAGE, "Testing USB Microphone: Noise");
+ mFreqAverageUsbNoise.reset();
+ mFreqAverageUsbNoise.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
+ record(TEST_DURATION_USB_NOISE);
+ sendMessage(mTestId, TEST_ENDED, "Testing Completed");
+ mTestsDone[mTestId] = true;
+ } else {
+ sendMessage(mTestId, TEST_ENDED_ERROR,
+ "USB Microphone not detected.");
+ mTestsDone[mTestId] = false;
+ }
+ }
+ });
+ break;
+ }
mTestThread.start();
} else {
Log.v(TAG,"test Thread already running.");
}
}
-
- Thread mTestThread;
- Runnable mTest1Runnable = new Runnable() {
- public void run() {
- Message msg = Message.obtain();
- msg.what = TEST_STARTED;
- mMessageHandler.sendMessage(msg);
-
- sendMessage("Testing Built in Microphone");
- mFreqAverageBuiltIn.reset();
- mFreqAverageBuiltIn.setCaptureType(VectorAverage.CAPTURE_TYPE_MAX);
- play();
-
- sendMessage("Testing Completed");
-
- Message msg2 = Message.obtain();
- msg2.what = TEST1_ENDED;
- mMessageHandler.sendMessage(msg2);
+ public class TestRunnable implements Runnable {
+ public int mTestId;
+ public boolean mUsbMicConnected;
+ TestRunnable(int testId) {
+ Log.v(TAG,"New TestRunnable");
+ mTestId = testId;
}
-
- private void play() {
+ public void run() {
+ mCurrentTest = mTestId;
+ sendMessage(mTestId, TEST_STARTED,"");
+ mUsbMicConnected =
+ UsbMicrophoneTester.getIsMicrophoneConnected(getApplicationContext());
+ };
+ public void record(int durationMs) {
startRecording();
-
try {
- Thread.sleep(5000);
+ Thread.sleep(durationMs);
} catch (InterruptedException e) {
e.printStackTrace();
//restore interrupted status
@@ -272,41 +785,40 @@
}
stopRecording();
}
-
- private void sendMessage(String str) {
+ public void sendMessage(int testId, int msgType, String str) {
Message msg = Message.obtain();
- msg.what = TEST1_MESSAGE;
+ msg.what = msgType;
msg.obj = str;
+ msg.arg1 = testId;
mMessageHandler.sendMessage(msg);
}
- };
+ }
private Handler mMessageHandler = new Handler() {
public void handleMessage(Message msg) {
super.handleMessage(msg);
+ int testId = msg.arg1; //testId
+ String str = (String) msg.obj;
switch (msg.what) {
case TEST_STARTED:
- showWait(true);
- getPassButton().setEnabled(false);
+ showWait(testId, true);
+// getPassButton().setEnabled(false);
+ break;
+ case TEST_MESSAGE:
+ showMessage(testId, str);
break;
case TEST_ENDED:
- showWait(false);
-// computeTest2Results();
+ showWait(testId, false);
+ playerStopAll();
+ showMessage(testId, str);
+ appendResultsToScreen(testId, "test finished");
+ computeAllResults();
break;
- case TEST1_MESSAGE: {
- String str = (String)msg.obj;
- if (str != null) {
- mTest1Result.setText(str);
- }
- }
- break;
- case TEST1_ENDED:
- showWait(false);
- computeTest1Results();
- break;
- case TEST_MESSAGE: {
- }
- break;
+ case TEST_ENDED_ERROR:
+ showWait(testId, false);
+ playerStopAll();
+ showMessage(testId, str);
+ computeAllResults();
default:
Log.e(TAG, String.format("Unknown message: %d", msg.what));
}
@@ -314,21 +826,32 @@
};
private class Results {
+ private int mBandCount;
private String mLabel;
public double[] mValuesLog;
- int[] mPointsPerBand = new int[mBands];
- double[] mAverageEnergyPerBand = new double[mBands];
- int[] mInBoundPointsPerBand = new int[mBands];
- public Results(String label) {
+ int[] mPointsPerBand; // = new int[mBands];
+ double[] mAverageEnergyPerBand;// = new double[mBands];
+ int[] mInBoundPointsPerBand;// = new int[mBands];
+ public Results(String label, int bandCount) {
mLabel = label;
+ mBandCount = bandCount;
+ mPointsPerBand = new int[mBandCount];
+ mAverageEnergyPerBand = new double[mBandCount];
+ mInBoundPointsPerBand = new int[mBandCount];
+ }
+ public void reset() {
+ for (int i = 0; i < mBandCount; i++) {
+ mPointsPerBand[i] = 0;
+ mAverageEnergyPerBand[i] = 0;
+ mInBoundPointsPerBand[i] = 0;
+ }
}
//append results
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(String.format("Channel %s\n", mLabel));
- sb.append("Level in Band 1 : " + (testLevel() ? "OK" :"Not Optimal") + "\n");
- for (int b = 0; b < mBands; b++) {
+ for (int b = 0; b < mBandCount; b++) {
double percent = 0;
if (mPointsPerBand[b] > 0) {
percent = 100.0 * (double) mInBoundPointsPerBand[b] / mPointsPerBand[b];
@@ -344,15 +867,8 @@
return sb.toString();
}
- public boolean testLevel() {
- if (mAverageEnergyPerBand[1] >= MIN_ENERGY_BAND_1) {
- return true;
- }
- return false;
- }
-
public boolean testInBand(int b) {
- if (b >= 0 && b < mBands && mPointsPerBand[b] > 0) {
+ if (b >= 0 && b < mBandCount && mPointsPerBand[b] > 0) {
if ((double) mInBoundPointsPerBand[b] / mPointsPerBand[b] >
MIN_FRACTION_POINTS_IN_BAND) {
return true;
@@ -362,10 +878,7 @@
}
public boolean testAll() {
- if (!testLevel()) {
- return false;
- }
- for (int b = 0; b < mBands; b++) {
+ for (int b = 0; b < mBandCount; b++) {
if (!testInBand(b)) {
return false;
}
@@ -375,98 +888,13 @@
}
- /**
- * compute test1 results
- */
- private void computeTest1Results() {
- Results resultsBuiltIn = new Results("BuiltIn");
- if (computeResultsForVector(mFreqAverageBuiltIn, resultsBuiltIn, bandSpecsArray)) {
- appendResultsToScreen(resultsBuiltIn.toString(), mTest1Result);
- recordTestResults(resultsBuiltIn);
- }
- if (mSupportsUnprocessed) { //test is mandatory
- appendResultsToScreen(getResources().getText(
- R.string.audio_frequency_unprocessed_defined).toString(), mTest1Result);
- if (resultsBuiltIn.testAll()) {
- //tst passed
- getPassButton().setEnabled(true);
- String strSuccess = getResources().getString(R.string.audio_general_test_passed);
- appendResultsToScreen(strSuccess, mTest1Result);
- } else {
- getPassButton().setEnabled(false);
- String strFailed = getResources().getString(R.string.audio_general_test_failed);
- appendResultsToScreen(strFailed, mTest1Result);
- }
- } else {
- //test optional
- appendResultsToScreen(getResources().getText(
- R.string.audio_frequency_unprocessed_not_defined).toString(), mTest1Result);
- getPassButton().setEnabled(true);
- }
- }
-
- private boolean computeResultsForVector(VectorAverage freqAverage, Results results,
- AudioBandSpecs[] bandSpecs) {
-
- int points = freqAverage.getSize();
- if (points > 0) {
- //compute vector in db
- double[] values = new double[points];
- freqAverage.getData(values, false);
- results.mValuesLog = new double[points];
- for (int i = 0; i < points; i++) {
- results.mValuesLog[i] = 20 * Math.log10(values[i]);
- }
-
- int currentBand = 0;
- for (int i = 0; i < points; i++) {
- double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
- if (freq > bandSpecs[currentBand].mFreqStop) {
- currentBand++;
- if (currentBand >= mBands)
- break;
- }
-
- if (freq >= bandSpecs[currentBand].mFreqStart) {
- results.mAverageEnergyPerBand[currentBand] += results.mValuesLog[i];
- results.mPointsPerBand[currentBand]++;
- }
- }
-
- for (int b = 0; b < mBands; b++) {
- if (results.mPointsPerBand[b] > 0) {
- results.mAverageEnergyPerBand[b] =
- results.mAverageEnergyPerBand[b] / results.mPointsPerBand[b];
- }
- }
-
- //set offset relative to band 1 level
- for (int b = 0; b < mBands; b++) {
- bandSpecs[b].setOffset(results.mAverageEnergyPerBand[1]);
- }
-
- //test points in band.
- currentBand = 0;
- for (int i = 0; i < points; i++) {
- double freq = (double)mSamplingRate * i / (double)mBlockSizeSamples;
- if (freq > bandSpecs[currentBand].mFreqStop) {
- currentBand++;
- if (currentBand >= mBands)
- break;
- }
-
- if (freq >= bandSpecs[currentBand].mFreqStart) {
- double value = results.mValuesLog[i];
- if (bandSpecs[currentBand].isInBounds(freq, value)) {
- results.mInBoundPointsPerBand[currentBand]++;
- }
- }
- }
- return true;
- } else {
- return false;
- }
- }
+// /**
+// * compute test results
+// */
+// private void computeTestResults(int testId) {
+// String testName = getTestString(testId);
+// appendResultsToScreen(testId, "test finished");
+// }
//append results
private void appendResultsToScreen(String str, TextView text) {
@@ -474,6 +902,24 @@
text.setText(currentText + "\n" + str);
}
+ private void appendResultsToScreen(int testId, String str) {
+ switch(testId) {
+ case TEST_TONE:
+ appendResultsToScreen(str, mResultTestTone);
+ showToneRMS();
+ break;
+ case TEST_NOISE:
+ appendResultsToScreen(str, mResultTestNoise);
+ break;
+ case TEST_USB_BACKGROUND:
+ appendResultsToScreen(str, mResultTestUsbBackground);
+ break;
+ case TEST_USB_NOISE:
+ appendResultsToScreen(str, mResultTestUsbNoise);
+ break;
+ }
+ }
+
/**
* Store test results in log
*/
@@ -615,6 +1061,12 @@
mRecorder.setPositionNotificationPeriod(mBlockSizeSamples / 2);
return true;
}
+ private void showToneRMS() {
+ String str = String.format("RMS: %.3f dBFS. Max RMS: %.3f dBFS",
+ 20 * Math.log10(mRMSTone),
+ 20 * Math.log10(mRMSMaxTone));
+ showMessage(TEST_TONE, str);
+ }
// ---------------------------------------------------------
// Implementation of AudioRecord.OnPeriodicNotificationListener
@@ -627,9 +1079,10 @@
//compute stuff.
int clipcount = 0;
- double sum = 0;
+// double sum = 0;
double maxabs = 0;
int i;
+ double rmsTempSum = 0;
for (i = 0; i < samplesNeeded; i++) {
double value = mAudioShortArray2[i] / MAX_VAL;
@@ -643,10 +1096,18 @@
clipcount++;
}
- sum += value * value;
+ rmsTempSum += value * value;
//fft stuff
mData.mData[i] = value;
}
+ double rms = Math.sqrt(rmsTempSum / samplesNeeded);
+
+ double alpha = 0.9;
+ double total_rms = rms * alpha + mRMS *(1-alpha);
+ mRMS = total_rms;
+ if (mRMS > mRMSMax) {
+ mRMSMax = mRMS;
+ }
//for the current frame, compute FFT and send to the viewer.
@@ -660,8 +1121,25 @@
halfMagnitude[i] = Math.sqrt(mC.mReal[i] * mC.mReal[i] + mC.mImag[i] * mC.mImag[i]);
}
- mFreqAverageMain.setData(halfMagnitude, false); //average all of them!
- mFreqAverageBuiltIn.setData(halfMagnitude, false);
+ switch(mCurrentTest) {
+ case TEST_TONE: {
+ mFreqAverageTone.setData(halfMagnitude, false);
+ //Update realtime info on screen
+ mRMSTone = mRMS;
+ mRMSMaxTone = mRMSMax;
+ showToneRMS();
+ }
+ break;
+ case TEST_NOISE:
+ mFreqAverageNoise.setData(halfMagnitude, false);
+ break;
+ case TEST_USB_BACKGROUND:
+ mFreqAverageUsbBackground.setData(halfMagnitude, false);
+ break;
+ case TEST_USB_NOISE:
+ mFreqAverageUsbNoise.setData(halfMagnitude, false);
+ break;
+ }
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 1349694..cf8ec89 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -97,8 +97,10 @@
}
} break;
case COMMAND_DISALLOW_KEYGUARD_UNREDACTED_NOTIFICATIONS: {
- mDpm.setKeyguardDisabledFeatures(mAdmin,
- DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS);
+ boolean enforced = intent.getBooleanExtra(EXTRA_ENFORCED, false);
+ mDpm.setKeyguardDisabledFeatures(mAdmin, enforced
+ ? DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS
+ : 0);
} break;
case COMMAND_SET_AUTO_TIME_REQUIRED: {
mDpm.setAutoTimeRequired(mAdmin,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
index 985cbf6..3cabbd3 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DisallowAppsControlActivity.java
@@ -67,11 +67,8 @@
@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 = getAdminComponent();
- if (mDpm.isAdminActive(adminComponent)) {
- allowAppsControl();
- }
+ // clear the restriction.
+ allowAppsControl();
super.finish();
}
@@ -120,9 +117,4 @@
setupCheckDisabledForceStopTest(adapter);
setupCheckDisabledAppStorageButtonsTest(adapter);
}
-
- @Override
- protected void clearRemainingState(final DialogTestListItem test) {
- allowAppsControl();
- }
}
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 5585cbc..27a140c 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/KeyguardDisabledFeaturesActivity.java
@@ -21,6 +21,8 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.hardware.fingerprint.FingerprintManager;
import android.os.Bundle;
import android.provider.Settings;
@@ -32,6 +34,8 @@
import com.android.cts.verifier.DialogTestListActivity;
import com.android.cts.verifier.R;
+import java.util.List;
+
public class KeyguardDisabledFeaturesActivity extends DialogTestListActivity {
protected DevicePolicyManager mDpm;
@@ -131,11 +135,20 @@
@Override
protected void setupTests(ArrayTestListAdapter adapter) {
- setupDisableTrustAgentsTest(adapter);
+ if (hasTrustAgents()) {
+ setupDisableTrustAgentsTest(adapter);
+ }
setupDisableUnredactedWorkNotification(adapter);
setupFingerprintTests(adapter);
}
+ private boolean hasTrustAgents() {
+ PackageManager packageManager = getPackageManager();
+ Intent intent = new Intent("android.service.trust.TrustAgentService");
+ List<ResolveInfo> resolveInfos = packageManager.queryIntentServices(intent, 0);
+ return resolveInfos.size() > 0;
+ }
+
@Override
protected void clearRemainingState(final DialogTestListItem test) {
super.clearRemainingState(test);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
index 9261284..5eaf862 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestActivity.java
@@ -266,7 +266,8 @@
return mTestId;
}
- public class DummyAccessibilityService extends AccessibilityService {
+ public static class DummyAccessibilityService extends AccessibilityService {
+
@Override
public void onAccessibilityEvent(AccessibilityEvent event) {
// Do nothing
@@ -278,7 +279,7 @@
}
}
- public class DummyInputMethod extends InputMethodService {
+ public static class DummyInputMethod extends InputMethodService {
@Override
public boolean onEvaluateFullscreenMode() {
return false;
@@ -306,4 +307,4 @@
this.command = command;
}
}
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
index 34c7cc4..c5b4a93 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/PolicyTransparencyTestListActivity.java
@@ -122,8 +122,8 @@
private void addTestsToAdapter(final ArrayTestListAdapter adapter) {
for (String restriction : UserRestrictions.getUserRestrictions()) {
final Intent intent = UserRestrictions.getUserRestrictionTestIntent(this, restriction);
- if (!UserRestrictions.isRestrictionValid(this, restriction) &&
- !mIsDeviceOwner && !UserRestrictions.isValidForPO(restriction)) {
+ if (!UserRestrictions.isRestrictionValid(this, restriction) ||
+ (!mIsDeviceOwner && !UserRestrictions.isValidForPO(restriction))) {
continue;
}
final String title = UserRestrictions.getRestrictionLabel(this, restriction);
@@ -135,8 +135,8 @@
for (Pair<Intent, Integer> policy : POLICIES) {
final Intent intent = policy.first;
String test = intent.getStringExtra(PolicyTransparencyTestActivity.EXTRA_TEST);
- if (!isPolicyValid(test) &&
- !mIsDeviceOwner && !ALSO_VALID_FOR_PO.contains(test)) {
+ if (!isPolicyValid(test) ||
+ (!mIsDeviceOwner && !ALSO_VALID_FOR_PO.contains(test))) {
continue;
}
final String title = getString(policy.second);
@@ -191,4 +191,4 @@
: CommandReceiverActivity.COMMAND_PROFILE_OWNER_CLEAR_POLICIES);
startActivity(intent);
}
-}
\ No newline at end of file
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
index 49c0c20..b7c10bb 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/VpnTestActivity.java
@@ -56,7 +56,7 @@
private DevicePolicyManager mDevicePolicyManager;
private UserManager mUserManager;
private static final String TAG = "DeviceOwnerPositiveTestActivity";
- private static final int REQUEST_VPN_CODE = 1;
+ private static final int REQUEST_VPN_CODE = 54321;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -81,12 +81,13 @@
@Override
protected void onActivityResult(int requestCode, int result, Intent data) {
- if (requestCode == REQUEST_VPN_CODE && result == RESULT_OK) {
+ if (requestCode == REQUEST_VPN_CODE) {
+ // We don't care about the result - ideally it should automatically cancel, but if
+ // some custom component doesn't do that, try to establish the connection anyway
+ // and see what happens.
establishVpn();
} else {
- // vpn connection canceled by user
- Log.w(TAG, "Test failed, canceled by user");
- populateInfo(R.string.device_owner_vpn_connection_canceled);
+ Log.w(TAG, "Unexpected request code: " + requestCode);
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
index 9a76f04..24d88b7 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/ConditionProviderVerifierActivity.java
@@ -447,6 +447,11 @@
// Now that it's subscribed, remove the rule and verify that it
// unsubscribes.
mNm.removeAutomaticZenRule(id);
+ try {
+ Thread.sleep(3000);
+ } catch (InterruptedException e) {
+ logFail("unexpected InterruptedException");
+ }
MockConditionProvider.probeSubscribe(mContext,
new MockConditionProvider.ParcelableListResultCatcher() {
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
index 802df56..6c294e5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/MockListener.java
@@ -17,6 +17,7 @@
import android.app.Activity;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -38,6 +39,9 @@
public class MockListener extends NotificationListenerService {
static final String TAG = "MockListener";
+ public static final ComponentName COMPONENT_NAME =
+ new ComponentName("com.android.cts.verifier", MockListener.class.getName());
+
static final String SERVICE_BASE = "android.service.notification.cts.";
static final String SERVICE_CHECK = SERVICE_BASE + "SERVICE_CHECK";
static final String SERVICE_POSTED = SERVICE_BASE + "SERVICE_POSTED";
@@ -47,13 +51,20 @@
static final String SERVICE_RESET = SERVICE_BASE + "SERVICE_RESET";
static final String SERVICE_CLEAR_ONE = SERVICE_BASE + "SERVICE_CLEAR_ONE";
static final String SERVICE_CLEAR_ALL = SERVICE_BASE + "SERVICE_CLEAR_ALL";
- public static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
- public static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+ static final String SERVICE_SNOOZE = SERVICE_BASE + "SERVICE_SNOOZE";
+ static final String SERVICE_HINTS = SERVICE_BASE + "SERVICE_HINTS";
+ static final String SERVICE_PROBE_HINTS = SERVICE_BASE + "SERVICE_PROBE_HINTS";
+ static final String SERVICE_ORDER = SERVICE_BASE + "SERVICE_ORDER";
+ static final String SERVICE_DND = SERVICE_BASE + "SERVICE_DND";
+ static final String SERVICE_SNOOZE_ONE = SERVICE_BASE + "SERVICE_SNOOZE_ONE";
+ static final String SERVICE_UNSNOOZE_ONE = SERVICE_BASE + "SERVICE_UNSNOOZE_ONE";
+ static final String SERVICE_SNOOZE_UNTIL = SERVICE_BASE + "SERVICE_SNOOZE_UNTIL";
static final String EXTRA_PAYLOAD = "PAYLOAD";
static final String EXTRA_INT = "INT";
static final String EXTRA_TAG = "TAG";
static final String EXTRA_CODE = "CODE";
+ static final String EXTRA_LONG = "LONG";
static final int RESULT_NO_SERVER = Activity.RESULT_FIRST_USER + 1;
@@ -67,6 +78,7 @@
public static final String JSON_AMBIENT = "ambient";
public static final String JSON_MATCHES_ZEN_FILTER = "matches_zen_filter";
public static final String JSON_REASON = "reason";
+ public static final String JSON_HINTS = "hints";
private ArrayList<String> mPosted = new ArrayList<String>();
private ArrayMap<String, JSONObject> mNotifications = new ArrayMap<>();
@@ -92,31 +104,24 @@
mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
+ final String action = intent.getAction();
+ final Bundle bundle = new Bundle();
+ Log.d(TAG, action);
if (SERVICE_CHECK.equals(action)) {
- Log.d(TAG, "SERVICE_CHECK");
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_POSTED.equals(action)) {
- Log.d(TAG, "SERVICE_POSTED");
- Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mPosted);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_DND.equals(action)) {
- Log.d(TAG, "SERVICE_DND");
- Bundle bundle = new Bundle();
bundle.putInt(EXTRA_INT, mDND);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_ORDER.equals(action)) {
- Log.d(TAG, "SERVICE_ORDER");
- Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mOrder);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_PAYLOADS.equals(action)) {
- Log.d(TAG, "SERVICE_PAYLOADS");
- Bundle bundle = new Bundle();
ArrayList<String> payloadData = new ArrayList<>(mNotifications.size());
for (JSONObject payload: mNotifications.values()) {
payloadData.add(payload.toString());
@@ -125,14 +130,10 @@
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_REMOVED.equals(action)) {
- Log.d(TAG, "SERVICE_REMOVED");
- Bundle bundle = new Bundle();
bundle.putStringArrayList(EXTRA_PAYLOAD, mRemoved);
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_REMOVED_REASON.equals(action)) {
- Log.d(TAG, "SERVICE_REMOVED_REASON");
- Bundle bundle = new Bundle();
ArrayList<String> payloadData = new ArrayList<>(mRemovedReason.size());
for (JSONObject payload: mRemovedReason.values()) {
payloadData.add(payload.toString());
@@ -141,7 +142,6 @@
setResultExtras(bundle);
setResultCode(Activity.RESULT_OK);
} else if (SERVICE_CLEAR_ONE.equals(action)) {
- Log.d(TAG, "SERVICE_CLEAR_ONE");
String tag = intent.getStringExtra(EXTRA_TAG);
String key = mNotificationKeys.get(tag);
if (key != null) {
@@ -150,11 +150,30 @@
Log.w(TAG, "Notification does not exist: " + tag);
}
} else if (SERVICE_CLEAR_ALL.equals(action)) {
- Log.d(TAG, "SERVICE_CLEAR_ALL");
MockListener.this.cancelAllNotifications();
} else if (SERVICE_RESET.equals(action)) {
- Log.d(TAG, "SERVICE_RESET");
resetData();
+ } else if (SERVICE_SNOOZE.equals(action)) {
+ MockListener.this.requestUnbind();
+ } else if (SERVICE_HINTS.equals(action)) {
+ MockListener.this.requestListenerHints(intent.getIntExtra(EXTRA_CODE, 0));
+ } else if (SERVICE_PROBE_HINTS.equals(action)) {
+ bundle.putInt(EXTRA_INT, MockListener.this.getCurrentListenerHints());
+ setResultExtras(bundle);
+ setResultCode(Activity.RESULT_OK);
+ } else if (SERVICE_SNOOZE_ONE.equals(action)) {
+ String tag = intent.getStringExtra(EXTRA_TAG);
+ String key = mNotificationKeys.get(tag);
+ MockListener.this.snoozeNotification(key);
+ } else if (SERVICE_UNSNOOZE_ONE.equals(action)) {
+ String tag = intent.getStringExtra(EXTRA_TAG);
+ String key = mNotificationKeys.get(tag);
+ MockListener.this.unsnoozeNotification(key);
+ } else if (SERVICE_SNOOZE_UNTIL.equals(action)) {
+ String tag = intent.getStringExtra(EXTRA_TAG);
+ String key = mNotificationKeys.get(tag);
+ MockListener.this.snoozeNotification(key,
+ intent.getLongExtra(EXTRA_LONG, (long) 0));
} else {
Log.w(TAG, "unknown action");
setResultCode(Activity.RESULT_CANCELED);
@@ -172,6 +191,12 @@
filter.addAction(SERVICE_CLEAR_ONE);
filter.addAction(SERVICE_CLEAR_ALL);
filter.addAction(SERVICE_RESET);
+ filter.addAction(SERVICE_SNOOZE);
+ filter.addAction(SERVICE_HINTS);
+ filter.addAction(SERVICE_PROBE_HINTS);
+ filter.addAction(SERVICE_SNOOZE_ONE);
+ filter.addAction(SERVICE_UNSNOOZE_ONE);
+ filter.addAction(SERVICE_SNOOZE_UNTIL);
registerReceiver(mReceiver, filter);
}
@@ -202,6 +227,7 @@
mNotifications.clear();
mRemoved.clear();
mOrder.clear();
+ mRemovedReason.clear();
}
@Override
@@ -307,10 +333,41 @@
requestStringListResult(context, SERVICE_REMOVED_REASON, catcher);
}
+ public static void probeListenerHints(Context context, IntegerResultCatcher catcher) {
+ requestIntegerResult(context, SERVICE_PROBE_HINTS, catcher);
+ }
+
+ public static void setHints(Context context, int hints) {
+ Intent broadcast = new Intent(SERVICE_HINTS);
+ broadcast.putExtra(EXTRA_CODE, hints);
+ context.sendBroadcast(broadcast);
+ }
+
+ public static void snooze(Context context) {
+ sendCommand(context, SERVICE_SNOOZE, null, 0);
+ }
+
public static void clearOne(Context context, String tag, int code) {
sendCommand(context, SERVICE_CLEAR_ONE, tag, code);
}
+ public static void snoozeOne(Context context, String tag) {
+ sendCommand(context, SERVICE_SNOOZE_ONE, tag, 0);
+ }
+
+ public static void unsnoozeOne(Context context, String tag) {
+ sendCommand(context, SERVICE_UNSNOOZE_ONE, tag, 0);
+ }
+
+ public static void snoozeOneUntil(Context context, String tag, long until) {
+ Intent broadcast = new Intent(SERVICE_SNOOZE_UNTIL);
+ if (tag != null) {
+ broadcast.putExtra(EXTRA_TAG, tag);
+ broadcast.putExtra(EXTRA_LONG, until);
+ }
+ context.sendBroadcast(broadcast);
+ }
+
public static void clearAll(Context context) {
sendCommand(context, SERVICE_CLEAR_ALL, null, 0);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
index 6bf623a..fe23fe0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/notifications/NotificationListenerVerifierActivity.java
@@ -79,6 +79,13 @@
tests.add(new DismissOneTest());
tests.add(new DismissOneWithReasonTest());
tests.add(new DismissAllTest());
+ tests.add(new SnoozeNotificationTest());
+ tests.add(new UnsnoozeNotificationTest());
+ tests.add(new SnoozeNotificationForTimeTest());
+ tests.add(new EnableHintsTest());
+ tests.add(new SnoozeTest());
+ tests.add(new UnsnoozeTest());
+ tests.add(new EnableHintsTest());
tests.add(new IsDisabledTest());
tests.add(new ServiceStoppedTest());
tests.add(new NotificationNotReceivedTest());
@@ -350,7 +357,6 @@
} catch (JSONException e) {
e.printStackTrace();
}
-
}
status = pass ? PASS : FAIL;
next();
@@ -427,6 +433,12 @@
}
@Override
+ void setUp(){
+ MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+ delay();
+ }
+
+ @Override
void test() {
String listeners = Secure.getString(getContentResolver(),
ENABLED_NOTIFICATION_LISTENERS);
@@ -461,7 +473,11 @@
logFail();
status = FAIL;
} else {
- status = PASS;
+ if (mNm.getEffectsSuppressor() == null) {
+ status = PASS;
+ } else {
+ status = FAIL;
+ }
}
next();
}
@@ -515,4 +531,362 @@
delay();
}
}
+
+ private class SnoozeTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_snooze);
+
+ }
+
+ @Override
+ void setUp() {
+ status = READY;
+ MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (status == READY) {
+ MockListener.snooze(mContext);
+ status = RETEST;
+ } else {
+ MockListener.probeListenerStatus(mContext,
+ new MockListener.StatusCatcher() {
+ @Override
+ public void accept(int result) {
+ if (result == Activity.RESULT_OK) {
+ logFail();
+ status = FAIL;
+ } else {
+ if (mNm.getEffectsSuppressor() == null) {
+ status = PASS;
+ } else {
+ logFail();
+ status = RETEST;
+ delay();
+ }
+ }
+ next();
+ }
+ });
+ }
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ delay();
+ }
+ }
+
+ private class UnsnoozeTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_unsnooze);
+
+ }
+
+ @Override
+ void setUp() {
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (status == READY) {
+ MockListener.requestRebind(MockListener.COMPONENT_NAME);
+ status = RETEST;
+ } else {
+ MockListener.probeListenerStatus(mContext,
+ new MockListener.StatusCatcher() {
+ @Override
+ public void accept(int result) {
+ if (result == Activity.RESULT_OK) {
+ status = PASS;
+ next();
+ } else {
+ logFail();
+ status = RETEST;
+ delay();
+ }
+ }
+ });
+ }
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ delay();
+ }
+ }
+
+ private class EnableHintsTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_hints);
+
+ }
+
+ @Override
+ void setUp() {
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (status == READY) {
+ MockListener.setHints(mContext, MockListener.HINT_HOST_DISABLE_CALL_EFFECTS);
+ status = RETEST;
+ } else {
+ MockListener.probeListenerHints(mContext,
+ new MockListener.IntegerResultCatcher() {
+ @Override
+ public void accept(int result) {
+ if (result == MockListener.HINT_HOST_DISABLE_CALL_EFFECTS) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ }
+ delay(); // in case the catcher never returns
+ }
+
+ @Override
+ void tearDown() {
+ delay();
+ }
+ }
+
+ private class SnoozeNotificationTest extends InteractiveTestCase {
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_snooze_one);
+ }
+
+ @Override
+ void setUp() {
+ sendNotifications();
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ if (status == READY) {
+ MockListener.snoozeOne(mContext, mTag1);
+ status = RETEST;
+ } else {
+ MockListener.probeListenerRemoved(mContext,
+ new MockListener.StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result != null && result.size() != 0
+ && result.contains(mTag1)
+ && !result.contains(mTag2)
+ && !result.contains(mTag3)) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ }
+ delay();
+ }
+
+ @Override
+ void tearDown() {
+ mNm.cancel(mTag1, mId1);
+ mNm.cancel(mTag2, mId2);
+ mNm.cancel(mTag2, mId3);
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ private class UnsnoozeNotificationTest extends InteractiveTestCase {
+ final static int READY_TO_SNOOZE = 0;
+ final static int SNOOZED = 1;
+ final static int READY_TO_UNSNOOZE = 2;
+ final static int UNSNOOZED = 3;
+ int state = -1;
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_unsnooze_one);
+ }
+
+ @Override
+ void setUp() {
+ sendNotifications();
+ status = READY;
+ delay();
+ }
+
+ @Override
+ void test() {
+ status = RETEST;
+
+ if (state == READY_TO_SNOOZE) {
+ MockListener.snoozeOne(mContext, mTag1);
+ state = SNOOZED;
+ } else if (state == SNOOZED) {
+ MockListener.probeListenerRemovedWithReason(mContext,
+ new StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result == null || result.size() == 0) {
+ status = FAIL;
+ return;
+ }
+ boolean pass = true;
+ for (String payloadData : result) {
+ JSONObject payload = null;
+ try {
+ payload = new JSONObject(payloadData);
+ pass &= checkEquals(mTag1,
+ payload.getString(JSON_TAG),
+ "data dismissal test: notification tag (%s, %s)");
+ pass &= checkEquals(MockListener.REASON_SNOOZED,
+ payload.getInt(JSON_TAG),
+ "data dismissal test: reason (%d, %d)");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ if (!pass) {
+ logFail();
+ status = FAIL;
+ next();
+ return;
+ } else {
+ state = READY_TO_UNSNOOZE;
+ }
+ }
+ });
+ } else if (state == READY_TO_UNSNOOZE) {
+ MockListener.unsnoozeOne(mContext, mTag1);
+ state = UNSNOOZED;
+ } else {
+ MockListener.probeListenerPosted(mContext,
+ new MockListener.StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result != null && result.size() != 0
+ && result.contains(mTag1)) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ }
+ }
+
+ @Override
+ void tearDown() {
+ mNm.cancelAll();
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
+
+ private class SnoozeNotificationForTimeTest extends InteractiveTestCase {
+ final static int READY_TO_SNOOZE = 0;
+ final static int SNOOZED = 1;
+ final static int READY_TO_CHECK_FOR_UNSNOOZE = 2;
+ int state = -1;
+ long snoozeTime = 3000;
+ @Override
+ View inflate(ViewGroup parent) {
+ return createAutoItem(parent, R.string.nls_snooze_one_time);
+ }
+
+ @Override
+ void setUp() {
+ sendNotifications();
+ status = READY;
+ state = READY_TO_SNOOZE;
+ delay();
+ }
+
+ @Override
+ void test() {
+ status = RETEST;
+ if (state == READY_TO_SNOOZE) {
+ MockListener.snoozeOneUntil(mContext, mTag1,
+ System.currentTimeMillis() + snoozeTime);
+ state = SNOOZED;
+ } else if (state == SNOOZED){
+ MockListener.probeListenerRemovedWithReason(mContext,
+ new StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result == null || result.size() == 0) {
+ status = FAIL;
+ return;
+ }
+ boolean pass = true;
+ for (String payloadData : result) {
+ JSONObject payload = null;
+ try {
+ payload = new JSONObject(payloadData);
+ pass &= checkEquals(mTag1,
+ payload.getString(JSON_TAG),
+ "data dismissal test: notification tag (%s, %s)");
+ pass &= checkEquals(MockListener.REASON_SNOOZED,
+ payload.getInt(JSON_TAG),
+ "data dismissal test: reason (%d, %d)");
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+ if (!pass) {
+ logFail();
+ status = FAIL;
+ next();
+ return;
+ } else {
+ state = READY_TO_CHECK_FOR_UNSNOOZE;
+ }
+ }
+ });
+ } else {
+ MockListener.probeListenerPosted(mContext,
+ new MockListener.StringListResultCatcher() {
+ @Override
+ public void accept(List<String> result) {
+ if (result != null && result.size() != 0
+ && result.contains(mTag1)) {
+ status = PASS;
+ } else {
+ logFail();
+ status = FAIL;
+ }
+ next();
+ }
+ });
+ }
+ delay();
+ }
+
+ @Override
+ void tearDown() {
+ mNm.cancelAll();
+ MockListener.resetListenerData(mContext);
+ delay();
+ }
+ }
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java
new file mode 100644
index 0000000..5be1792
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/Util.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.usb;
+
+import android.support.annotation.NonNull;
+import android.util.Log;
+
+/**
+ * Utilities for the USB CTS verifier tests.
+ */
+public class Util {
+ private static final String LOG_TAG = Util.class.getSimpleName();
+
+ /**
+ * Run a {@link Invokable} and expect a {@link Throwable}.
+ *
+ * @param r The {@link Invokable} to run
+ * @param expectedClass The expected {@link Throwable} type
+ */
+ public static void runAndAssertException(@NonNull Invokable r,
+ @NonNull Class<? extends Throwable> expectedClass) throws Throwable {
+ try {
+ r.run();
+ } catch (Throwable e) {
+ if (e.getClass().isAssignableFrom(expectedClass)) {
+ return;
+ } else {
+ Log.e(LOG_TAG, "Expected: " + expectedClass.getName() + ", got: "
+ + e.getClass().getName());
+ throw e;
+ }
+ }
+
+ throw new AssertionError("No throwable thrown");
+ }
+
+
+ /**
+ * A {@link Runnable} that can throw an {@link Throwable}.
+ */
+ public interface Invokable {
+ /**
+ * Run the code that might cause an exception.
+ */
+ void run() throws Throwable;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java
new file mode 100644
index 0000000..f5e0fef
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/AccessoryAttachmentHandler.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.usb.accessory;
+
+import android.app.Activity;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+
+/**
+ * Utility to receive callbacks when an USB accessory is attached.
+ */
+public class AccessoryAttachmentHandler extends Activity {
+ private static final ArrayList<AccessoryAttachmentObserver> sObservers = new ArrayList<>();
+
+ /**
+ * Register an observer to be called when an USB accessory connects.
+ *
+ * @param observer The observer that should be called when an USB accessory connects.
+ */
+ static void addObserver(@NonNull AccessoryAttachmentObserver observer) {
+ synchronized (sObservers) {
+ sObservers.add(observer);
+ }
+ }
+
+ /**
+ * Remove an observer that was added in {@link #addObserver}.
+ *
+ * @param observer The observer to remove
+ */
+ static void removeObserver(@NonNull AccessoryAttachmentObserver observer) {
+ synchronized (sObservers) {
+ sObservers.remove(observer);
+ }
+ }
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ UsbAccessory accessory = getIntent().getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+
+ synchronized (sObservers) {
+ ArrayList<AccessoryAttachmentObserver> observers =
+ (ArrayList<AccessoryAttachmentObserver>) sObservers.clone();
+
+ for (AccessoryAttachmentObserver observer : observers) {
+ observer.onAttached(accessory);
+ }
+ }
+
+ finish();
+ }
+
+ /**
+ * Callback when an accessory is attached
+ */
+ interface AccessoryAttachmentObserver {
+ void onAttached(UsbAccessory accessory);
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
index 2e11f98..8ac009b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/accessory/UsbAccessoryTestActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2011 The Android Open Source Project
+ * Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,460 +16,231 @@
package com.android.cts.verifier.usb.accessory;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-import com.android.cts.verifier.TestResult;
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
-import android.app.AlertDialog;
-import android.app.Dialog;
-import android.app.PendingIntent;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.DialogInterface;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager;
-import android.content.res.Configuration;
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
import android.hardware.usb.UsbAccessory;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
import android.os.ParcelFileDescriptor;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
-import android.widget.ArrayAdapter;
-import android.widget.ListView;
-import android.widget.Toast;
+import android.widget.ProgressBar;
+import android.widget.TextView;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileOutputStream;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.util.Arrays;
+import java.util.Random;
/**
- * Test for USB accessories. The test activity interacts with a cts-usb-accessory program that
- * acts as an accessory by exchanging a series of messages.
+ * Guide the user to run test for the USB accessory interface.
*/
-public class UsbAccessoryTestActivity extends PassFailButtons.Activity {
+public class UsbAccessoryTestActivity extends PassFailButtons.Activity implements
+ AccessoryAttachmentHandler.AccessoryAttachmentObserver {
+ private static final String LOG_TAG = UsbAccessoryTestActivity.class.getSimpleName();
+ private static final int MAX_BUFFER_SIZE = 16384;
- private static final String TAG = "UsbAccessoryTest";
-
- private static final int FILE_DESCRIPTOR_PROBLEM_DIALOG_ID = 1;
- private static final int STATE_START = 0;
- private static final int STATE_CONNECTED = 1;
- private static final int STATE_WAITING_FOR_RECONNECT = 2;
- private static final int STATE_RECONNECTED = 3;
- private static final int STATE_PASSED = 4;
-
- private static final String ACTION_USB_PERMISSION =
- "com.android.cts.verifier.usb.USB_PERMISSION";
-
- private ArrayAdapter<String> mReceivedMessagesAdapter;
- private ArrayAdapter<String> mSentMessagesAdapter;
- private MessageHandler mHandler;
- private Handler mMainHandler;
-
- private UsbManager mUsbManager;
- private PendingIntent mPermissionIntent;
- private boolean mPermissionRequestPending;
- private UsbReceiver mUsbReceiver;
- private int mState = STATE_START;
- private AlertDialog mDisconnectDialog;
- private AlertDialog mConnectDialog;
-
- private UsbAccessory mAccessory;
- private ParcelFileDescriptor mFileDescriptor;
-
- private Runnable mTimeoutRunnable = new Runnable() {
- @Override
- public void run() {
- Toast.makeText(UsbAccessoryTestActivity.this,
- R.string.usb_reconnect_timeout, Toast.LENGTH_SHORT).show();
- TestResult.setFailedResult(UsbAccessoryTestActivity.this, getTestId(), getTestDetails());
- }
- };
+ private TextView mStatus;
+ private ProgressBar mProgress;
@Override
- protected void onCreate(Bundle savedInstanceState) {
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Log.d(TAG, "onCreate");
- // Test success only works properly if launched from TestListActivity
- String action = getIntent().getAction();
- if (ACTION_USB_PERMISSION.equals(action)
- || UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(action)) {
- finish();
- return;
- }
setContentView(R.layout.usb_main);
- setInfoResources(R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
- setPassFailButtonClickListeners();
+ setInfoResources(
+ R.string.usb_accessory_test, R.string.usb_accessory_test_info, -1);
- // Don't allow a test pass until the accessory and the Android device exchange messages...
+ mStatus = (TextView) findViewById(R.id.status);
+ mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+ mStatus.setText(R.string.usb_accessory_test_step1);
getPassButton().setEnabled(false);
- if (!hasUsbAccessorySupport()) {
- showNoUsbAccessoryDialog();
- }
-
- mReceivedMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
- mSentMessagesAdapter = new ArrayAdapter<String>(this, R.layout.usb_message_row);
- mHandler = new MessageHandler();
-
- mUsbManager = (UsbManager) getSystemService(USB_SERVICE);
- mPermissionIntent = PendingIntent.getBroadcast(this, 0,
- new Intent(ACTION_USB_PERMISSION), 0);
-
- mUsbReceiver = new UsbReceiver();
- IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
- filter.addAction(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
- registerReceiver(mUsbReceiver, filter);
-
- setupListViews();
-
- AlertDialog.Builder builder = new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.usb_reconnect_title)
- .setCancelable(false)
- .setNegativeButton(R.string.usb_reconnect_abort,
- new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- setTestResultAndFinish(false);
- }
- });
- mConnectDialog = builder
- .setMessage(R.string.usb_connect_message)
- .create();
- mDisconnectDialog = builder
- .setMessage(R.string.usb_disconnect_message)
- .create();
-
- mMainHandler = new Handler(Looper.getMainLooper());
- }
-
- private boolean hasUsbAccessorySupport() {
- return getPackageManager().hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
- }
-
- private void showNoUsbAccessoryDialog() {
- new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.usb_not_available_title)
- .setMessage(R.string.usb_not_available_message)
- .setCancelable(false)
- .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int which) {
- finish();
- }
- })
- .show();
- }
-
- private void setupListViews() {
- ListView sentMessages = (ListView) findViewById(R.id.usb_sent_messages);
- ListView receivedMessages = (ListView) findViewById(R.id.usb_received_messages);
-
- View emptySentView = findViewById(R.id.usb_empty_sent_messages);
- View emptyReceivedView = findViewById(R.id.usb_empty_received_messages);
- sentMessages.setEmptyView(emptySentView);
- receivedMessages.setEmptyView(emptyReceivedView);
-
- receivedMessages.setAdapter(mReceivedMessagesAdapter);
- sentMessages.setAdapter(mSentMessagesAdapter);
- }
-
- class UsbReceiver extends BroadcastReceiver {
- @Override
- public void onReceive(Context context, Intent intent) {
- Log.d(TAG, "Received broadcast: intent=" + intent);
- if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
- if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
- UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
- openAccessory(accessory);
- } else {
- Log.i(TAG, "Permission denied...");
- }
- mPermissionRequestPending = false;
- } else if (mState == STATE_WAITING_FOR_RECONNECT &&
- UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(intent.getAction())) {
- UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
- if (accessory.equals(mAccessory)) {
- closeAccessory();
- mDisconnectDialog.dismiss();
- mConnectDialog.show();
- mMainHandler.postDelayed(mTimeoutRunnable, 10000 /* 10 seconds */);
- }
- }
- }
- }
-
- public void onNewIntent(Intent intent) {
- super.onNewIntent(intent);
- Log.d(TAG, "onNewIntent: state=" + mState + ", intent=" + intent);
- if (UsbManager.ACTION_USB_ACCESSORY_ATTACHED.equals(intent.getAction())) {
- UsbAccessory accessory = intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
- openAccessory(accessory);
- }
- }
-
- private void openAccessory(UsbAccessory accessory) {
- mAccessory = accessory;
- mFileDescriptor = mUsbManager.openAccessory(accessory);
- if (mState == STATE_START) {
- setState(STATE_CONNECTED);
- } else if (mState == STATE_WAITING_FOR_RECONNECT) {
- setState(STATE_RECONNECTED);
- mConnectDialog.dismiss();
- }
- if (mFileDescriptor != null) {
- FileDescriptor fileDescriptor = mFileDescriptor.getFileDescriptor();
- FileInputStream inputStream = new FileInputStream(fileDescriptor);
- FileOutputStream outputStream = new FileOutputStream(fileDescriptor);
- new MessageThread(inputStream, outputStream, mHandler).start();
- } else {
- showDialog(FILE_DESCRIPTOR_PROBLEM_DIALOG_ID);
- }
- }
-
- private void closeAccessory() {
- mAccessory = null;
- if (mFileDescriptor != null) {
- try {
- mFileDescriptor.close();
- } catch (IOException e) {
- Log.e(TAG, "Exception while closing file descriptor", e);
- } finally {
- mFileDescriptor = null;
- }
- }
- }
-
- static class MessageThread extends Thread {
-
- private final InputStream mInputStream;
-
- private final OutputStream mOutputStream;
-
- private final MessageHandler mHandler;
-
- private int mNextMessageNumber = 0;
-
- MessageThread(InputStream inputStream, OutputStream outputStream, MessageHandler handler) {
- this.mInputStream = inputStream;
- this.mOutputStream = outputStream;
- this.mHandler = handler;
- }
-
- @Override
- public void run() {
- mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_STARTING);
-
- try {
- // Wait a bit or else the messages can appear to quick and be confusing...
- Thread.sleep(2000);
- sendMessage();
-
- // Wait for response and send message acks...
- int numRead = 0;
- byte[] buffer = new byte[16384];
- boolean done = false;
- while (numRead >= 0 && !done) {
- numRead = mInputStream.read(buffer);
- if (numRead > 0) {
- done = handleReceivedMessage(buffer, numRead);
- }
- }
- } catch (IOException e) {
- Log.e(TAG, "Exception while reading from input stream", e);
- mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
- } catch (InterruptedException e) {
- Log.e(TAG, "Exception while reading from input stream", e);
- mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_EXCEPTION);
- }
- mHandler.sendEmptyMessage(MessageHandler.MESSAGE_THREAD_ENDING);
- }
-
- private boolean handleReceivedMessage(byte[] buffer, int numRead) throws IOException {
- // TODO: Check the contents of the message?
- String text = new String(buffer, 0, numRead).trim();
- mHandler.sendReceivedMessage(text);
-
- // Send back a response..
- if (mNextMessageNumber <= 10) {
- sendMessage();
- return false;
- } else {
- mHandler.sendEmptyMessage(MessageHandler.STAGE_PASSED);
- return true;
- }
- }
-
- private void sendMessage() throws IOException {
- String text = "Message from Android device #" + mNextMessageNumber++;
- mOutputStream.write(text.getBytes());
- mHandler.sendSentMessage(text);
- }
- }
-
- class MessageHandler extends Handler {
-
- static final int RECEIVED_MESSAGE = 1;
-
- static final int SENT_MESSAGE = 2;
-
- static final int MESSAGE_THREAD_STARTING = 3;
-
- static final int MESSAGE_THREAD_EXCEPTION = 4;
-
- static final int MESSAGE_THREAD_ENDING = 5;
-
- static final int STAGE_PASSED = 6;
-
- @Override
- public void handleMessage(Message msg) {
- super.handleMessage(msg);
- switch (msg.what) {
- case RECEIVED_MESSAGE:
- mReceivedMessagesAdapter.add((String) msg.obj);
- break;
-
- case SENT_MESSAGE:
- mSentMessagesAdapter.add((String) msg.obj);
- break;
-
- case MESSAGE_THREAD_STARTING:
- showToast(R.string.usb_message_thread_started);
- break;
-
- case MESSAGE_THREAD_EXCEPTION:
- showToast(R.string.usb_message_thread_exception);
- break;
-
- case MESSAGE_THREAD_ENDING:
- showToast(R.string.usb_message_thread_ended);
- break;
-
- case STAGE_PASSED:
- if (mState == STATE_RECONNECTED) {
- showToast(R.string.usb_test_passed);
- getPassButton().setEnabled(true);
- setState(STATE_PASSED);
- mMainHandler.removeCallbacks(mTimeoutRunnable);
- } else if (mState == STATE_CONNECTED) {
- mDisconnectDialog.show();
- setState(STATE_WAITING_FOR_RECONNECT);
- }
- break;
-
- default:
- throw new IllegalArgumentException("Bad message type: " + msg.what);
- }
- }
-
- private void showToast(int messageId) {
- Toast.makeText(UsbAccessoryTestActivity.this, messageId, Toast.LENGTH_SHORT).show();
- }
-
- void sendReceivedMessage(String text) {
- Message message = Message.obtain(this, RECEIVED_MESSAGE);
- message.obj = text;
- sendMessage(message);
- }
-
- void sendSentMessage(String text) {
- Message message = Message.obtain(this, SENT_MESSAGE);
- message.obj = text;
- sendMessage(message);
- }
+ AccessoryAttachmentHandler.addObserver(this);
}
@Override
- protected void onResume() {
- super.onResume();
- Log.d(TAG, "onResume: state=" + stateToString(mState));
- if (mState == STATE_START) {
- UsbAccessory[] accessories = mUsbManager.getAccessoryList();
- UsbAccessory accessory = accessories != null && accessories.length > 0
- ? accessories[0]
- : null;
- if (accessory != null) {
- if (mUsbManager.hasPermission(accessory)) {
- openAccessory(accessory);
- } else {
- if (!mPermissionRequestPending) {
- mUsbManager.requestPermission(accessory, mPermissionIntent);
- mPermissionRequestPending = true;
- }
+ public void onAttached(UsbAccessory accessory) {
+ mStatus.setText(R.string.usb_accessory_test_step2);
+ mProgress.setVisibility(View.VISIBLE);
+
+ AccessoryAttachmentHandler.removeObserver(this);
+
+ UsbManager usbManager = getSystemService(UsbManager.class);
+
+ try {
+ assertEquals("Android device running CTS verifier", accessory.getDescription());
+ assertEquals("Android", accessory.getManufacturer());
+ assertEquals("Android device", accessory.getModel());
+ assertEquals("0", accessory.getSerial());
+ assertEquals("https://source.android.com/compatibility/cts/verifier.html",
+ accessory.getUri());
+ assertEquals("1", accessory.getVersion());
+
+ assertTrue(Arrays.asList(usbManager.getAccessoryList()).contains(accessory));
+
+ runAndAssertException(() -> usbManager.openAccessory(null), NullPointerException.class);
+
+ ParcelFileDescriptor accessoryFd = usbManager.openAccessory(accessory);
+ assertNotNull(accessoryFd);
+
+ try (InputStream is = new ParcelFileDescriptor.AutoCloseInputStream(accessoryFd)) {
+ try (OutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(
+ accessoryFd)) {
+ byte[] origBuffer32 = new byte[32];
+ (new Random()).nextBytes(origBuffer32);
+
+ byte[] origBufferMax = new byte[MAX_BUFFER_SIZE];
+ (new Random()).nextBytes(origBufferMax);
+
+ byte[] bufferMax = new byte[MAX_BUFFER_SIZE];
+ byte[] buffer32 = new byte[32];
+ byte[] buffer16 = new byte[16];
+
+ // Echo a transfer
+ nextTest(is, os, "echo 32 bytes");
+
+ os.write(origBuffer32);
+
+ int numRead = is.read(buffer32);
+ assertEquals(32, numRead);
+ assertArrayEquals(origBuffer32, buffer32);
+
+ // Receive less data than available
+ nextTest(is, os, "echo 32 bytes");
+
+ os.write(origBuffer32);
+
+ numRead = is.read(buffer16);
+ assertEquals(16, numRead);
+ assertArrayEquals(Arrays.copyOf(origBuffer32, 16), buffer16);
+
+ // If a transfer was only partially read, the rest of the transfer is lost.
+ // We cannot read the second part, hence proceed to the next test.
+
+ // Send two transfers in a row
+ nextTest(is, os, "echo two 16 byte transfers as one");
+
+ os.write(Arrays.copyOf(origBuffer32, 16));
+ os.write(Arrays.copyOfRange(origBuffer32, 16, 32));
+
+ numRead = is.read(buffer32);
+ assertEquals(32, numRead);
+ assertArrayEquals(origBuffer32, buffer32);
+
+ // Receive two transfers in a row into a buffer that is bigger than the transfer
+ nextTest(is, os, "echo 32 bytes as two 16 byte transfers");
+
+ os.write(origBuffer32);
+
+ // Even though the buffer would hold 32 bytes the input stream will read the
+ // transfers individually
+ numRead = is.read(buffer32);
+ assertEquals(16, numRead);
+ assertArrayEquals(Arrays.copyOf(origBuffer32, 16),
+ Arrays.copyOf(buffer32, 16));
+
+ numRead = is.read(buffer32);
+ assertEquals(16, numRead);
+ assertArrayEquals(Arrays.copyOfRange(origBuffer32, 16, 32),
+ Arrays.copyOf(buffer32, 16));
+
+ // Echo a buffer with the maximum size
+ nextTest(is, os, "echo max bytes");
+
+ os.write(origBufferMax);
+
+ numRead = is.read(bufferMax);
+ assertEquals(MAX_BUFFER_SIZE, numRead);
+ assertArrayEquals(origBufferMax, bufferMax);
+
+ // Echo a buffer with twice the maximum size
+ nextTest(is, os, "echo max*2 bytes");
+
+ byte[] oversizeBuffer = new byte[MAX_BUFFER_SIZE * 2];
+ System.arraycopy(origBufferMax, 0, oversizeBuffer, 0, MAX_BUFFER_SIZE);
+ System.arraycopy(origBufferMax, 0, oversizeBuffer, MAX_BUFFER_SIZE,
+ MAX_BUFFER_SIZE);
+ os.write(oversizeBuffer);
+
+ // The other side can not write more than the maximum size at once, hence we get
+ // two transfers in return
+ numRead = is.read(bufferMax);
+ assertEquals(MAX_BUFFER_SIZE, numRead);
+ assertArrayEquals(origBufferMax, bufferMax);
+
+ numRead = is.read(bufferMax);
+ assertEquals(MAX_BUFFER_SIZE, numRead);
+ assertArrayEquals(origBufferMax, bufferMax);
+
+ nextTest(is, os, "done");
}
}
+
+ accessoryFd.close();
+
+ setTestResultAndFinish(true);
+ } catch (Throwable t) {
+ fail(null, t);
}
}
- @Override
- protected void onPause() {
- super.onPause();
- Log.d(TAG, "onPause: state=" + stateToString(mState));
- }
+ /**
+ * Signal to the companion device that we want to switch to the next test.
+ *
+ * @param is The input stream from the companion device
+ * @param os The output stream from the companion device
+ * @param testName The name of the new test
+ */
+ private boolean nextTest(@NonNull InputStream is, @NonNull OutputStream os,
+ @NonNull String testName) throws IOException {
+ Log.i(LOG_TAG, "Init new test " + testName);
- @Override
- protected void onStop() {
- super.onStop();
- Log.d(TAG, "onStop: state=" + stateToString(mState));
- closeAccessory();
- }
+ ByteBuffer nameBuffer = Charset.forName("UTF-8").encode(CharBuffer.wrap(testName));
+ byte[] sizeBuffer = {(byte) nameBuffer.limit()};
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
- setContentView(R.layout.usb_main);
- setupListViews();
- }
+ os.write(sizeBuffer);
+ os.write(Arrays.copyOf(nameBuffer.array(), nameBuffer.limit()));
- @Override
- public Dialog onCreateDialog(int id, Bundle args) {
- switch (id) {
- case FILE_DESCRIPTOR_PROBLEM_DIALOG_ID:
- return new AlertDialog.Builder(this)
- .setIcon(android.R.drawable.ic_dialog_alert)
- .setTitle(R.string.usb_accessory_test)
- .setMessage(R.string.usb_file_descriptor_error)
- .create();
-
- default:
- return super.onCreateDialog(id, args);
+ int ret = is.read();
+ if (ret <= 0) {
+ Log.i(LOG_TAG, "Last test failed " + ret);
+ return false;
}
+
+ os.write(0);
+
+ Log.i(LOG_TAG, "Running " + testName);
+
+ return true;
}
@Override
protected void onDestroy() {
+ AccessoryAttachmentHandler.removeObserver(this);
+
super.onDestroy();
- Log.d(TAG, "onDestroy");
- if (mUsbReceiver != null) {
- unregisterReceiver(mUsbReceiver);
- }
}
- private void setState(int newState) {
- Log.d(TAG, "Transition: " + stateToString(mState) + " -> " + stateToString(newState));
- mState = newState;
+ /**
+ * Indicate that the test failed.
+ */
+ private void fail(@Nullable String s, @Nullable Throwable e) {
+ Log.e(LOG_TAG, s, e);
+ setTestResultAndFinish(false);
}
-
-
- private static String stateToString(int state) {
- switch (state) {
- case STATE_START: return "START";
- case STATE_CONNECTED: return "CONNECTED";
- case STATE_WAITING_FOR_RECONNECT: return "WAITING_FOR_RECONNECT";
- case STATE_RECONNECTED: return "RECONNECTED";
- case STATE_PASSED: return "PASSED";
- default: return "UNKNOWN";
- }
- }
-
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index d762096..6a1a16a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -16,6 +16,8 @@
package com.android.cts.verifier.usb.device;
+import static com.android.cts.verifier.usb.Util.runAndAssertException;
+
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -45,6 +47,9 @@
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
import android.widget.Toast;
import com.android.cts.verifier.PassFailButtons;
@@ -72,37 +77,35 @@
private static final int MAX_BUFFER_SIZE = 16384;
private UsbManager mUsbManager;
- private final BroadcastReceiver mUsbDeviceConnectionReceiver;
+ private BroadcastReceiver mUsbDeviceConnectionReceiver;
private Thread mTestThread;
+ private TextView mStatus;
+ private ProgressBar mProgress;
private static long now() {
return System.nanoTime() / 1000000;
}
- /**
- * Run a {@link Invokable} and expect a {@link Throwable} of a certain type.
- *
- * @param r The {@link Invokable} to run
- * @param expectedClass The expected {@link Throwable} type
- */
- private static void assertException(@NonNull Invokable r,
- @NonNull Class<? extends Throwable> expectedClass) throws Throwable {
- try {
- r.run();
- } catch (Throwable e) {
- if (e.getClass().isAssignableFrom(expectedClass)) {
- return;
- } else {
- Log.e(LOG_TAG, "Expected: " + expectedClass.getName() + ", got: "
- + e.getClass().getName());
- throw e;
- }
- }
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
- throw new AssertionError("No throwable thrown");
- }
+ setContentView(R.layout.usb_main);
+ setInfoResources(R.string.usb_device_test, R.string.usb_device_test_info, -1);
- public UsbDeviceTestActivity() {
+ mStatus = (TextView) findViewById(R.id.status);
+ mProgress = (ProgressBar) findViewById(R.id.progress_bar);
+
+ mUsbManager = getSystemService(UsbManager.class);
+
+ getPassButton().setEnabled(false);
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USB_PERMISSION);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+ mStatus.setText(R.string.usb_device_test_step1);
+
mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -111,6 +114,10 @@
switch (intent.getAction()) {
case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+ if (!AoapInterface.isDeviceInAoapMode(device)) {
+ mStatus.setText(R.string.usb_device_test_step2);
+ }
+
mUsbManager.requestPermission(device,
PendingIntent.getBroadcast(UsbDeviceTestActivity.this, 0,
new Intent(ACTION_USB_PERMISSION), 0));
@@ -121,6 +128,8 @@
if (granted) {
if (!AoapInterface.isDeviceInAoapMode(device)) {
+ mStatus.setText(R.string.usb_device_test_step3);
+
UsbDeviceConnection connection = mUsbManager.openDevice(device);
try {
makeThisDeviceAnAccessory(connection);
@@ -128,6 +137,13 @@
connection.close();
}
} else {
+ mStatus.setText(R.string.usb_device_test_step4);
+ mProgress.setIndeterminate(true);
+ mProgress.setVisibility(View.VISIBLE);
+
+ unregisterReceiver(mUsbDeviceConnectionReceiver);
+ mUsbDeviceConnectionReceiver = null;
+
// Do not run test on main thread
mTestThread = new Thread() {
@Override
@@ -147,22 +163,6 @@
}
}
};
- }
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.usb_main);
- setInfoResources(R.string.usb_device_test, R.string.usb_device_test_info, -1);
-
- mUsbManager = getSystemService(UsbManager.class);
-
- getPassButton().setEnabled(false);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_USB_PERMISSION);
- filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
registerReceiver(mUsbDeviceConnectionReceiver, filter);
}
@@ -390,22 +390,22 @@
* @throws Throwable
*/
private void ctrlTransferTests(@NonNull UsbDeviceConnection connection) throws Throwable {
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 1, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], -1, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 2, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 2, 0),
IllegalArgumentException.class);
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 0, 1, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, null, 0, 1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 0, -1, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 0, -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 1, 1, 0),
+ runAndAssertException(() -> connection.controlTransfer(0, 0, 0, 0, new byte[1], 1, 1, 0),
IllegalArgumentException.class);
}
@@ -729,7 +729,7 @@
*/
private void timeoutWhileWaitingForUsbRequest(@NonNull UsbDeviceConnection connection)
throws Throwable {
- assertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
+ runAndAssertException(() -> connection.requestWait(-1), IllegalArgumentException.class);
long startTime = now();
UsbRequest req = connection.requestWait(100);
@@ -981,18 +981,19 @@
// Illegal arguments
final UsbRequest req1 = new UsbRequest();
- assertException(() -> req1.initialize(null, in), NullPointerException.class);
- assertException(() -> req1.initialize(connection, null), NullPointerException.class);
+ runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+ runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
boolean isInited = req1.initialize(connection, in);
assertTrue(isInited);
- assertException(() -> req1.queue(null, 0), NullPointerException.class);
- assertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
+ runAndAssertException(() -> req1.queue(null, 0), NullPointerException.class);
+ runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1).asReadOnlyBuffer(), 1),
IllegalArgumentException.class);
req1.close();
// Cannot queue closed request
- assertException(() -> req1.queue(ByteBuffer.allocate(1), 1), NullPointerException.class);
- assertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
+ runAndAssertException(() -> req1.queue(ByteBuffer.allocate(1), 1),
+ NullPointerException.class);
+ runAndAssertException(() -> req1.queue(ByteBuffer.allocateDirect(1), 1),
NullPointerException.class);
}
@@ -1096,19 +1097,20 @@
// Illegal arguments
final UsbRequest req1 = new UsbRequest();
- assertException(() -> req1.initialize(null, in), NullPointerException.class);
- assertException(() -> req1.initialize(connection, null), NullPointerException.class);
+ runAndAssertException(() -> req1.initialize(null, in), NullPointerException.class);
+ runAndAssertException(() -> req1.initialize(connection, null), NullPointerException.class);
boolean isInited = req1.initialize(connection, in);
assertTrue(isInited);
- assertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
+ runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(16384 + 1).asReadOnlyBuffer()),
IllegalArgumentException.class);
- assertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
+ runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1).asReadOnlyBuffer()),
IllegalArgumentException.class);
req1.close();
// Cannot queue closed request
- assertException(() -> req1.enqueue(ByteBuffer.allocate(1)), IllegalStateException.class);
- assertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
+ runAndAssertException(() -> req1.enqueue(ByteBuffer.allocate(1)),
+ IllegalStateException.class);
+ runAndAssertException(() -> req1.enqueue(ByteBuffer.allocateDirect(1)),
IllegalStateException.class);
// Initialize
@@ -1629,27 +1631,27 @@
receiveOversizedBulkTransfer(connection, in);
// Illegal arguments
- assertException(() -> connection.bulkTransfer(out, new byte[1], 2, 0),
+ runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 2, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(in, new byte[1], 2, 0),
+ runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 2, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(out, new byte[2], 1, 2, 0),
+ runAndAssertException(() -> connection.bulkTransfer(out, new byte[2], 1, 2, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(in, new byte[2], 1, 2, 0),
+ runAndAssertException(() -> connection.bulkTransfer(in, new byte[2], 1, 2, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(out, new byte[1], -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(in, new byte[1], -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(out, new byte[1], 1, -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], 1, -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(in, new byte[1], 1, -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], 1, -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(out, new byte[1], -1, -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(out, new byte[1], -1, -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(in, new byte[1], -1, -1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(in, new byte[1], -1, -1, 0),
IllegalArgumentException.class);
- assertException(() -> connection.bulkTransfer(null, new byte[1], 1, 0),
+ runAndAssertException(() -> connection.bulkTransfer(null, new byte[1], 1, 0),
NullPointerException.class);
// Transmissions that do nothing
@@ -1768,9 +1770,11 @@
released = connection.releaseInterface(iface);
assertTrue(released);
- assertException(() -> connection.claimInterface(null, true), NullPointerException.class);
- assertException(() -> connection.claimInterface(null, false), NullPointerException.class);
- assertException(() -> connection.releaseInterface(null), NullPointerException.class);
+ runAndAssertException(() -> connection.claimInterface(null, true),
+ NullPointerException.class);
+ runAndAssertException(() -> connection.claimInterface(null, false),
+ NullPointerException.class);
+ runAndAssertException(() -> connection.releaseInterface(null), NullPointerException.class);
}
/**
@@ -1803,7 +1807,7 @@
boolean released = connection.releaseInterface(iface);
assertTrue(released);
- assertException(() -> connection.setConfiguration(null), NullPointerException.class);
+ runAndAssertException(() -> connection.setConfiguration(null), NullPointerException.class);
}
/**
@@ -1832,7 +1836,7 @@
released = connection.releaseInterface(iface);
assertTrue(released);
- assertException(() -> connection.setInterface(null), NullPointerException.class);
+ runAndAssertException(() -> connection.setInterface(null), NullPointerException.class);
}
/**
@@ -2010,14 +2014,10 @@
@Override
protected void onDestroy() {
- unregisterReceiver(mUsbDeviceConnectionReceiver);
- super.onDestroy();
- }
+ if (mUsbDeviceConnectionReceiver != null) {
+ unregisterReceiver(mUsbDeviceConnectionReceiver);
+ }
- /**
- * A {@link Runnable} that can throw an {@link Throwable}.
- */
- private interface Invokable {
- void run() throws Throwable;
+ super.onDestroy();
}
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java
new file mode 100644
index 0000000..8250594
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastActivity.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.telecom.TelecomManager;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+import com.android.cts.verifier.voicemail.VoicemailBroadcastReceiver.ReceivedListener;
+
+/**
+ * This test ask the tester to set the CTS verifier as the default dialer and leave a voicemail. The
+ * test will pass if the verifier is able to receive a broadcast for the incoming voicemail. This
+ * depends on telephony to send the broadcast to the default dialer when receiving a Message Waiting
+ * Indicator SMS.
+ */
+public class VoicemailBroadcastActivity extends PassFailButtons.Activity {
+
+ private String mDefaultDialer;
+
+ private ImageView mSetDefaultDialerImage;
+ private ImageView mLeaveVoicemailImage;
+ private TextView mLeaveVoicemailText;
+ private ImageView mRestoreDefaultDialerImage;
+ private TextView mRestoreDefaultDialerText;
+
+ private Button mSetDefaultDialerButton;
+ private Button mRestoreDefaultDialerButton;
+
+ private BroadcastReceiver mDefaultDialerChangedReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String packageName =
+ intent.getStringExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME);
+ if (!getPassButton().isEnabled()) {
+ updateSetDefaultDialerState(packageName);
+ } else {
+ if (packageName.equals(getPackageName())) {
+ mRestoreDefaultDialerImage
+ .setImageDrawable(getDrawable(R.drawable.fs_indeterminate));
+ } else {
+ mRestoreDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+ }
+ }
+ }
+ };
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ View view = getLayoutInflater().inflate(R.layout.voicemail_broadcast, null);
+ setContentView(view);
+ setInfoResources(R.string.voicemail_broadcast_test,
+ R.string.voicemail_broadcast_instructions, -1);
+ setPassFailButtonClickListeners();
+ getPassButton().setEnabled(false);
+
+ mSetDefaultDialerImage = (ImageView) findViewById(R.id.set_default_dialer_image);
+ mLeaveVoicemailImage = (ImageView) findViewById(R.id.leave_voicemail_image);
+ mLeaveVoicemailText = (TextView) findViewById(R.id.leave_voicemail_text);
+ mRestoreDefaultDialerImage = (ImageView) findViewById(R.id.restore_default_dialer_image);
+ mRestoreDefaultDialerText = (TextView) findViewById(R.id.restore_default_dialer_text);
+
+ mSetDefaultDialerButton = (Button) view.findViewById(R.id.set_default_dialer);
+ mRestoreDefaultDialerButton = (Button) view.findViewById(R.id.restore_default_dialer);
+
+ final TelecomManager telecomManager = getSystemService(TelecomManager.class);
+ mDefaultDialer = telecomManager.getDefaultDialerPackage();
+ updateSetDefaultDialerState(mDefaultDialer);
+ if (mDefaultDialer.equals(getPackageName())) {
+ // The CTS verifier is already the default dialer (probably due to the tester exiting
+ // mid test. We don't know what the default dialer should be so just prompt the tester
+ // to restore it through settings, and remove the button.
+ mRestoreDefaultDialerText
+ .setText(R.string.voicemail_restore_default_dialer_no_default_description);
+ mRestoreDefaultDialerButton.setVisibility(View.GONE);
+ }
+
+ mSetDefaultDialerButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (telecomManager.getDefaultDialerPackage().equals(getPackageName())) {
+ Toast.makeText(VoicemailBroadcastActivity.this,
+ R.string.voicemail_default_dialer_already_set, Toast.LENGTH_SHORT)
+ .show();
+ return;
+ }
+
+ final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
+ intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
+ getPackageName());
+ startActivityForResult(intent, 0);
+ }
+ });
+
+ mRestoreDefaultDialerButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ if (telecomManager.getDefaultDialerPackage().equals(mDefaultDialer)) {
+ Toast.makeText(VoicemailBroadcastActivity.this,
+ R.string.voicemail_default_dialer_already_restored, Toast.LENGTH_SHORT)
+ .show();
+ return;
+ }
+
+ final Intent intent = new Intent(TelecomManager.ACTION_CHANGE_DEFAULT_DIALER);
+ intent.putExtra(TelecomManager.EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME,
+ mDefaultDialer);
+ startActivityForResult(intent, 0);
+ }
+ });
+
+ VoicemailBroadcastReceiver.setListener(new ReceivedListener() {
+ @Override
+ public void onReceived() {
+
+ Toast.makeText(VoicemailBroadcastActivity.this,
+ R.string.voicemail_broadcast_received, Toast.LENGTH_SHORT).show();
+ mLeaveVoicemailImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+ mLeaveVoicemailText.setText(R.string.voicemail_broadcast_received);
+ getPassButton().setEnabled(true);
+ }
+ });
+
+ registerReceiver(mDefaultDialerChangedReceiver,
+ new IntentFilter(TelecomManager.ACTION_DEFAULT_DIALER_CHANGED));
+ }
+
+ @Override
+ protected void onDestroy() {
+ VoicemailBroadcastReceiver.setListener(null);
+ unregisterReceiver(mDefaultDialerChangedReceiver);
+ super.onDestroy();
+ }
+
+ private void updateSetDefaultDialerState(String packageName) {
+ if (packageName.equals(getPackageName())) {
+ mSetDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_good));
+ } else {
+ mSetDefaultDialerImage.setImageDrawable(getDrawable(R.drawable.fs_indeterminate));
+ }
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java
new file mode 100644
index 0000000..1785576
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/voicemail/VoicemailBroadcastReceiver.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.voicemail;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver used by {@link VoicemailBroadcastActivity} to receive {@link
+ * android.telephony.TelephonyManager.ACTION_SHOW_VOICEMAIL_NOTIFICATION}, which must be a manifest
+ * receiver.
+ */
+public class VoicemailBroadcastReceiver extends BroadcastReceiver {
+
+ public interface ReceivedListener {
+
+ void onReceived();
+ }
+
+ private static ReceivedListener sListener;
+
+ public static void setListener(ReceivedListener listener) {
+ sListener = listener;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (sListener != null) {
+ sListener.onReceived();
+ }
+ }
+}
diff --git a/apps/CtsVerifierUSBCompanion/res/layout/main.xml b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
index e3d45b2..6eb2cec 100644
--- a/apps/CtsVerifierUSBCompanion/res/layout/main.xml
+++ b/apps/CtsVerifierUSBCompanion/res/layout/main.xml
@@ -47,6 +47,13 @@
android:text="@string/device_test_button" />
<Button
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_below="@id/deviceTest"
+ android:id="@+id/accessoryTest"
+ android:text="@string/accessory_test_button" />
+
+ <Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/status"
diff --git a/apps/CtsVerifierUSBCompanion/res/values/strings.xml b/apps/CtsVerifierUSBCompanion/res/values/strings.xml
index 99b2d24..56bc71f 100644
--- a/apps/CtsVerifierUSBCompanion/res/values/strings.xml
+++ b/apps/CtsVerifierUSBCompanion/res/values/strings.xml
@@ -18,6 +18,7 @@
<resources>
<string name="status_label">Status:</string>
<string name="device_test_button">Start device test companion</string>
+ <string name="accessory_test_button">Start accessory test companion</string>
<string name="abort_button">Abort</string>
<string name="app_name">Cts Verifier USB Companion</string>
<string name="status_no_test">No test run</string>
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
new file mode 100644
index 0000000..dc5cc3d
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AccessoryTestCompanion.java
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.verifierusbcompanion;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.hardware.usb.UsbEndpoint;
+import android.hardware.usb.UsbInterface;
+import android.hardware.usb.UsbManager;
+import android.support.annotation.NonNull;
+
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+
+/**
+ * Companion code for com.android.cts.verifier.usb.device.UsbAccessoryTestActivity
+ */
+class AccessoryTestCompanion extends TestCompanion {
+ private static final int MAX_BUFFER_SIZE = 16384;
+
+ private static final String ACTION_USB_PERMISSION =
+ "com.android.cts.verifierusbcompanion.USB_PERMISSION";
+
+ private UsbManager mUsbManager;
+ private BroadcastReceiver mUsbDeviceConnectionReceiver;
+ private UsbDevice mDevice;
+
+ AccessoryTestCompanion(@NonNull Context context, @NonNull TestObserver observer) {
+ super(context, observer);
+ }
+
+ /**
+ * @throws Throwable
+ */
+ @Override
+ protected void runTest() throws Throwable {
+ updateStatus("Waiting for device under test to connect");
+
+ mUsbManager = getContext().getSystemService(UsbManager.class);
+
+ mUsbDeviceConnectionReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ synchronized (AccessoryTestCompanion.this) {
+ UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+
+ switch (intent.getAction()) {
+ case UsbManager.ACTION_USB_DEVICE_ATTACHED:
+ if (mUsbManager.hasPermission(device)) {
+ onDeviceAccessPermitted(device);
+ } else {
+ mUsbManager.requestPermission(device,
+ PendingIntent.getBroadcast(getContext(), 0,
+ new Intent(ACTION_USB_PERMISSION), 0));
+ }
+ break;
+ case ACTION_USB_PERMISSION:
+ boolean granted = intent.getBooleanExtra(
+ UsbManager.EXTRA_PERMISSION_GRANTED, false);
+
+ if (granted) {
+ onDeviceAccessPermitted(device);
+ } else {
+ fail("Permission to connect to " + device.getProductName()
+ + " not granted");
+ }
+ break;
+ }
+ }
+ }
+ };
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(ACTION_USB_PERMISSION);
+ filter.addAction(UsbManager.ACTION_USB_DEVICE_ATTACHED);
+
+ getContext().registerReceiver(mUsbDeviceConnectionReceiver, filter);
+
+ synchronized (this) {
+ while (mDevice == null) {
+ wait();
+ }
+ }
+
+ UsbInterface iface = null;
+ for (int i = 0; i < mDevice.getConfigurationCount(); i++) {
+ if (mDevice.getInterface(i).getName().equals("Android Accessory Interface")) {
+ iface = mDevice.getInterface(i);
+ break;
+ }
+ }
+
+ UsbEndpoint in = getEndpoint(iface, UsbConstants.USB_DIR_IN);
+ UsbEndpoint out = getEndpoint(iface, UsbConstants.USB_DIR_OUT);
+
+ UsbDeviceConnection connection = mUsbManager.openDevice(mDevice);
+
+ try {
+ String testName;
+ do {
+ testName = nextTest(connection, in, out, true);
+
+ updateStatus("Running test \"" + testName + "\"");
+
+ switch (testName) {
+ case "echo 32 bytes": {
+ byte[] buffer = new byte[32];
+
+ int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+ assertEquals(32, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+ assertEquals(32, numTransferred);
+ }
+ break;
+
+ case "echo two 16 byte transfers as one": {
+ byte[] buffer = new byte[48];
+
+ // We receive the individual transfers even if we wait for more data
+ int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+ assertEquals(16, numTransferred);
+ numTransferred = connection.bulkTransfer(in, buffer, 16, 32, 0);
+ assertEquals(16, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, 32, 0);
+ assertEquals(32, numTransferred);
+ }
+ break;
+
+ case "echo 32 bytes as two 16 byte transfers": {
+ byte[] buffer = new byte[32];
+
+ int numTransferred = connection.bulkTransfer(in, buffer, 32, 0);
+ assertEquals(32, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, 16, 0);
+ assertEquals(16, numTransferred);
+ numTransferred = connection.bulkTransfer(out, buffer, 16, 16, 0);
+ assertEquals(16, numTransferred);
+ }
+ break;
+
+ case "echo max bytes": {
+ byte[] buffer = new byte[MAX_BUFFER_SIZE];
+
+ int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+ 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+ }
+ break;
+
+ case "echo max*2 bytes": {
+ byte[] buffer = new byte[MAX_BUFFER_SIZE * 2];
+
+ int numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+ 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+ // Oversized transfers get split into two
+ numTransferred = connection.bulkTransfer(in, buffer, MAX_BUFFER_SIZE,
+ MAX_BUFFER_SIZE, 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE, 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, buffer, MAX_BUFFER_SIZE,
+ MAX_BUFFER_SIZE, 0);
+ assertEquals(MAX_BUFFER_SIZE, numTransferred);
+ }
+ break;
+
+ default:
+ break;
+ }
+ } while (!testName.equals("done"));
+ } finally {
+ connection.close();
+ }
+ }
+
+ /**
+ * If access to a device was permitted either make the device an accessory if it already is,
+ * start the test.
+ *
+ * @param device The device access was permitted to
+ */
+ private void onDeviceAccessPermitted(@NonNull UsbDevice device) {
+ if (!AoapInterface.isDeviceInAoapMode(device)) {
+ UsbDeviceConnection connection = mUsbManager.openDevice(device);
+ try {
+ makeThisDeviceAnAccessory(connection);
+ } finally {
+ connection.close();
+ }
+ } else {
+ getContext().unregisterReceiver(mUsbDeviceConnectionReceiver);
+ mUsbDeviceConnectionReceiver = null;
+
+ synchronized (AccessoryTestCompanion.this) {
+ mDevice = device;
+
+ AccessoryTestCompanion.this.notifyAll();
+ }
+ }
+ }
+
+ @NonNull private String nextTest(@NonNull UsbDeviceConnection connection,
+ @NonNull UsbEndpoint in, @NonNull UsbEndpoint out, boolean isSuccess) {
+ byte[] sizeBuffer = new byte[1];
+
+ updateStatus("Waiting for next test");
+
+ int numTransferred = connection.bulkTransfer(in, sizeBuffer, 1, 0);
+ assertEquals(1, numTransferred);
+
+ int nameSize = sizeBuffer[0];
+
+ byte[] nameBuffer = new byte[nameSize];
+ numTransferred = connection.bulkTransfer(in, nameBuffer, nameSize, 0);
+ assertEquals(nameSize, numTransferred);
+
+ numTransferred = connection.bulkTransfer(out, new byte[]{(byte) (isSuccess ? 1 : 0)}, 1, 0);
+ assertEquals(1, numTransferred);
+
+ numTransferred = connection.bulkTransfer(in, new byte[1], 1, 0);
+ assertEquals(1, numTransferred);
+
+ String name = Charset.forName("UTF-8").decode(ByteBuffer.wrap(nameBuffer)).toString();
+
+ updateStatus("Next test is " + name);
+
+ return name;
+ }
+
+ /**
+ * Search an {@link UsbInterface} for an {@link UsbEndpoint endpoint} of a certain direction.
+ *
+ * @param iface The interface to search
+ * @param direction The direction the endpoint is for.
+ *
+ * @return The first endpoint found or {@link null}.
+ */
+ @NonNull private UsbEndpoint getEndpoint(@NonNull UsbInterface iface, int direction) {
+ for (int i = 0; i < iface.getEndpointCount(); i++) {
+ UsbEndpoint ep = iface.getEndpoint(i);
+ if (ep.getDirection() == direction) {
+ return ep;
+ }
+ }
+
+ throw new IllegalStateException("Could not find " + direction + " endpoint in "
+ + iface.getName());
+ }
+
+ /**
+ * Converts the device under test into an Android accessory. Accessories are USB hosts that are
+ * detected on the device side via {@link UsbManager#getAccessoryList()}.
+ *
+ * @param connection The connection to the USB device
+ */
+ private void makeThisDeviceAnAccessory(@NonNull UsbDeviceConnection connection) {
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MANUFACTURER,
+ "Android");
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_MODEL,
+ "Android device");
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_DESCRIPTION,
+ "Android device running CTS verifier");
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_VERSION, "1");
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_URI,
+ "https://source.android.com/compatibility/cts/verifier.html");
+ AoapInterface.sendString(connection, AoapInterface.ACCESSORY_STRING_SERIAL, "0");
+ AoapInterface.sendAoapStart(connection);
+ }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
new file mode 100644
index 0000000..6f8d1a1
--- /dev/null
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/AoapInterface.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.verifierusbcompanion;
+
+import android.hardware.usb.UsbConstants;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbDeviceConnection;
+import android.util.Log;
+
+class AoapInterface {
+ /**
+ * Use Google Vendor ID when in accessory mode
+ */
+ private static final int USB_ACCESSORY_VENDOR_ID = 0x18D1;
+
+ /**
+ * Product ID to use when in accessory mode
+ */
+ private static final int USB_ACCESSORY_PRODUCT_ID = 0x2D00;
+
+ /**
+ * Product ID to use when in accessory mode and adb is enabled
+ */
+ private static final int USB_ACCESSORY_ADB_PRODUCT_ID = 0x2D01;
+
+ /**
+ * Indexes for strings sent by the host via ACCESSORY_SEND_STRING
+ */
+ public static final int ACCESSORY_STRING_MANUFACTURER = 0;
+ public static final int ACCESSORY_STRING_MODEL = 1;
+ public static final int ACCESSORY_STRING_DESCRIPTION = 2;
+ public static final int ACCESSORY_STRING_VERSION = 3;
+ public static final int ACCESSORY_STRING_URI = 4;
+ public static final int ACCESSORY_STRING_SERIAL = 5;
+
+ /**
+ * Control request for retrieving device's protocol version
+ *
+ * requestType: USB_DIR_IN | USB_TYPE_VENDOR
+ * request: ACCESSORY_GET_PROTOCOL
+ * value: 0
+ * index: 0
+ * data version number (16 bits little endian)
+ * 1 for original accessory support
+ * 2 adds HID and device to host audio support
+ */
+ private static final int ACCESSORY_GET_PROTOCOL = 51;
+
+ /**
+ * Control request for host to send a string to the device
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_SEND_STRING
+ * value: 0
+ * index: string ID
+ * data zero terminated UTF8 string
+ *
+ * The device can later retrieve these strings via the
+ * ACCESSORY_GET_STRING_* ioctls
+ */
+ private static final int ACCESSORY_SEND_STRING = 52;
+
+ /**
+ * Control request for starting device in accessory mode.
+ * The host sends this after setting all its strings to the device.
+ *
+ * requestType: USB_DIR_OUT | USB_TYPE_VENDOR
+ * request: ACCESSORY_START
+ * value: 0
+ * index: 0
+ * data none
+ */
+ private static final int ACCESSORY_START = 53;
+
+ private static final String TAG = AoapInterface.class.getSimpleName();
+
+ public static int getProtocol(UsbDeviceConnection conn) {
+ byte[] buffer = new byte[2];
+ int len = conn.controlTransfer(
+ UsbConstants.USB_DIR_IN | UsbConstants.USB_TYPE_VENDOR,
+ AoapInterface.ACCESSORY_GET_PROTOCOL, 0, 0, buffer, 2, 10000);
+ if (len != 2) {
+ return -1;
+ }
+ return (buffer[1] << 8) | buffer[0];
+ }
+
+ public static void sendString(UsbDeviceConnection conn, int index, String string) {
+ byte[] buffer = (string + "\0").getBytes();
+ int len = conn.controlTransfer(
+ UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+ AoapInterface.ACCESSORY_SEND_STRING, 0, index,
+ buffer, buffer.length, 10000);
+ if (len != buffer.length) {
+ throw new RuntimeException("Failed to send string " + index + ": \"" + string + "\"");
+ } else {
+ Log.i(TAG, "Sent string " + index + ": \"" + string + "\"");
+ }
+ }
+
+ public static void sendAoapStart(UsbDeviceConnection conn) {
+ int len = conn.controlTransfer(
+ UsbConstants.USB_DIR_OUT | UsbConstants.USB_TYPE_VENDOR,
+ AoapInterface.ACCESSORY_START, 0, 0, null, 0, 10000);
+ if (len < 0) {
+ throw new RuntimeException("control transfer for accessory start failed:" + len);
+ }
+ }
+
+ public static boolean isDeviceInAoapMode(UsbDevice device) {
+ final int vid = device.getVendorId();
+ final int pid = device.getProductId();
+ return vid == USB_ACCESSORY_VENDOR_ID
+ && (pid == USB_ACCESSORY_PRODUCT_ID
+ || pid == USB_ACCESSORY_ADB_PRODUCT_ID);
+ }
+}
diff --git a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
index 4b1bb39..a87f9ce 100644
--- a/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
+++ b/apps/CtsVerifierUSBCompanion/src/com/android/cts/verifierusbcompanion/Main.java
@@ -16,10 +16,10 @@
package com.android.cts.verifierusbcompanion;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
import android.app.Activity;
import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
import android.view.View;
import android.view.WindowManager;
import android.widget.Button;
@@ -31,6 +31,7 @@
public class Main extends Activity implements TestCompanion.TestObserver {
private TextView mStatusMessage;
private Button mDeviceTestButton;
+ private Button mAccessoryTestButton;
private Button mAbortButton;
private TestCompanion mCurrentTest;
@@ -44,11 +45,13 @@
mStatusMessage = (TextView) findViewById(R.id.status_message);
mDeviceTestButton = (Button) findViewById(R.id.deviceTest);
+ mAccessoryTestButton = (Button) findViewById(R.id.accessoryTest);
mAbortButton = (Button) findViewById(R.id.abort);
mStatusMessage.setText(getString(R.string.status_no_test));
mDeviceTestButton.setOnClickListener(view -> runDeviceTest());
+ mAccessoryTestButton.setOnClickListener(view -> runAccessoryTest());
mAbortButton.setOnClickListener(view -> abortCurrentTest());
}
@@ -60,19 +63,27 @@
}
/**
- * Abort the {@link DeviceTestCompanion}
+ * Run the {@link DeviceTestCompanion}
*/
private void runDeviceTest() {
runTestCompanion(new DeviceTestCompanion(this, this));
}
/**
+ * Run the {@link AccessoryTestCompanion}
+ */
+ private void runAccessoryTest() {
+ runTestCompanion(new AccessoryTestCompanion(this, this));
+ }
+
+ /**
* Run a test.
* @param test The test to run
*/
private void runTestCompanion(@NonNull TestCompanion test) {
mAbortButton.setVisibility(View.VISIBLE);
mDeviceTestButton.setVisibility(View.GONE);
+ mAccessoryTestButton.setVisibility(View.GONE);
mCurrentTest = test;
test.start();
@@ -84,6 +95,7 @@
private void resetUI() {
mAbortButton.setVisibility(View.GONE);
mDeviceTestButton.setVisibility(View.VISIBLE);
+ mAccessoryTestButton.setVisibility(View.VISIBLE);
}
@Override
diff --git a/apps/cts-usb-accessory/Android.mk b/apps/cts-usb-accessory/Android.mk
deleted file mode 100644
index 7699b1a..0000000
--- a/apps/cts-usb-accessory/Android.mk
+++ /dev/null
@@ -1,41 +0,0 @@
-#
-# Copyright (C) 2011 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# Build for Linux (desktop) host
-ifeq ($(HOST_OS),linux)
-
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := cts-usb-accessory.c
-
-LOCAL_MODULE := cts-usb-accessory
-
-LOCAL_C_INCLUDES += \
- bionic/libc/kernel/uapi \
- bionic/libc/kernel/android/uapi \
- bionic/libc/kernel/uapi/asm-x86 \
-
-LOCAL_STATIC_LIBRARIES := libusbhost libcutils
-LOCAL_LDLIBS += -lpthread
-LOCAL_CFLAGS := -g -O0
-LOCAL_CXX_STL := none
-
-include $(BUILD_HOST_EXECUTABLE)
-
-endif
diff --git a/apps/cts-usb-accessory/cts-usb-accessory.c b/apps/cts-usb-accessory/cts-usb-accessory.c
deleted file mode 100644
index 0fbfce7..0000000
--- a/apps/cts-usb-accessory/cts-usb-accessory.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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 <unistd.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <pthread.h>
-#include <time.h>
-
-#include <usbhost/usbhost.h>
-#include <linux/usb/f_accessory.h>
-
-#define USB_CONTROL_READ_TIMEOUT_MS 200
-
-static struct usb_device *sDevice = NULL;
-static int sAfterUnplug = 0;
-static char* sDeviceSerial = NULL;
-
-static void* message_thread(void* arg) {
- int *endpoints = (int *)arg;
- int ret = 0;
- int num = 0;
- char message[50];
-
- while (sDevice && ret >= 0) {
- char buffer[16384];
- ret = usb_device_bulk_transfer(sDevice, endpoints[0], buffer, sizeof(buffer), 1000);
- if (ret < 0 && errno == ETIMEDOUT) {
- ret = 0;
- }
- if (ret > 0) {
- printf("[RECV] ");
- fwrite(buffer, 1, ret, stdout);
- printf("\n");
-
- // Respond by sending a message back
- sprintf(message, "Message from Android accessory #%d", num++);
- printf("[SENT] %s\n", message);
- fflush(stdout);
- usb_device_bulk_transfer(sDevice, endpoints[1], message, strlen(message), 1000);
- }
- }
-
- return NULL;
-}
-
-static void milli_sleep(int millis) {
- struct timespec tm;
-
- tm.tv_sec = 0;
- tm.tv_nsec = millis * 1000000;
- nanosleep(&tm, NULL);
-}
-
-static int send_string(struct usb_device *device, int index, const char* string) {
- int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
- ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 1000);
-
- // some devices can't handle back-to-back requests, so delay a bit
- milli_sleep(10);
- return ret;
-}
-
-static int usb_device_added(const char *devname, void* client_data) {
- struct usb_descriptor_header* desc;
- struct usb_descriptor_iter iter;
- uint16_t vendorId, productId;
- int ret;
- pthread_t th;
-
- struct usb_device *device = usb_device_open(devname);
- if (!device) {
- fprintf(stderr, "usb_device_open failed\n");
- return 0;
- }
-
- char* serial = usb_device_get_serial(device, USB_CONTROL_READ_TIMEOUT_MS);
- if (sDeviceSerial && (!serial || strcmp(sDeviceSerial, serial))) {
- free(serial);
- return 0;
- }
- free(serial);
-
- vendorId = usb_device_get_vendor_id(device);
- productId = usb_device_get_product_id(device);
-
- if (!sDevice && (vendorId == 0x18D1 && (productId == 0x2D00 || productId == 0x2D01))) {
- struct usb_descriptor_header* desc;
- struct usb_descriptor_iter iter;
- struct usb_interface_descriptor *intf = NULL;
- struct usb_endpoint_descriptor *ep1 = NULL;
- struct usb_endpoint_descriptor *ep2 = NULL;
-
- printf("Found Android device in accessory mode (%x:%x)...\n",
- vendorId, productId);
- sDevice = device;
- sDeviceSerial = usb_device_get_serial(sDevice, USB_CONTROL_READ_TIMEOUT_MS);
-
- usb_descriptor_iter_init(device, &iter);
- while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
- if (desc->bDescriptorType == USB_DT_INTERFACE) {
- intf = (struct usb_interface_descriptor *)desc;
- } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
- if (ep1)
- ep2 = (struct usb_endpoint_descriptor *)desc;
- else
- ep1 = (struct usb_endpoint_descriptor *)desc;
- }
- }
-
- if (!intf) {
- fprintf(stderr, "Interface not found\n");
- exit(1);
- }
- if (!ep1 || !ep2) {
- fprintf(stderr, "Endpoints not found\n");
- exit(1);
- }
-
- if (usb_device_claim_interface(device, intf->bInterfaceNumber)) {
- fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno);
- exit(1);
- }
-
- int endpoints[2];
- if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
- endpoints[0] = ep1->bEndpointAddress;
- endpoints[1] = ep2->bEndpointAddress;
- } else {
- endpoints[0] = ep2->bEndpointAddress;
- endpoints[1] = ep1->bEndpointAddress;
- }
- pthread_create(&th, NULL, message_thread, (void *)endpoints);
- } else {
- printf("Found possible Android device (%x:%x) "
- "- attempting to switch to accessory mode...\n", vendorId, productId);
-
- uint16_t protocol = 0;
- ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
- ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 1000);
- if (ret == 2) {
- printf("Device supports protocol version %d\n", protocol);
- } else {
- fprintf(stderr, "Failed to read protocol version\n");
- }
-
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_MANUFACTURER, "Android CTS");
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_MODEL, "CTS USB Accessory");
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_DESCRIPTION, "CTS USB Accessory");
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_VERSION, "1.0");
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_URI,
- "http://source.android.com/compatibility/cts-intro.html");
- ret = (ret < 0) ? ret :
- send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
-
- ret = (ret < 0) ? ret :
- usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
- ACCESSORY_START, 0, 0, 0, 0, 1000);
- if (ret < 0) {
- fprintf(stderr, "Failed to start accessory mode\n");
- }
- return 0;
- }
-
- if (device != sDevice)
- usb_device_close(device);
-
- return 0;
-}
-
-static int usb_device_removed(const char *devname, void* client_data) {
- if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
- usb_device_close(sDevice);
- sDevice = NULL;
- if (sAfterUnplug) {
- // exit when we are disconnected the second time
- free(sDeviceSerial);
- return 1;
- } else {
- sAfterUnplug = 1;
- }
- }
- return 0;
-}
-
-
-int main(int argc, char* argv[]) {
- printf("CTS USB Accessory Tester\n");
-
- struct usb_host_context* context = usb_host_init();
- if (!context) {
- fprintf(stderr, "usb_host_init failed");
- return 1;
- }
-
- // this will never return so it is safe to pass thiz directly
- usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL);
- return 0;
-}
diff --git a/build/compatibility_test_suite.mk b/build/compatibility_test_suite.mk
index f109185..7cdd220 100644
--- a/build/compatibility_test_suite.mk
+++ b/build/compatibility_test_suite.mk
@@ -46,7 +46,7 @@
LOCAL_GENERATED_SOURCES := $(suite_info_java)
# Add the base libraries
-LOCAL_JAVA_LIBRARIES += tradefed-prebuilt hosttestlib compatibility-host-util
+LOCAL_JAVA_LIBRARIES += tradefed hosttestlib compatibility-host-util
LOCAL_MODULE_TAGS := optional
diff --git a/common/host-side/manifest-generator/tests/Android.mk b/common/host-side/manifest-generator/tests/Android.mk
index 2eb5d2f..1601fc8 100644
--- a/common/host-side/manifest-generator/tests/Android.mk
+++ b/common/host-side/manifest-generator/tests/Android.mk
@@ -18,7 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := compatibility-manifest-generator junit
+LOCAL_JAVA_LIBRARIES := compatibility-manifest-generator junit-host
LOCAL_MODULE := compatibility-manifest-generator-tests
diff --git a/tools/cts-tradefed/res/config/cts-unit-tests.xml b/common/host-side/tradefed/res/config/cts-unit-tests.xml
similarity index 94%
rename from tools/cts-tradefed/res/config/cts-unit-tests.xml
rename to common/host-side/tradefed/res/config/cts-unit-tests.xml
index f621a7b..4bec93e 100644
--- a/tools/cts-tradefed/res/config/cts-unit-tests.xml
+++ b/common/host-side/tradefed/res/config/cts-unit-tests.xml
@@ -21,6 +21,7 @@
<option name="class" value="com.android.compatibility.common.util.HostUnitTests" />
<option name="class" value="com.android.compatibility.common.util.UnitTests" />
<option name="class" value="com.android.compatibility.tradefed.CtsTradefedTest" />
+ <option name="class" value="com.drawelements.deqp.runner.DeqpTestRunnerTest" />
</test>
<logger class="com.android.tradefed.log.FileLogger" />
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 0887d07..c1087a1 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
@@ -208,6 +208,19 @@
}
/**
+ * @return a {@link File} representing the test file in the test modules directory.
+ * @throws FileNotFoundException if the test file cannot be found
+ */
+ public File getTestFile(String filename) throws FileNotFoundException {
+ File testFile = new File(getTestsDir(), filename);
+ if (!testFile.exists()) {
+ throw new FileNotFoundException(String.format(
+ "Compatibility test file %s does not exist", filename));
+ }
+ return testFile;
+ }
+
+ /**
* @return a {@link File} in the resultDir for logging invocation failures
*/
public File getInvocationFailureFile() throws FileNotFoundException {
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 01a35b4..dc6a321 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
@@ -216,7 +216,7 @@
helpBuilder.append("Options:\n");
helpBuilder.append(" --session <session_id>: The session used to create a subplan.\n");
helpBuilder.append(" --name/-n <subplan_name>: The name of the new subplan.\n");
- helpBuilder.append(" --result-type/-r <status>: Which results to include in the");
+ helpBuilder.append(" --result-type <status>: Which results to include in the");
helpBuilder.append(" subplan. One of passed, failed, not_executed. Repeatable.\n");
return helpBuilder.toString();
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 7310f56..3c0b21b 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
@@ -404,7 +404,6 @@
// NOTE: Everything after this line only applies to the master ResultReporter.
-
synchronized(this) {
// The master ResultReporter tracks the progress of all invocations across
// shard ResultReporters. Writing results should not proceed until all
@@ -456,16 +455,16 @@
long startTime = mResult.getStartTime();
try {
+ // Zip the full test results directory.
+ copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
+ copyFormattingFiles(mResultDir);
+
File resultFile = ResultHandler.writeResults(mBuildHelper.getSuiteName(),
mBuildHelper.getSuiteVersion(), mBuildHelper.getSuitePlan(),
mBuildHelper.getSuiteBuild(), mResult, mResultDir, startTime,
elapsedTime + startTime, mReferenceUrl, getLogUrl(),
mBuildHelper.getCommandLineArgs());
info("Test Result: %s", resultFile.getCanonicalPath());
-
- // Zip the full test results directory.
- copyDynamicConfigFiles(mBuildHelper.getDynamicConfigFiles(), mResultDir);
- copyFormattingFiles(mResultDir);
File zippedResults = zipResults(mResultDir);
info("Full Result: %s", zippedResults.getCanonicalPath());
diff --git a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
index 7d6d77f..4b4c0be 100644
--- a/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
+++ b/common/host-side/tradefed/src/com/android/compatibility/common/tradefed/result/SubPlanCreator.java
@@ -57,12 +57,20 @@
public static final String FAILED = "failed";
public static final String NOT_EXECUTED = "not_executed";
// static mapping of result types to TestStatuses
- private static final Map<String, TestStatus> mStatusMap;
+ private static final Map<String, TestStatus> STATUS_MAP;
static {
Map<String, TestStatus> statusMap = new HashMap<String, TestStatus>();
statusMap.put(PASSED, TestStatus.PASS);
statusMap.put(FAILED, TestStatus.FAIL);
- mStatusMap = Collections.unmodifiableMap(statusMap);
+ STATUS_MAP = Collections.unmodifiableMap(statusMap);
+ }
+
+ // TODO(aaronholden): remove this temporary workaround for b/33090757
+ private static final Set<String> MULTITEST_MODULES;
+ static {
+ Set<String> multiTestModuleSet = new HashSet<String>();
+ multiTestModuleSet.add("CtsDeqpTestCases");
+ MULTITEST_MODULES = Collections.unmodifiableSet(multiTestModuleSet);
}
@Option (name = "name", shortName = 'n', description = "the name of the subplan to create",
@@ -73,7 +81,7 @@
importance=Importance.IF_UNSET)
private Integer mSessionId = null;
- @Option (name = "result-type", shortName = 'r',
+ @Option (name = "result-type",
description = "the result type to include. One of passed, failed, not_executed."
+ " Option may be repeated",
importance=Importance.IF_UNSET)
@@ -219,9 +227,21 @@
}
} else {
// module should not run, exclude entire module
- TestFilter moduleExclude =
- new TestFilter(module.getAbi(), module.getName(), null /*test*/);
- subPlan.addExcludeFilter(moduleExclude.toString());
+ // TODO(aaronholden): remove this special case from SubPlanCreator, and filter
+ // individual tests only when the module should run. Tracked by b/33211104
+ if (MULTITEST_MODULES.contains(module.getName())) {
+ for (ICaseResult caseResult : module.getResults()) {
+ for (ITestResult testResult : caseResult.getResults()) {
+ TestFilter testExclude = new TestFilter(module.getAbi(),
+ module.getName(), testResult.getFullName());
+ subPlan.addExcludeFilter(testExclude.toString());
+ }
+ }
+ } else {
+ TestFilter moduleExclude =
+ new TestFilter(module.getAbi(), module.getName(), null /*test*/);
+ subPlan.addExcludeFilter(moduleExclude.toString());
+ }
}
}
return subPlan;
@@ -280,7 +300,7 @@
for (String resultType : mResultTypes) {
// no test status exists for not-executed tests
if (resultType != NOT_EXECUTED) {
- statusesToRun.add(mStatusMap.get(resultType));
+ statusesToRun.add(STATUS_MAP.get(resultType));
}
}
return statusesToRun;
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 5c0658f..06cca2f 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
@@ -221,6 +221,11 @@
IModuleListener moduleListener = new ModuleListener(this, listener);
CLog.d("Running module %s", toString());
+ // Run DynamicConfigPusher setup once more, in case cleaner has previously
+ // removed dynamic config file from the target (see b/32877809)
+ for (ITargetPreparer preparer : mDynamicConfigPreparers) {
+ runPreparerSetup(preparer);
+ }
// Setup
for (ITargetPreparer preparer : mPreparers) {
runPreparerSetup(preparer);
diff --git a/common/host-side/tradefed/tests/Android.mk b/common/host-side/tradefed/tests/Android.mk
index e0b44a3..17bdd50 100644
--- a/common/host-side/tradefed/tests/Android.mk
+++ b/common/host-side/tradefed/tests/Android.mk
@@ -41,6 +41,6 @@
LOCAL_STATIC_JAVA_LIBRARIES := easymock
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt compatibility-mock-tradefed junit compatibility-host-util
+LOCAL_JAVA_LIBRARIES := tradefed compatibility-mock-tradefed junit-host compatibility-host-util
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
index 1752e20..dcdede0 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/UnitTests.java
@@ -18,6 +18,8 @@
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelperTest;
import com.android.compatibility.common.tradefed.command.CompatibilityConsoleTest;
import com.android.compatibility.common.tradefed.config.ConfigurationFactoryTest;
+import com.android.compatibility.common.tradefed.presubmit.PresubmitSetupValidation;
+import com.android.compatibility.common.tradefed.result.ChecksumReporterTest;
import com.android.compatibility.common.tradefed.result.ConsoleReporterTest;
import com.android.compatibility.common.tradefed.result.ResultReporterTest;
import com.android.compatibility.common.tradefed.result.SubPlanCreatorTest;
@@ -27,8 +29,8 @@
import com.android.compatibility.common.tradefed.testtype.ModuleDefTest;
import com.android.compatibility.common.tradefed.testtype.ModuleRepoTest;
import com.android.compatibility.common.tradefed.testtype.SubPlanTest;
-import com.android.compatibility.common.tradefed.util.OptionHelperTest;
import com.android.compatibility.common.tradefed.util.CollectorUtilTest;
+import com.android.compatibility.common.tradefed.util.OptionHelperTest;
import junit.framework.Test;
import junit.framework.TestSuite;
@@ -42,20 +44,37 @@
public UnitTests() {
super();
+ // build
addTestSuite(CompatibilityBuildHelperTest.class);
+
+ // command
addTestSuite(CompatibilityConsoleTest.class);
- addTestSuite(CompatibilityTestTest.class);
+
+ //config
addTestSuite(ConfigurationFactoryTest.class);
+
+ // presubmit
+ addTestSuite(PresubmitSetupValidation.class);
+
+ //result
+ addTestSuite(ChecksumReporterTest.class);
addTestSuite(ConsoleReporterTest.class);
addTestSuite(ResultReporterTest.class);
- addTestSuite(OptionHelperTest.class);
- addTestSuite(CollectorUtilTest.class);
- addTestSuite(ModuleDefTest.class);
- addTestSuite(ModuleRepoTest.class);
+ addTestSuite(SubPlanCreatorTest.class);
+
+ // targetprep
addTestSuite(PropertyCheckTest.class);
addTestSuite(SettingsPreparerTest.class);
+
+ // testtype
+ addTestSuite(CompatibilityTestTest.class);
+ addTestSuite(ModuleDefTest.class);
+ addTestSuite(ModuleRepoTest.class);
addTestSuite(SubPlanTest.class);
- addTestSuite(SubPlanCreatorTest.class);
+
+ // util
+ addTestSuite(CollectorUtilTest.class);
+ addTestSuite(OptionHelperTest.class);
}
public static Test suite() {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
new file mode 100644
index 0000000..3342ba0
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/PresubmitSetupValidation.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.presubmit;
+
+import com.android.tradefed.config.ConfigurationException;
+import com.android.tradefed.config.ConfigurationFactory;
+import com.android.tradefed.config.IConfigurationFactory;
+import com.android.tradefed.log.LogUtil.CLog;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that validate the CTS presubmit setup to ensure no CL will break the presubmit setup
+ * itself.
+ */
+public class PresubmitSetupValidation extends TestCase {
+ private static final String PRESUBMIT_CTS_UNIT_TESTS = "cts-unit-tests";
+
+ /**
+ * Test that the base cts unit tests configuration is still working, and has a reporter
+ * template placeholder.
+ */
+ public void testCtsPresubmit_unit_tests() {
+ IConfigurationFactory factory = ConfigurationFactory.getInstance();
+ String[] presubmitCommand = {PRESUBMIT_CTS_UNIT_TESTS, "--template:map", "reporters=empty"};
+ try {
+ factory.createConfigurationFromArgs(presubmitCommand);
+ } catch (ConfigurationException e) {
+ CLog.e(e);
+ fail(String.format("ConfigException '%s': One of your change is breaking the presubmit "
+ + "CTS unit tests configuration.", e.getMessage()));
+ }
+ }
+}
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
new file mode 100644
index 0000000..d5062b3
--- /dev/null
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/ChecksumReporterTest.java
@@ -0,0 +1,193 @@
+/*
+ * 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.result;
+
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildProvider;
+import com.android.compatibility.common.util.ChecksumReporter;
+import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
+import com.android.compatibility.common.util.ICaseResult;
+import com.android.compatibility.common.util.IInvocationResult;
+import com.android.compatibility.common.util.IModuleResult;
+import com.android.compatibility.common.util.ITestResult;
+import com.android.compatibility.common.util.ReportLog;
+import com.android.compatibility.common.util.TestStatus;
+import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.OptionSetter;
+import com.android.tradefed.util.FileUtil;
+
+import junit.framework.TestCase;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+
+public class ChecksumReporterTest extends TestCase {
+
+ private static final String ROOT_PROPERTY = "TESTS_ROOT";
+ private static final String ROOT_DIR_NAME = "root";
+ private static final String SUITE_NAME = "TESTS";
+ private static final String BUILD_NUMBER = "2";
+ private static final String SUITE_PLAN = "cts";
+ private static final String BASE_DIR_NAME = "android-tests";
+ private static final String TESTCASES = "testcases";
+
+ private ChecksumReporter mReporter;
+ private File mRoot = null;
+ private IBuildInfo mBuildInfo;
+ private ReportLog mReportLog = null;
+ private IInvocationResult mInvocationResult;
+ private IModuleResult mModuleResult;
+ private ITestResult mFailedTest;
+
+ @Override
+ public void setUp() throws Exception {
+ mReporter = new ChecksumReporter(100, .001, (short)1);
+ mRoot = FileUtil.createTempDir(ROOT_DIR_NAME);
+ File baseDir = new File(mRoot, BASE_DIR_NAME);
+ baseDir.mkdirs();
+ File testDir = new File(baseDir, TESTCASES);
+ testDir.mkdirs();
+ System.setProperty(ROOT_PROPERTY, mRoot.getAbsolutePath());
+
+ ResultReporter resultReporter = new ResultReporter();
+ CompatibilityBuildProvider provider = new CompatibilityBuildProvider() {
+ @Override
+ protected String getSuiteInfoName() {
+ return SUITE_NAME;
+ }
+ @Override
+ protected String getSuiteInfoBuildNumber() {
+ return BUILD_NUMBER;
+ }
+ @Override
+ protected String getSuiteInfoVersion() {
+ return BUILD_NUMBER;
+ }
+ };
+ OptionSetter setter = new OptionSetter(provider);
+ setter.setOptionValue("plan", SUITE_PLAN);
+ setter.setOptionValue("dynamic-config-url", "");
+ mBuildInfo = provider.getBuild();
+
+ resultReporter.invocationStarted(mBuildInfo);
+ mInvocationResult = resultReporter.getResult();
+ mModuleResult = mInvocationResult.getOrCreateModule("Module-1");
+ mModuleResult.setDone(true);
+ mModuleResult.setNotExecuted(0);
+ ICaseResult caseResult = mModuleResult.getOrCreateResult("Case-1");
+ ITestResult test1 = caseResult.getOrCreateResult("Test1");
+ test1.passed(mReportLog);
+ mFailedTest = caseResult.getOrCreateResult("Test2");
+ mFailedTest.failed("stack-trace - error happened");
+
+ IModuleResult moduleResult2 = mInvocationResult.getOrCreateModule("Module-2");
+ ICaseResult caseResult2 = moduleResult2.getOrCreateResult("Case-2");
+ mModuleResult.setDone(false);
+ mModuleResult.setNotExecuted(1);
+ ITestResult test3 = caseResult2.getOrCreateResult("Test3");
+ test3.passed(mReportLog);
+
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ mReporter = null;
+ FileUtil.recursiveDelete(mRoot);
+ }
+
+ public void testStoreAndRetrieveTestResults() {
+ mReporter.addInvocation(mInvocationResult);
+ VerifyInvocationResults(mInvocationResult, mReporter);
+ }
+
+ /***
+ * By definition this test is flaky since the checksum has a false positive probability of .1%
+ */
+ public void testInvalidChecksums() {
+ mReporter.addInvocation(mInvocationResult);
+ IModuleResult module = mInvocationResult.getModules().get(1);
+ module.setDone(!module.isDone());
+ String fingerprint = mInvocationResult.getBuildFingerprint();
+ assertFalse("Checksum should contain module: " + module.getName(),
+ mReporter.containsModuleResult(module, fingerprint));
+
+ mFailedTest.setResultStatus(TestStatus.PASS);
+ assertFalse("Checksum should not contain test: " + mFailedTest.getName(),
+ mReporter.containsTestResult(mFailedTest, mModuleResult, fingerprint));
+ assertFalse("Module checksum should verify number of tests",
+ mReporter.containsModuleResult(mModuleResult, fingerprint));
+ }
+
+ public void testFileSerialization() throws IOException, ChecksumValidationException {
+ mReporter.addInvocation(mInvocationResult);
+
+ File file1 = new File(mRoot, "file1.txt");
+ try (FileWriter fileWriter = new FileWriter(file1, false)) {
+ fileWriter.append("This is a test file");
+ }
+
+ mReporter.addDirectory(mRoot);
+ mReporter.saveToFile(mRoot);
+
+ ChecksumReporter storedChecksum = ChecksumReporter.load(mRoot);
+ VerifyInvocationResults(mInvocationResult, storedChecksum);
+ assertTrue("Serializing checksum maintains file hash",
+ storedChecksum.containsFile(file1, mRoot.getName()));
+ }
+
+ public void testFileCRCOperations() throws IOException {
+ File subDirectory = new File(mRoot, "child");
+ subDirectory.mkdir();
+ File file1 = new File(mRoot, "file1.txt");
+ try (FileWriter fileWriter = new FileWriter(file1, false)) {
+ fileWriter.append("This is a test file");
+ }
+
+ File file2 = new File(subDirectory, "file2.txt");
+ try (FileWriter fileWriter = new FileWriter(file2, false)) {
+ fileWriter.append("This is another test file with a different crc");
+ }
+
+ mReporter.addDirectory(mRoot);
+ String folderName = mRoot.getName();
+ assertTrue(mReporter.containsFile(file1, folderName));
+ assertTrue(mReporter.containsFile(file2, folderName + "/child"));
+ assertFalse("Should not contain non-existent file",
+ mReporter.containsFile(new File(mRoot, "fake.txt"), folderName));
+
+ File file3 = new File(mRoot, "file3.txt");
+ try (FileWriter fileWriter = new FileWriter(file3, false)) {
+ fileWriter.append("This is a test file added after crc calculated");
+ }
+ assertFalse("Should not contain file created after crc calculated",
+ mReporter.containsFile(file3, mRoot + "/"));
+
+ }
+
+ private void VerifyInvocationResults(IInvocationResult invocation, ChecksumReporter reporter) {
+ for (IModuleResult module : invocation.getModules()) {
+ String buildFingerprint = invocation.getBuildFingerprint();
+ assertTrue("Checksum should contain module: " + module.getName(),
+ reporter.containsModuleResult(module, buildFingerprint));
+ for (ICaseResult caseResult : module.getResults()) {
+ for (ITestResult result : caseResult.getResults()) {
+ assertTrue("Checksum should contain test: " + result.getName(),
+ reporter.containsTestResult(result, module, buildFingerprint));
+ }
+ }
+ }
+ }
+}
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 f48a403..84f9faf 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
@@ -26,7 +26,6 @@
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.config.OptionSetter;
-import com.android.tradefed.log.LogUtil.CLog;
import com.android.tradefed.util.AbiUtils;
import com.android.tradefed.util.FileUtil;
@@ -321,7 +320,6 @@
public void testCopyFormattingFiles() throws Exception {
File resultDir = new File(mBuildHelper.getResultsDir(), RESULT_DIR);
- CLog.e("%s", resultDir);
resultDir.mkdirs();
ResultReporter.copyFormattingFiles(resultDir);
for (String filename : FORMATTING_FILES) {
diff --git a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
index ae00eb4..e3240c1 100644
--- a/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
+++ b/common/host-side/tradefed/tests/src/com/android/compatibility/common/tradefed/result/SubPlanCreatorTest.java
@@ -94,8 +94,8 @@
optionParser.parse(Arrays.asList(
"-n", SP_NAME,
"--session", SP_SESSION,
- "-r", SP_RESULT_TYPE_FAILED,
- "-r", SP_RESULT_TYPE_NOT_EXECUTED));
+ "--result-type", SP_RESULT_TYPE_FAILED,
+ "--result-type", SP_RESULT_TYPE_NOT_EXECUTED));
}
@Override
diff --git a/common/host-side/util/Android.mk b/common/host-side/util/Android.mk
index 5f5fb6f..771e334 100644
--- a/common/host-side/util/Android.mk
+++ b/common/host-side/util/Android.mk
@@ -20,7 +20,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := compatibility-common-util-hostsidelib jsonlib
-LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := json-prebuilt tradefed
LOCAL_MODULE := compatibility-host-util
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java b/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
new file mode 100644
index 0000000..faac61f
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ChecksumReporter.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.util;
+
+import com.android.annotations.Nullable;
+
+import com.google.common.annotations.VisibleForTesting;
+import com.google.common.base.Joiner;
+import com.google.common.base.Strings;
+import com.google.common.hash.BloomFilter;
+import com.google.common.hash.Funnels;
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.ObjectInput;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutput;
+import java.io.ObjectOutputStream;
+import java.io.OutputStream;
+import java.io.Serializable;
+import java.security.DigestException;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+import java.util.HashMap;
+
+/***
+ * Calculate and store checksum values for files and test results
+ */
+public final class ChecksumReporter implements Serializable {
+
+ public static final String NAME = "checksum.data";
+ public static final String PREV_NAME = "checksum.previous.data";
+
+ private static final double DEFAULT_FPP = 0.05;
+ private static final String SEPARATOR = "/";
+ private static final String ID_SEPARATOR = "@";
+ private static final String NAME_SEPARATOR = ".";
+
+ private static final short CURRENT_VERSION = 1;
+ // Serialized format Id (ie magic number) used to identify serialized data.
+ static final short SERIALIZED_FORMAT_CODE = 650;
+
+ private final BloomFilter<CharSequence> mResultChecksum;
+ private final HashMap<String, byte[]> mFileChecksum;
+ private final short mVersion;
+
+ /***
+ * Calculate checksum of test results and files in result directory and write to disk
+ * @param dir test results directory
+ * @param result test results
+ * @return true if successful, false if unable to calculate or store the checksum
+ */
+ public static boolean tryCreateChecksum(File dir, IInvocationResult result) {
+ try {
+ int totalCount = countTestResults(result);
+ ChecksumReporter checksumReporter =
+ new ChecksumReporter(totalCount, DEFAULT_FPP, CURRENT_VERSION);
+ checksumReporter.addInvocation(result);
+ checksumReporter.addDirectory(dir);
+ checksumReporter.saveToFile(dir);
+ } catch (Exception e) {
+ return false;
+ }
+ return true;
+ }
+
+ /***
+ * Create Checksum Reporter from data saved on disk
+ * @param directory
+ * @return
+ * @throws ChecksumValidationException
+ */
+ public static ChecksumReporter load(File directory) throws ChecksumValidationException {
+ ChecksumReporter reporter = new ChecksumReporter(directory);
+ if (reporter.getCapacity() > 1.1) {
+ throw new ChecksumValidationException("Capacity exceeded.");
+ }
+ return reporter;
+ }
+
+ /***
+ * Deserialize checksum from file
+ * @param directory the parent directory containing the checksum file
+ * @throws ChecksumValidationException
+ */
+ public ChecksumReporter(File directory) throws ChecksumValidationException {
+ File file = new File(directory, ChecksumReporter.NAME);
+ try (FileInputStream fileStream = new FileInputStream(file);
+ InputStream outputStream = new BufferedInputStream(fileStream);
+ ObjectInput objectInput = new ObjectInputStream(outputStream)) {
+ short magicNumber = objectInput.readShort();
+ switch (magicNumber) {
+ case SERIALIZED_FORMAT_CODE:
+ mVersion = objectInput.readShort();
+ mResultChecksum = (BloomFilter<CharSequence>) objectInput.readObject();
+ mFileChecksum = (HashMap<String, byte[]>) objectInput.readObject();
+ break;
+ default:
+ throw new ChecksumValidationException("Unknown format of serialized data.");
+ }
+ } catch (Exception e) {
+ throw new ChecksumValidationException("Unable to load checksum from file", e);
+ }
+ if (mVersion > CURRENT_VERSION) {
+ throw new ChecksumValidationException(
+ "File contains a newer version of ChecksumReporter");
+ }
+ }
+
+ /***
+ * Create new instance of ChecksumReporter
+ * @param testCount the number of test results that will be stored
+ * @param fpp the false positive percentage for result lookup misses
+ */
+ public ChecksumReporter(int testCount, double fpp, short version) {
+ mResultChecksum = BloomFilter.create(Funnels.unencodedCharsFunnel(),
+ testCount, fpp);
+ mFileChecksum = new HashMap<>();
+ mVersion = version;
+ }
+
+ /***
+ * Add each test result from each module and test case
+ */
+ public void addInvocation(IInvocationResult invocationResult) {
+ for (IModuleResult module : invocationResult.getModules()) {
+ String buildFingerprint = invocationResult.getBuildFingerprint();
+ addModuleResult(module, buildFingerprint);
+ for (ICaseResult caseResult : module.getResults()) {
+ for (ITestResult testResult : caseResult.getResults()) {
+ addTestResult(testResult, module, buildFingerprint);
+ }
+ }
+ }
+ }
+
+ /***
+ * Calculate CRC of file and store the result
+ * @param file crc calculated on this file
+ * @param path part of the key to identify the files crc
+ */
+ public void addFile(File file, String path) {
+ byte[] crc;
+ try {
+ crc = calculateFileChecksum(file);
+ } catch (ChecksumValidationException e) {
+ crc = new byte[0];
+ }
+ String key = path + SEPARATOR + file.getName();
+ mFileChecksum.put(key, crc);
+ }
+
+ @VisibleForTesting
+ public boolean containsFile(File file, String path) {
+ String key = path + SEPARATOR + file.getName();
+ if (mFileChecksum.containsKey(key))
+ {
+ try {
+ byte[] crc = calculateFileChecksum(file);
+ return Arrays.equals(mFileChecksum.get(key), crc);
+ } catch (ChecksumValidationException e) {
+ return false;
+ }
+ }
+ return false;
+ }
+
+ /***
+ * Adds all child files recursively through all sub directories
+ * @param directory target that is deeply searched for files
+ */
+ public void addDirectory(File directory) {
+ addDirectory(directory, directory.getName());
+ }
+
+ /***
+ * @param path the relative path to the current directory from the base directory
+ */
+ private void addDirectory(File directory, String path) {
+ for(String childName : directory.list()) {
+ File child = new File(directory, childName);
+ if (child.isDirectory()) {
+ addDirectory(child, path + SEPARATOR + child.getName());
+ } else {
+ addFile(child, path);
+ }
+ }
+ }
+
+ /***
+ * Calculate checksum of test result and store the value
+ * @param testResult the target of the checksum
+ * @param moduleResult the module that contains the test result
+ * @param buildFingerprint the fingerprint the test execution is running against
+ */
+ public void addTestResult(
+ ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+ String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+ mResultChecksum.put(signature);
+ }
+
+ @VisibleForTesting
+ public boolean containsTestResult(
+ ITestResult testResult, IModuleResult moduleResult, String buildFingerprint) {
+
+ String signature = generateTestResultSignature(testResult, moduleResult, buildFingerprint);
+ return mResultChecksum.mightContain(signature);
+ }
+
+ /***
+ * Calculate checksm of module result and store value
+ * @param moduleResult the target of the checksum
+ * @param buildFingerprint the fingerprint the test execution is running against
+ */
+ public void addModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+ mResultChecksum.put(
+ generateModuleResultSignature(moduleResult, buildFingerprint));
+ mResultChecksum.put(
+ generateModuleSummarySignature(moduleResult, buildFingerprint));
+ }
+
+ @VisibleForTesting
+ public Boolean containsModuleResult(IModuleResult moduleResult, String buildFingerprint) {
+ return mResultChecksum.mightContain(
+ generateModuleResultSignature(moduleResult, buildFingerprint));
+ }
+
+ /***
+ * Write the checksum data to disk.
+ * Overwrites existing file
+ * @param directory
+ * @throws IOException
+ */
+ public void saveToFile(File directory) throws IOException {
+ File file = new File(directory, NAME);
+
+ try (FileOutputStream fileStream = new FileOutputStream(file, false);
+ OutputStream outputStream = new BufferedOutputStream(fileStream);
+ ObjectOutput objectOutput = new ObjectOutputStream(outputStream)) {
+ objectOutput.writeShort(SERIALIZED_FORMAT_CODE);
+ objectOutput.writeShort(mVersion);
+ objectOutput.writeObject(mResultChecksum);
+ objectOutput.writeObject(mFileChecksum);
+ }
+ }
+
+ @VisibleForTesting
+ double getCapacity() {
+ // If default FPP changes:
+ // increment the CURRENT_VERSION and set the denominator based on this.mVersion
+ return mResultChecksum.expectedFpp() / DEFAULT_FPP;
+ }
+
+ static String generateTestResultSignature(ITestResult testResult, IModuleResult module,
+ String buildFingerprint) {
+ StringBuilder sb = new StringBuilder();
+ String stacktrace = testResult.getStackTrace();
+
+ stacktrace = stacktrace == null ? "" : stacktrace.trim();
+ // Line endings for stacktraces are somewhat unpredictable and there is no need to
+ // actually read the result they are all removed for consistency.
+ stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+ sb.append(buildFingerprint).append(SEPARATOR)
+ .append(module.getId()).append(SEPARATOR)
+ .append(testResult.getFullName()).append(SEPARATOR)
+ .append(testResult.getResultStatus().getValue()).append(SEPARATOR)
+ .append(stacktrace).append(SEPARATOR);
+ return sb.toString();
+ }
+
+ static String generateTestResultSignature(
+ String packageName, String suiteName, String caseName, String testName, String abi,
+ String status,
+ String stacktrace,
+ String buildFingerprint) {
+
+ String testId = buildTestId(suiteName, caseName, testName, abi);
+ StringBuilder sb = new StringBuilder();
+
+ stacktrace = stacktrace == null ? "" : stacktrace.trim();
+ // Line endings for stacktraces are somewhat unpredictable and there is no need to
+ // actually read the result they are all removed for consistency.
+ stacktrace = stacktrace.replaceAll("\\r?\\n|\\r", "");
+ sb.append(buildFingerprint)
+ .append(SEPARATOR)
+ .append(packageName)
+ .append(SEPARATOR)
+ .append(testId)
+ .append(SEPARATOR)
+ .append(status)
+ .append(SEPARATOR)
+ .append(stacktrace)
+ .append(SEPARATOR);
+ return sb.toString();
+ }
+
+ private static String buildTestId(
+ String suiteName, String caseName, String testName, @Nullable String abi) {
+ String name = Joiner.on(NAME_SEPARATOR).skipNulls().join(
+ Strings.emptyToNull(suiteName),
+ Strings.emptyToNull(caseName),
+ Strings.emptyToNull(testName));
+ return Joiner.on(ID_SEPARATOR).skipNulls().join(
+ Strings.emptyToNull(name),
+ Strings.emptyToNull(abi));
+ }
+
+
+ private static String generateModuleResultSignature(IModuleResult module,
+ String buildFingerprint) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(buildFingerprint).append(SEPARATOR)
+ .append(module.getId()).append(SEPARATOR)
+ .append(module.isDone()).append(SEPARATOR)
+ .append(module.getNotExecuted()).append(SEPARATOR)
+ .append(module.countResults(TestStatus.FAIL));
+ return sb.toString();
+ }
+
+ private static String generateModuleSummarySignature(IModuleResult module,
+ String buildFingerprint) {
+ StringBuilder sb = new StringBuilder();
+ sb.append(buildFingerprint).append(SEPARATOR)
+ .append(module.getId()).append(SEPARATOR)
+ .append(module.countResults(TestStatus.FAIL));
+ return sb.toString();
+ }
+
+ static byte[] calculateFileChecksum(File file) throws ChecksumValidationException {
+
+ try (FileInputStream fis = new FileInputStream(file);
+ InputStream inputStream = new BufferedInputStream(fis)) {
+ MessageDigest hashSum = MessageDigest.getInstance("SHA-256");
+ int cnt;
+ int bufferSize = 8192;
+ byte [] buffer = new byte[bufferSize];
+ while ((cnt = inputStream.read(buffer)) != -1) {
+ hashSum.update(buffer, 0, cnt);
+ }
+
+ byte[] partialHash = new byte[32];
+ hashSum.digest(partialHash, 0, 32);
+ return partialHash;
+ } catch (NoSuchAlgorithmException e) {
+ throw new ChecksumValidationException("Unable to hash file.", e);
+ } catch (IOException e) {
+ throw new ChecksumValidationException("Unable to hash file.", e);
+ } catch (DigestException e) {
+ throw new ChecksumValidationException("Unable to hash file.", e);
+ }
+ }
+
+
+ private static int countTestResults(IInvocationResult invocation) {
+ int count = 0;
+ for (IModuleResult module : invocation.getModules()) {
+ // Two entries per module (result & summary)
+ count += 2;
+ for (ICaseResult caseResult : module.getResults()) {
+ count += caseResult.getResults().size();
+ }
+ }
+ return count;
+ }
+
+ public static class ChecksumValidationException extends Exception {
+ public ChecksumValidationException(String detailMessage) {
+ super(detailMessage);
+ }
+
+ public ChecksumValidationException(String detailMessage, Throwable throwable) {
+ super(detailMessage, throwable);
+ }
+ }
+}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java b/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
index 739dd48..96eca2d 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/IInvocationResult.java
@@ -114,4 +114,25 @@
* Return the number of completed test modules for this invocation.
*/
int getModuleCompleteCount();
+
+ /**
+ * Return status of checksum from previous session
+ */
+ RetryChecksumStatus getRetryChecksumStatus();
+
+ /**
+ * Set status of checksum from previous session
+ */
+ void setRetryChecksumStatus(RetryChecksumStatus retryStatus);
+
+ /**
+ * Return the directory of the previous sessions results
+ */
+ File getRetryDirectory();
+
+ /**
+ * Set the directory of the previous sessions results
+ */
+ void setRetryDirectory(File resultDir);
+
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java b/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
index f74c61d..c11c27d 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/InvocationResult.java
@@ -15,6 +15,7 @@
*/
package com.android.compatibility.common.util;
+import java.io.File;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -37,6 +38,8 @@
private String mTestPlan;
private String mCommandLineArgs;
private int mNotExecuted = 0;
+ private RetryChecksumStatus mRetryChecksumStatus = RetryChecksumStatus.NotRetry;
+ private File mRetryDirectory = null;
/**
* {@inheritDoc}
@@ -201,4 +204,36 @@
}
return completeModules;
}
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public RetryChecksumStatus getRetryChecksumStatus() {
+ return mRetryChecksumStatus;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setRetryChecksumStatus(RetryChecksumStatus retryStatus) {
+ mRetryChecksumStatus = retryStatus;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public File getRetryDirectory() {
+ return mRetryDirectory;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setRetryDirectory(File resultDir) {
+ mRetryDirectory = resultDir;
+ }
}
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
index 4a73d60..46fa9db 100644
--- a/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
+++ b/common/host-side/util/src/com/android/compatibility/common/util/ResultHandler.java
@@ -15,8 +15,11 @@
*/
package com.android.compatibility.common.util;
+import com.android.compatibility.common.util.ChecksumReporter.ChecksumValidationException;
import com.android.tradefed.util.AbiUtils;
+import com.google.common.base.Strings;
+
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;
@@ -30,9 +33,11 @@
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.nio.file.FileSystems;
+import java.nio.file.Files;
+import java.nio.file.Path;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
-import java.util.Comparator;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -97,26 +102,43 @@
private static final String SUMMARY_TAG = "Summary";
private static final String TEST_TAG = "Test";
+
/**
* @param resultsDir
*/
public static List<IInvocationResult> getResults(File resultsDir) {
+ return getResults(resultsDir, false);
+ }
+
+ /**
+ * @param resultsDir
+ * @param useChecksum
+ */
+ public static List<IInvocationResult> getResults(
+ File resultsDir, Boolean useChecksum) {
List<IInvocationResult> results = new ArrayList<>();
- File[] files = resultsDir.listFiles();
- if (files == null || files.length == 0) {
- // No results, just return the empty list
- return results;
- }
+ List<File> files = getResultDirectories(resultsDir);
+
for (File resultDir : files) {
- if (!resultDir.isDirectory()) {
- continue;
- }
try {
File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
if (!resultFile.exists()) {
continue;
}
+ Boolean invocationUseChecksum = useChecksum;
IInvocationResult invocation = new InvocationResult();
+ invocation.setRetryDirectory(resultDir);
+ ChecksumReporter checksumReporter = null;
+ if (invocationUseChecksum) {
+ try {
+ checksumReporter = ChecksumReporter.load(resultDir);
+ invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithChecksum);
+ } catch (ChecksumValidationException e) {
+ // Unable to read checksum form previous execution
+ invocation.setRetryChecksumStatus(RetryChecksumStatus.RetryWithoutChecksum);
+ invocationUseChecksum = false;
+ }
+ }
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser parser = factory.newPullParser();
parser.setInput(new FileReader(resultFile));
@@ -202,10 +224,22 @@
}
}
parser.require(XmlPullParser.END_TAG, NS, TEST_TAG);
+ Boolean checksumMismatch = invocationUseChecksum
+ && !checksumReporter.containsTestResult(
+ test, module, invocation.getBuildFingerprint());
+ if (checksumMismatch) {
+ test.removeResult();
+ }
}
parser.require(XmlPullParser.END_TAG, NS, CASE_TAG);
}
parser.require(XmlPullParser.END_TAG, NS, MODULE_TAG);
+ Boolean checksumMismatch = invocationUseChecksum
+ && !checksumReporter.containsModuleResult(
+ module, invocation.getBuildFingerprint());
+ if (checksumMismatch) {
+ module.setDone(false);
+ }
}
parser.require(XmlPullParser.END_TAG, NS, RESULT_TAG);
results.add(invocation);
@@ -218,11 +252,9 @@
}
}
// Sort the table entries on each entry's timestamp.
- Collections.sort(results, new Comparator<IInvocationResult>() {
- public int compare(IInvocationResult result1, IInvocationResult result2) {
- return Long.compare(result1.getStartTime(), result2.getStartTime());
- }
- });
+ Collections.sort(results, (result1, result2) -> Long.compare(
+ result1.getStartTime(),
+ result2.getStartTime()));
return results;
}
@@ -304,6 +336,10 @@
serializer.startTag(NS, BUILD_TAG);
for (Entry<String, String> entry : result.getInvocationInfo().entrySet()) {
serializer.attribute(NS, entry.getKey(), entry.getValue());
+ if (Strings.isNullOrEmpty(result.getBuildFingerprint()) &&
+ entry.getKey().equals(BUILD_FINGERPRINT)) {
+ result.setBuildFingerprint(entry.getValue());
+ }
}
serializer.endTag(NS, BUILD_TAG);
@@ -381,20 +417,60 @@
serializer.endTag(NS, MODULE_TAG);
}
serializer.endDocument();
+ createChecksum(resultDir, result);
return resultFile;
}
+ private static void createChecksum(File resultDir, IInvocationResult invocationResult) {
+ RetryChecksumStatus retryStatus = invocationResult.getRetryChecksumStatus();
+ switch (retryStatus) {
+ case NotRetry: case RetryWithChecksum:
+ // Do not disrupt the process if there is a problem generating checksum.
+ ChecksumReporter.tryCreateChecksum(resultDir, invocationResult);
+ break;
+ case RetryWithoutChecksum:
+ // If the previous run has an invalid checksum file,
+ // copy it into current results folder for future troubleshooting
+ File retryDirectory = invocationResult.getRetryDirectory();
+ Path retryChecksum = FileSystems.getDefault().getPath(
+ retryDirectory.getAbsolutePath(), ChecksumReporter.NAME);
+ if (!retryChecksum.toFile().exists()) {
+ // if no checksum file, check for a copy from a previous retry
+ retryChecksum = FileSystems.getDefault().getPath(
+ retryDirectory.getAbsolutePath(), ChecksumReporter.PREV_NAME);
+ }
+
+ if (retryChecksum.toFile().exists()) {
+ File checksumCopy = new File(resultDir, ChecksumReporter.PREV_NAME);
+ try (FileOutputStream stream = new FileOutputStream(checksumCopy)) {
+ Files.copy(retryChecksum, stream);
+ } catch (IOException e) {
+ // Do not disrupt the process if there is a problem copying checksum
+ }
+ }
+ }
+ }
+
+
/**
* Find the IInvocationResult for the given sessionId.
*/
public static IInvocationResult findResult(File resultsDir, Integer sessionId)
throws FileNotFoundException {
+ return findResult(resultsDir, sessionId, true);
+ }
+
+ /**
+ * Find the IInvocationResult for the given sessionId.
+ */
+ private static IInvocationResult findResult(
+ File resultsDir, Integer sessionId, Boolean useChecksum) throws FileNotFoundException {
if (sessionId < 0) {
throw new IllegalArgumentException(
String.format("Invalid session id [%d] ", sessionId));
}
- List<IInvocationResult> results = getResults(resultsDir);
+ List<IInvocationResult> results = getResults(resultsDir, useChecksum);
if (results == null || sessionId >= results.size()) {
throw new RuntimeException(String.format("Could not find session [%d]", sessionId));
}
@@ -402,6 +478,33 @@
}
/**
+ * Get a list of child directories that contain test invocation results
+ * @param resultsDir the root test result directory
+ * @return
+ */
+ public static List<File> getResultDirectories(File resultsDir) {
+ List<File> directoryList = new ArrayList<>();
+ File[] files = resultsDir.listFiles();
+ if (files == null || files.length == 0) {
+ // No results, just return the empty list
+ return directoryList;
+ }
+ for (File resultDir : files) {
+ if (!resultDir.isDirectory()) {
+ continue;
+ }
+ // Only include if it contain results file
+ File resultFile = new File(resultDir, TEST_RESULT_FILE_NAME);
+ if (!resultFile.exists()) {
+ continue;
+ }
+ directoryList.add(resultDir);
+ }
+ Collections.sort(directoryList, (d1, d2) -> d1.getName().compareTo(d2.getName()));
+ return directoryList;
+ }
+
+ /**
* Return the given time as a {@link String} suitable for displaying.
* <p/>
* Example: Fri Aug 20 15:13:03 PDT 2010
diff --git a/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java b/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java
new file mode 100644
index 0000000..a86ab37
--- /dev/null
+++ b/common/host-side/util/src/com/android/compatibility/common/util/RetryChecksumStatus.java
@@ -0,0 +1,8 @@
+package com.android.compatibility.common.util;
+
+
+public enum RetryChecksumStatus {
+ NotRetry,
+ RetryWithChecksum,
+ RetryWithoutChecksum
+}
diff --git a/common/host-side/util/tests/Android.mk b/common/host-side/util/tests/Android.mk
index 9bd3a4b..b5806c7 100644
--- a/common/host-side/util/tests/Android.mk
+++ b/common/host-side/util/tests/Android.mk
@@ -18,7 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := compatibility-host-util junit json-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util junit-host json-prebuilt tradefed
LOCAL_MODULE := compatibility-host-util-tests
diff --git a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
index 386a4ce..f2fa303 100644
--- a/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
+++ b/common/host-side/util/tests/src/com/android/compatibility/common/util/ResultHandlerTest.java
@@ -151,9 +151,7 @@
@Override
public void tearDown() throws Exception {
- if (resultsDir != null) {
- FileUtil.recursiveDelete(resultsDir);
- }
+ FileUtil.recursiveDelete(resultsDir);
}
public void testSerialization() throws Exception {
@@ -253,6 +251,7 @@
if (writer != null) {
writer.close();
}
+ FileUtil.recursiveDelete(resultsDir);
}
}
diff --git a/common/util/Android.mk b/common/util/Android.mk
index c95508b..faf4596 100644
--- a/common/util/Android.mk
+++ b/common/util/Android.mk
@@ -42,7 +42,7 @@
LOCAL_MODULE := compatibility-common-util-hostsidelib
-LOCAL_STATIC_JAVA_LIBRARIES := junit kxml2-2.3.0 platform-test-annotations-host
+LOCAL_STATIC_JAVA_LIBRARIES := junit-host kxml2-2.3.0 platform-test-annotations-host
include $(BUILD_HOST_JAVA_LIBRARY)
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 98d93c5..d5c95e8 100644
--- a/common/util/src/com/android/compatibility/common/util/ITestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/ITestResult.java
@@ -146,4 +146,8 @@
*/
boolean isRetry();
+ /**
+ * Clear the existing result and default to 'failed'
+ */
+ void removeResult();
}
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 c59ba1f..18a8b4c 100644
--- a/common/util/src/com/android/compatibility/common/util/TestResult.java
+++ b/common/util/src/com/android/compatibility/common/util/TestResult.java
@@ -255,6 +255,15 @@
* {@inheritDoc}
*/
@Override
+ public void removeResult() {
+ setResultStatus(TestStatus.FAIL);
+ setStackTrace("");
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
public int compareTo(ITestResult another) {
return getName().compareTo(another.getName());
}
diff --git a/common/util/tests/Android.mk b/common/util/tests/Android.mk
index 0e0af50..5e3370b 100644
--- a/common/util/tests/Android.mk
+++ b/common/util/tests/Android.mk
@@ -18,7 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := junit kxml2-2.3.0 tradefed-prebuilt compatibility-common-util-hostsidelib
+LOCAL_JAVA_LIBRARIES := junit-host kxml2-2.3.0 tradefed compatibility-common-util-hostsidelib
LOCAL_MODULE := compatibility-common-util-tests
diff --git a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
index cf1892a..df50d11 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/DynamicConfigTest.java
@@ -16,6 +16,8 @@
package com.android.compatibility.common.util;
+import com.android.tradefed.util.FileUtil;
+
import junit.framework.TestCase;
import org.xmlpull.v1.XmlPullParserException;
@@ -81,24 +83,28 @@
public void testCorrectConfig() throws Exception {
DynamicConfig config = new DynamicConfig();
File file = createFileFromStr(correctConfig);
- config.initializeConfig(file);
-
- assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
- assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
- assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
- assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
- assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+ try {
+ config.initializeConfig(file);
+ assertEquals("Wrong Config", config.getValue("test-config-1"), "test config 1");
+ assertEquals("Wrong Config", config.getValue("test-config-2"), "testconfig2");
+ assertEquals("Wrong Config List", config.getValues("config-list").get(0), "config0");
+ assertEquals("Wrong Config List", config.getValues("config-list").get(2), "config2");
+ assertEquals("Wrong Config List", config.getValues("config-list-2").get(2), "C");
+ } finally {
+ FileUtil.deleteFile(file);
+ }
}
public void testConfigWithWrongNodeName() throws Exception {
DynamicConfig config = new DynamicConfig();
File file = createFileFromStr(configWrongNodeName);
-
try {
config.initializeConfig(file);
fail("Cannot detect error when config file has wrong node name");
} catch (XmlPullParserException e) {
//expected
+ } finally {
+ FileUtil.deleteFile(file);
}
}
@@ -107,6 +113,7 @@
FileOutputStream stream = new FileOutputStream(file);
stream.write(configStr.getBytes());
stream.flush();
+ stream.close();
return file;
}
}
diff --git a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
index c8d4682..0da5f2d 100644
--- a/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
+++ b/common/util/tests/src/com/android/compatibility/common/util/ReportLogTest.java
@@ -20,9 +20,6 @@
import junit.framework.TestCase;
-import org.xmlpull.v1.XmlPullParserException;
-
-import java.util.List;
import java.util.Arrays;
/**
@@ -38,7 +35,8 @@
private static final String SUMMARY_XML =
HEADER_XML + "\r\n" +
"<Summary>\r\n" +
- " <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
+ " <Metric source=\"com.android.compatibility.common.util.ReportLogTest#%s\" "
+ + "message=\"Sample\" score_type=\"higher_better\" score_unit=\"byte\">\r\n" +
" <Value>1.0</Value>\r\n" +
" </Metric>\r\n" +
"</Summary>";
@@ -66,7 +64,7 @@
public void testSerialize_summaryOnly() throws Exception {
mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
- assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:68"),
+ assertEquals(String.format(SUMMARY_XML, "testSerialize_summaryOnly:66"),
ReportLog.serialize(mReportLog));
}
@@ -78,7 +76,7 @@
public void testSerialize_full() throws Exception {
mReportLog.setSummary("Sample", 1.0, ResultType.HIGHER_BETTER, ResultUnit.BYTE);
mReportLog.addValues("Details", VALUES, ResultType.NEUTRAL, ResultUnit.FPS);
- assertEquals(String.format(FULL_XML, "testSerialize_full:79"),
+ assertEquals(String.format(FULL_XML, "testSerialize_full:77"),
ReportLog.serialize(mReportLog));
}
diff --git a/hostsidetests/aadb/Android.mk b/hostsidetests/aadb/Android.mk
index f20f603..5cc2c10 100644
--- a/hostsidetests/aadb/Android.mk
+++ b/hostsidetests/aadb/Android.mk
@@ -22,7 +22,7 @@
# Adb test cases, but name 'aadb' ensures adb tests run before all other modules depending on adb
LOCAL_MODULE := CtsAadbHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.aadb
diff --git a/hostsidetests/abioverride/Android.mk b/hostsidetests/abioverride/Android.mk
index f77303b..88c44d9 100644
--- a/hostsidetests/abioverride/Android.mk
+++ b/hostsidetests/abioverride/Android.mk
@@ -27,9 +27,7 @@
LOCAL_CTS_TEST_PACKAGE := android.host.abioverride
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
index 26d35a4..c2f14f0 100644
--- a/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
+++ b/hostsidetests/abioverride/src/android/abioverride/cts/AbiOverrideTest.java
@@ -16,7 +16,7 @@
package android.abioverride.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -72,7 +72,8 @@
super.setUp();
ITestDevice device = getDevice();
device.uninstallPackage(PACKAGE);
- File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ File app = buildHelper.getTestFile(APK_NAME);
String[] options = {};
device.installPackage(app, false, options);
}
diff --git a/hostsidetests/appsecurity/Android.mk b/hostsidetests/appsecurity/Android.mk
index 258192d..6afcce8 100644
--- a/hostsidetests/appsecurity/Android.mk
+++ b/hostsidetests/appsecurity/Android.mk
@@ -21,9 +21,7 @@
LOCAL_MODULE := CtsAppSecurityHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_JAVA_RESOURCE_DIRS := res
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
index 1032c62..881f5b8b 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AdoptableHostTest.java
@@ -24,7 +24,6 @@
import static android.appsecurity.cts.SplitTests.PKG;
import android.appsecurity.cts.SplitTests.BaseInstallMultiple;
-import com.android.cts.migration.MigrationHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -293,8 +292,18 @@
}
private String getAdoptionDisk() throws Exception {
- final String disks = getDevice().executeShellCommand("sm list-disks adoptable");
- if (disks == null || disks.length() == 0) {
+ // In the case where we run multiple test we cleanup the state of the device. This
+ // results in the execution of sm forget all which causes the MountService to "reset"
+ // all its knowledge about available drives. This can cause the adoptable drive to
+ // become temporarily unavailable.
+ int attempt = 0;
+ String disks = getDevice().executeShellCommand("sm list-disks adoptable");
+ while ((disks == null || disks.isEmpty()) && attempt++ < 15) {
+ Thread.sleep(1000);
+ disks = getDevice().executeShellCommand("sm list-disks adoptable");
+ }
+
+ if (disks == null || disks.isEmpty()) {
throw new AssertionError("Devices that claim to support adoptable storage must have "
+ "adoptable media inserted during CTS to verify correct behavior");
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
index e6f6a6d..36b0921 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/AppSecurityTests.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -103,7 +103,8 @@
}
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return MigrationHelper.getTestFile(mCtsBuild, fileName);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ return buildHelper.getTestFile(fileName);
}
@Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
index 3c6cac5..a064287 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTest.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
/**
* Set of tests that verify behavior of
@@ -31,9 +31,8 @@
super.setUp();
getDevice().uninstallPackage(PROVIDER_PKG);
-
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, PROVIDER_APK), false));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ assertNull(getDevice().installPackage(buildHelper.getTestFile(PROVIDER_APK), false));
}
@Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
index 009d81b..ceb7539 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/DocumentsTestCase.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -68,8 +68,7 @@
protected void reinstallClientPackage() throws Exception {
getDevice().uninstallPackage(CLIENT_PKG);
-
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, CLIENT_APK), false));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ assertNull(getDevice().installPackage(buildHelper.getTestFile(CLIENT_APK), false));
}
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 65e8a03..ed46225 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -66,7 +66,8 @@
}
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return MigrationHelper.getTestFile(mCtsBuild, fileName);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ return buildHelper.getTestFile(fileName);
}
@Override
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
index 53a54dd..1f7c6be 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/KeySetHostTest.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
@@ -101,7 +101,8 @@
private static final String LOG_TAG = "AppsecurityHostTests";
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return MigrationHelper.getTestFile(mCtsBuild, fileName);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ return buildHelper.getTestFile(fileName);
}
/**
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
index 072a533..0e53c46 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PermissionsHostTest.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
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 APK_24 = "CtsUsePermissionApp24.apk";
private IAbi mAbi;
- private IBuildInfo mCtsBuild;
+ private CompatibilityBuildHelper mBuildHelper;
@Override
public void setAbi(IAbi abi) {
@@ -45,7 +45,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@Override
@@ -53,7 +53,7 @@
super.setUp();
assertNotNull(mAbi);
- assertNotNull(mCtsBuild);
+ assertNotNull(mBuildHelper);
getDevice().uninstallPackage(PKG);
}
@@ -67,8 +67,7 @@
public void testFail() throws Exception {
// Sanity check that remote failure is host failure
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testFail");
@@ -79,8 +78,7 @@
public void testKill() throws Exception {
// Sanity check that remote kill is host failure
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testKill");
@@ -90,17 +88,13 @@
}
public void testCompatDefault22() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22),
- false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
"testCompatDefault");
}
public void testCompatRevoked22() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22),
- false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
"testCompatRevoked_part1");
@@ -112,72 +106,61 @@
}
public void testNoRuntimePrompt22() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22),
- false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
"testNoRuntimePrompt");
}
public void testDefault23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testDefault");
}
public void testGranted23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testGranted");
}
public void testInteractiveGrant23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testInteractiveGrant");
}
public void testRuntimeGroupGrantSpecificity23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRuntimeGroupGrantSpecificity");
}
public void testRuntimeGroupGrantExpansion23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRuntimeGroupGrantExpansion");
}
public void testCancelledPermissionRequest23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testCancelledPermissionRequest");
}
public void testRequestGrantedPermission23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRequestGrantedPermission");
}
public void testDenialWithPrejudice23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testDenialWithPrejudice");
}
public void testRevokeAffectsWholeGroup23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRevokeAffectsWholeGroup_part1");
@@ -188,8 +171,7 @@
}
public void testGrantPreviouslyRevokedWithPrejudiceShowsPrompt23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testGrantPreviouslyRevokedWithPrejudiceShowsPrompt_part1");
@@ -201,89 +183,75 @@
}
public void testRequestNonRuntimePermission23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRequestNonRuntimePermission");
}
public void testRequestNonExistentPermission23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRequestNonExistentPermission");
}
public void testRequestPermissionFromTwoGroups23() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRequestPermissionFromTwoGroups");
}
// public void testOnlyRequestedPermissionsGranted24() throws Exception {
-// assertNull(getDevice().installPackage(
-// MigrationHelper.getTestFile(mCtsBuild, APK_24), false, false));
+// assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_24), false, false));
// runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest24",
// "testOnlyRequestedPermissionsGranted");
// }
public void testUpgradeKeepsPermissions() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
"testAllPermissionsGrantedByDefault");
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testAllPermissionsGrantedOnUpgrade");
}
public void testNoDowngradePermissionModel() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
try {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22), true, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), true, false));
fail("Permission mode downgrade not allowed");
} catch (AssertionError expected) {
}
}
public void testNoResidualPermissionsOnUninstall() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testNoResidualPermissionsOnUninstall_part1");
assertNull(getDevice().uninstallPackage(PKG));
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testNoResidualPermissionsOnUninstall_part2");
}
public void testRevokePropagatedOnUpgradeOldToNewModel() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_22), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_22), false, false));
try {
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest22",
"testRevokePropagatedOnUpgradeOldToNewModel_part1");
fail("App must be killed on a permission revoke");
} catch (AssertionError expected) {
}
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRevokePropagatedOnUpgradeOldToNewModel_part2");
}
public void testRevokePropagatedOnUpgradeNewToNewModel() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), false, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRevokePropagatedOnUpgradeNewToNewModel_part1");
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK_23), true, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK_23), true, false));
runDeviceTests(PKG, "com.android.cts.usepermission.UsePermissionTest23",
"testRevokePropagatedOnUpgradeNewToNewModel_part2");
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
index 53d3066..ca218ef 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/PrivilegedUpdateTests.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -47,7 +47,7 @@
+ " com.android.cts.priv.ctsshim";
private IAbi mAbi;
- private IBuildInfo mCtsBuild;
+ private CompatibilityBuildHelper mBuildHelper;
@Override
public void setAbi(IAbi abi) {
@@ -56,7 +56,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@Override
@@ -64,13 +64,12 @@
super.setUp();
assertNotNull(mAbi);
- assertNotNull(mCtsBuild);
+ assertNotNull(mBuildHelper);
getDevice().uninstallPackage(SHIM_PKG);
getDevice().uninstallPackage(TEST_PKG);
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, TEST_APK), false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(TEST_APK), false));
getDevice().executeShellCommand("pm enable " + SHIM_PKG);
}
@@ -86,7 +85,7 @@
public void testPrivilegedAppUpgradeRestricted() throws Exception {
getDevice().uninstallPackage(SHIM_PKG);
assertEquals(RESTRICTED_UPGRADE_FAILURE, getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_FAIL_APK), true));
+ mBuildHelper.getTestFile(SHIM_UPDATE_FAIL_APK), true));
}
public void testSystemAppPriorities() throws Exception {
@@ -102,7 +101,7 @@
try {
assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+ mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
runDeviceTests(TEST_PKG, ".PrivilegedUpdateTest", "testPrivilegedAppUpgradePriorities");
} finally {
getDevice().uninstallPackage(SHIM_PKG);
@@ -121,7 +120,7 @@
runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testPrivAppAndEnabled");
try {
assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, SHIM_UPDATE_APK), true));
+ mBuildHelper.getTestFile(SHIM_UPDATE_APK), true));
getDevice().executeShellCommand("pm disable-user " + SHIM_PKG);
runDeviceTests(TEST_PKG, ".PrivilegedAppDisableTest", "testUpdatedPrivAppAndDisabled");
getDevice().executeShellCommand("pm enable " + SHIM_PKG);
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
index 86cc8e8..00ccd4c 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/SplitTests.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -334,7 +334,8 @@
}
T addApk(String apk) throws FileNotFoundException {
- mApks.add(MigrationHelper.getTestFile(mBuild, apk));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ mApks.add(buildHelper.getTestFile(apk));
return (T) this;
}
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
index c8e608e..cf8a354 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/UsesLibraryHostTest.java
@@ -16,7 +16,7 @@
package android.appsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
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 = "CtsUsesLibraryAppCompat.apk";
private IAbi mAbi;
- private IBuildInfo mCtsBuild;
+ private CompatibilityBuildHelper mBuildHelper;
@Override
public void setAbi(IAbi abi) {
@@ -44,7 +44,7 @@
@Override
public void setBuild(IBuildInfo buildInfo) {
- mCtsBuild = buildInfo;
+ mBuildHelper = new CompatibilityBuildHelper(buildInfo);
}
@Override
@@ -52,7 +52,7 @@
super.setUp();
assertNotNull(mAbi);
- assertNotNull(mCtsBuild);
+ assertNotNull(mBuildHelper);
getDevice().uninstallPackage(PKG);
}
@@ -65,20 +65,17 @@
}
public void testUsesLibrary() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
runDeviceTests(PKG, ".UsesLibraryTest", "testUsesLibrary");
}
public void testMissingLibrary() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
runDeviceTests(PKG, ".UsesLibraryTest", "testMissingLibrary");
}
public void testDuplicateLibrary() throws Exception {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuild, APK), false, false));
+ assertNull(getDevice().installPackage(mBuildHelper.getTestFile(APK), false, false));
runDeviceTests(PKG, ".UsesLibraryTest", "testDuplicateLibrary");
}
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
index 69fc9e9..f2b1eda 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionApp23/src/com/android/cts/usepermission/BasePermissionsTest.java
@@ -433,6 +433,7 @@
(AccessibilityEvent event) -> event.getEventType()
== AccessibilityEvent.TYPE_VIEW_SCROLLED,
GLOBAL_TIMEOUT_MILLIS);
+ node.refresh();
waitForIdle();
}
diff --git a/hostsidetests/atrace/Android.mk b/hostsidetests/atrace/Android.mk
index d0b7ef5..c4a0913 100644
--- a/hostsidetests/atrace/Android.mk
+++ b/hostsidetests/atrace/Android.mk
@@ -21,9 +21,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsAtraceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.host.atrace
diff --git a/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java b/hostsidetests/atrace/src/android/atrace/cts/AtraceHostTest.java
index 4fc041c..3ab7d95 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.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
@@ -201,7 +201,8 @@
getDevice().uninstallPackage(TEST_PKG);
// install the test app
- File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ File testAppFile = buildHelper.getTestFile(TEST_APK);
String installResult = getDevice().installPackage(testAppFile, false);
assertNull(
String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/compilation/Android.mk b/hostsidetests/compilation/Android.mk
index 64e7063..723e5c3 100644
--- a/hostsidetests/compilation/Android.mk
+++ b/hostsidetests/compilation/Android.mk
@@ -27,7 +27,7 @@
LOCAL_MODULE := CtsCompilationTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_STATIC_JAVA_LIBRARIES := guavalib
diff --git a/hostsidetests/compilation/assets/primary.prof b/hostsidetests/compilation/assets/primary.prof
index dbd70c7..18792ba 100644
--- a/hostsidetests/compilation/assets/primary.prof
+++ b/hostsidetests/compilation/assets/primary.prof
Binary files differ
diff --git a/hostsidetests/cpptools/Android.mk b/hostsidetests/cpptools/Android.mk
index 2c1f697..67acb25 100644
--- a/hostsidetests/cpptools/Android.mk
+++ b/hostsidetests/cpptools/Android.mk
@@ -23,7 +23,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsCppToolsTestCases
-LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := ddmlib-prebuilt tradefed
LOCAL_CTS_TEST_PACKAGE := android.tests.cpptools
diff --git a/hostsidetests/devicepolicy/Android.mk b/hostsidetests/devicepolicy/Android.mk
index d6fb30b..1828e2c 100644
--- a/hostsidetests/devicepolicy/Android.mk
+++ b/hostsidetests/devicepolicy/Android.mk
@@ -22,9 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.adminhostside
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
new file mode 100644
index 0000000..9b3daed
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/Android.mk
@@ -0,0 +1,71 @@
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# IMPORTANT: We build two apps from the same source but with different package name.
+# This allow us to have different device owner and profile owner, some APIs may behave differently
+# in this situation.
+
+# === App 1 ===
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+include $(BUILD_CTS_PACKAGE)
+
+# === App 2 ===
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := CtsCorpOwnedManagedProfile2
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_AIDL_INCLUDES := $(LOCAL_PATH)/src
+
+LOCAL_JAVA_LIBRARIES := android.test.runner cts-junit
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctstestrunner ctsdeviceutil compatibility-device-util
+
+LOCAL_SDK_VERSION := test_current
+
+# tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+LOCAL_AAPT_FLAGS += --rename-manifest-package com.android.cts.comp2 \
+ --rename-instrumentation-target-package com.android.cts.comp2
+
+include $(BUILD_CTS_PACKAGE)
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
new file mode 100644
index 0000000..3924d84
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.cts.comp" >
+ <!-- package="com.android.cts.comp2"
+ We have com.android.cts.comp2 that have the exact same source but with different package
+ name, see Android.mk for details. -->
+ <application
+ android:testOnly="true">
+
+ <uses-library android:name="android.test.runner" />
+ <receiver
+ android:name="com.android.cts.comp.AdminReceiver"
+ android:exported="false"
+ 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>
+
+ <service android:name=".CrossUserService"
+ android:exported="false">
+ </service>
+
+ <service android:name=".ExportedCrossUserService"
+ android:exported="true">
+ </service>
+ </application>
+
+ <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+ android:targetPackage="com.android.cts.comp"
+ android:label="Corp owned managed profile CTS tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
new file mode 100644
index 0000000..ff086d6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/res/xml/device_admin.xml
@@ -0,0 +1,4 @@
+<device-admin xmlns:android="http://schemas.android.com/apk/res/android" android:visible="false">
+ <uses-policies>
+ </uses-policies>
+</device-admin>
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
new file mode 100644
index 0000000..ad52708
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/AdminReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.app.admin.DeviceAdminReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+
+public class AdminReceiver extends DeviceAdminReceiver {
+ // These two apps are built with this source.
+ public static final String COMP_DPC_PACKAGE_NAME = "com.android.cts.comp";
+ public static final String COMP_DPC_2_PACKAGE_NAME = "com.android.cts.comp2";
+
+ public static ComponentName getComponentName(Context context) {
+ return new ComponentName(context, AdminReceiver.class);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java
new file mode 100644
index 0000000..8e1f0e6
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseDeviceOwnerCompTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for device-owner based tests.
+ */
+public abstract class BaseDeviceOwnerCompTest extends AndroidTestCase {
+
+ protected DevicePolicyManager mDevicePolicyManager;
+ protected List<UserHandle> mOtherProfiles;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ assertDeviceOwner(mDevicePolicyManager);
+
+ // A managed profile must have been created.
+ mOtherProfiles = mContext.getSystemService(UserManager.class)
+ .getUserProfiles();
+ mOtherProfiles.remove(Process.myUserHandle());
+ assertTrue(mOtherProfiles.size() > 0);
+ }
+
+ private void assertDeviceOwner(DevicePolicyManager dpm) {
+ assertNotNull(dpm);
+ assertTrue(dpm.isAdminActive(AdminReceiver.getComponentName(getContext())));
+ assertTrue(dpm.isDeviceOwnerApp(getContext().getPackageName()));
+ assertFalse(dpm.isManagedProfile(AdminReceiver.getComponentName(getContext())));
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
new file mode 100644
index 0000000..6a3eb05
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/BaseManagedProfileCompTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.os.Process;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.test.AndroidTestCase;
+
+import java.util.List;
+
+/**
+ * Base class for profile-owner based tests.
+ * <p>
+ * This class handles making sure that the test is the profile owner and that it has an active admin
+ * registered, so that all tests may assume these are done.
+ */
+public class BaseManagedProfileCompTest extends AndroidTestCase {
+
+ protected DevicePolicyManager mDevicePolicyManager;
+ protected List<UserHandle> mOtherProfiles;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+
+ mDevicePolicyManager = (DevicePolicyManager)
+ mContext.getSystemService(Context.DEVICE_POLICY_SERVICE);
+ assertManagedProfile();
+
+ mOtherProfiles = mContext.getSystemService(UserManager.class)
+ .getUserProfiles();
+ mOtherProfiles.remove(Process.myUserHandle());
+ assertTrue(mOtherProfiles.size() > 0); // The primary profile should be there.
+ }
+
+ private void assertManagedProfile() {
+ assertNotNull(mDevicePolicyManager);
+ assertTrue(mDevicePolicyManager.isAdminActive(
+ AdminReceiver.getComponentName(getContext())));
+ assertTrue(mDevicePolicyManager.isProfileOwnerApp(getContext().getPackageName()));
+ assertTrue(mDevicePolicyManager.isManagedProfile(
+ AdminReceiver.getComponentName(getContext())));
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java
new file mode 100644
index 0000000..3b95b94
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/CrossUserService.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.UserHandle;
+
+/**
+ * Handle the cross user call from the device admin in other side.
+ */
+public class CrossUserService extends Service {
+
+ private final ICrossUserService.Stub mBinder = new ICrossUserService.Stub() {
+ public String echo(String msg) {
+ return msg;
+ }
+
+ public UserHandle getUserHandle() {
+ return Process.myUserHandle();
+ }
+ };
+
+ @Override
+ public IBinder onBind(Intent intent) {
+ return mBinder;
+ }
+
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..935a657
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/DeviceOwnerBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a device owner tries to bind a service from profile owner.
+ */
+public class DeviceOwnerBindDeviceAdminServiceTest extends BaseDeviceOwnerCompTest {
+
+ public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+ assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+ // COMP mode - DO should be allowed to bind to the managed profile user.
+ List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+ AdminReceiver.getComponentName(mContext));
+ assertEquals(1, allowedTargetUsers.size());
+ UserHandle managedProfileUserHandle = allowedTargetUsers.get(0);
+ assertTrue(mOtherProfiles.contains(managedProfileUserHandle));
+
+ new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+ mContext, managedProfileUserHandle)
+ .execute();
+ }
+
+ public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+ assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+ // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+ List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+ AdminReceiver.getComponentName(mContext));
+ assertEquals(0, allowedTargetUsers.size());
+
+ for (UserHandle userHandle : mOtherProfiles) {
+ new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+ mContext, userHandle, AdminReceiver.COMP_DPC_2_PACKAGE_NAME)
+ .execute();
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
new file mode 100644
index 0000000..e7a9e73
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ExportedCrossUserService.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+/**
+ * Dummy service that is exported.
+ */
+public class ExportedCrossUserService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ return null;
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
new file mode 100644
index 0000000..bc8d3d3
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ICrossUserService.aidl
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+interface ICrossUserService {
+ String echo(String msg);
+ android.os.UserHandle getUserHandle();
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
new file mode 100644
index 0000000..e301a4f
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/ManagedProfileBindDeviceAdminServiceTest.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp;
+
+import android.os.UserHandle;
+
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite;
+import com.android.cts.comp.bindservice.BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite;
+
+import java.util.List;
+
+/**
+ * Testing various scenarios when a profile owner from the managed profile tries to bind a service
+ * from the device owner.
+ */
+public class ManagedProfileBindDeviceAdminServiceTest extends BaseManagedProfileCompTest {
+
+ public void testBindDeviceAdminServiceForUser_corpOwnedManagedProfile() throws Exception {
+ assertEquals(AdminReceiver.COMP_DPC_PACKAGE_NAME, mContext.getPackageName());
+
+ // COMP mode - Managed Profile PO should be allowed to bind to the DO.
+ List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+ AdminReceiver.getComponentName(mContext));
+ assertEquals(1, allowedTargetUsers.size());
+ UserHandle primaryProfileUserHandle = allowedTargetUsers.get(0);
+ assertTrue(mOtherProfiles.contains(primaryProfileUserHandle));
+
+ new BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+ mContext, primaryProfileUserHandle).execute();
+ }
+
+ public void testBindDeviceAdminServiceForUser_byodPlusDeviceOwner() throws Exception {
+ assertEquals(AdminReceiver.COMP_DPC_2_PACKAGE_NAME, mContext.getPackageName());
+
+ // DO+BYOD mode - the DO and the PO should not be allowed to bind to each other.
+ List<UserHandle> allowedTargetUsers = mDevicePolicyManager.getBindDeviceAdminTargetUsers(
+ AdminReceiver.getComponentName(mContext));
+ assertEquals(0, allowedTargetUsers.size());
+
+ for (UserHandle userHandle : mOtherProfiles) {
+ new BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+ mContext, userHandle, AdminReceiver.COMP_DPC_PACKAGE_NAME)
+ .execute();
+ }
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
new file mode 100644
index 0000000..fe739c1
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case that device owner and profile owner are different packages.
+ */
+public class BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite {
+
+ private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+
+ private final Context mContext;
+ private final DevicePolicyManager mDpm;
+ private final String mDpcPackageInOtherSide;
+ private final UserHandle mTargetUserHandle;
+
+ /**
+ * @param context
+ * @param targetUserHandle Which user are we talking to.
+ * @param dpcPackageInOtherSide The dpc package installed in other side, it must not be this
+ * package.
+ */
+ public BindDeviceAdminServiceByodPlusDeviceOwnerTestSuite(
+ Context context, UserHandle targetUserHandle, String dpcPackageInOtherSide) {
+ MoreAsserts.assertNotEqual(context.getPackageName(), dpcPackageInOtherSide);
+ mContext = context;
+ mDpm = mContext.getSystemService(DevicePolicyManager.class);
+ mDpcPackageInOtherSide = dpcPackageInOtherSide;
+ mTargetUserHandle = targetUserHandle;
+ }
+
+ public void execute() throws Exception {
+ checkCannotBind_deviceOwnerProfileOwnerDifferentPackage();
+ checkCannotBind_talkToNonManagingPackage();
+ }
+
+ /**
+ * Device owner and profile owner try to talk to each other. It should fail as they are
+ * different packages.
+ */
+ private void checkCannotBind_deviceOwnerProfileOwnerDifferentPackage() throws Exception {
+ try {
+ final Intent serviceIntent = new Intent();
+ serviceIntent.setClassName(mDpcPackageInOtherSide, CrossUserService.class.getName());
+ bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+ fail("SecurityException should be thrown");
+ } catch (SecurityException ex) {
+ MoreAsserts.assertContainsRegex(
+ "Not allowed to bind to target user id", ex.getMessage());
+ }
+ }
+
+ /**
+ * Talk to our own instance in other end. It should fail as it is not the same app that
+ * is managing that profile.
+ */
+ private void checkCannotBind_talkToNonManagingPackage() throws Exception {
+ try {
+ final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+ bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+ fail("SecurityException should be thrown");
+ } catch (SecurityException ex) {
+ MoreAsserts.assertContainsRegex(
+ "Not allowed to bind to target user id", ex.getMessage());
+ }
+ }
+
+ private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+ UserHandle userHandle) {
+ return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+ serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
new file mode 100644
index 0000000..ce9efcf
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CorpOwnedManagedProfile/src/com/android/cts/comp/bindservice/BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite.java
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.comp.bindservice;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.test.MoreAsserts;
+import android.util.Log;
+
+import com.android.cts.comp.AdminReceiver;
+import com.android.cts.comp.CrossUserService;
+import com.android.cts.comp.ExportedCrossUserService;
+import com.android.cts.comp.ICrossUserService;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+/**
+ * Test suite for the case where we have the same package for both device owner and profile owner.
+ */
+public class BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite {
+ private static final String TAG = "BindServiceTest";
+
+ private static final ServiceConnection EMPTY_SERVICE_CONNECTION = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {}
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {}
+ };
+
+ private final Context mContext;
+ private static final String NON_MANAGING_PACKAGE = AdminReceiver.COMP_DPC_2_PACKAGE_NAME;
+ private final UserHandle mTargetUserHandle;
+ private final DevicePolicyManager mDpm;
+
+ /**
+ * @param context
+ * @param targetUserHandle Which user we are talking to.
+ */
+ public BindDeviceAdminServiceCorpOwnedManagedProfileTestSuite(
+ Context context, UserHandle targetUserHandle) {
+ mContext = context;
+ mTargetUserHandle = targetUserHandle;
+ mDpm = mContext.getSystemService(DevicePolicyManager.class);
+ }
+
+ public void execute() throws Exception {
+ checkCannotBind_exportedCrossUserService();
+ checkCannotBind_nonManagingPackage();
+ checkCannotBind_sameUser();
+ checkCrossProfileCall_echo();
+ checkCrossProfileCall_getUserHandle();
+ }
+
+ /**
+ * Make sure we cannot bind exported service.
+ */
+ private void checkCannotBind_exportedCrossUserService() throws Exception {
+ try {
+ final Intent serviceIntent = new Intent(mContext, ExportedCrossUserService.class);
+ bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+ fail("SecurityException should be thrown");
+ } catch (SecurityException ex) {
+ MoreAsserts.assertContainsRegex("Invalid intent", ex.getMessage());
+ }
+ }
+
+ /**
+ * Talk to a DPC package that is neither device owner nor profile owner.
+ */
+ private void checkCannotBind_nonManagingPackage() throws Exception {
+ try {
+ final Intent serviceIntent = new Intent();
+ serviceIntent.setClassName(NON_MANAGING_PACKAGE, CrossUserService.class.getName());
+ bind(serviceIntent, EMPTY_SERVICE_CONNECTION, mTargetUserHandle);
+ fail("SecurityException should be thrown");
+ } catch (SecurityException ex) {
+ MoreAsserts.assertContainsRegex("Invalid intent", ex.getMessage());
+ }
+ }
+
+ /**
+ * Talk to the same DPC in same user, that is talking to itself.
+ */
+ private void checkCannotBind_sameUser() throws Exception {
+ try {
+ final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+ bind(serviceIntent, EMPTY_SERVICE_CONNECTION, Process.myUserHandle());
+ fail("IllegalArgumentException should be thrown");
+ } catch (IllegalArgumentException ex) {
+ MoreAsserts.assertContainsRegex("target user id must be different", ex.getMessage());
+ }
+ }
+
+ /**
+ * Send a String to other side and expect the exact same string is echoed back.
+ */
+ private void checkCrossProfileCall_echo() throws Exception {
+ final String ANSWER = "42";
+ assertCrossProfileCall(ANSWER, service -> service.echo(ANSWER), mTargetUserHandle);
+ }
+
+ /**
+ * Make sure we are talking to the target user.
+ */
+ private void checkCrossProfileCall_getUserHandle() throws Exception {
+ assertCrossProfileCall(
+ mTargetUserHandle, service -> service.getUserHandle(), mTargetUserHandle);
+ }
+
+ /**
+ * Convenient method for you to execute a cross user call and assert the return value of it.
+ * @param expected The expected result of the cross user call.
+ * @param callable It is called when the service is bound, use this to make the service call.
+ * @param targetUserHandle Which user are we talking to.
+ * @param <T> The return type of the service call.
+ */
+ private <T> void assertCrossProfileCall(
+ T expected, CrossUserCallable<T> callable, UserHandle targetUserHandle)
+ throws Exception {
+ final LinkedBlockingQueue<ICrossUserService> queue
+ = new LinkedBlockingQueue<ICrossUserService>();
+ final ServiceConnection serviceConnection = new ServiceConnection() {
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ Log.d(TAG, "onServiceConnected is called");
+ queue.add(ICrossUserService.Stub.asInterface(service));
+ }
+
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ Log.d(TAG, "onServiceDisconnected is called");
+ }
+ };
+ final Intent serviceIntent = new Intent(mContext, CrossUserService.class);
+ assertTrue(bind(serviceIntent, serviceConnection, targetUserHandle));
+ ICrossUserService service = queue.poll(5, TimeUnit.SECONDS);
+ assertNotNull("binding to the target service timed out", service);
+ try {
+ assertEquals(expected, callable.call(service));
+ } finally {
+ mContext.unbindService(serviceConnection);
+ }
+ }
+
+ private boolean bind(Intent serviceIntent, ServiceConnection serviceConnection,
+ UserHandle userHandle) {
+ return mDpm.bindDeviceAdminServiceAsUser(AdminReceiver.getComponentName(mContext),
+ serviceIntent, serviceConnection, Context.BIND_AUTO_CREATE, userHandle);
+ }
+
+ interface CrossUserCallable<T> {
+ T call(ICrossUserService service) throws RemoteException;
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
index 41bb626..91b710e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/vpn/VpnTestHelper.java
@@ -61,6 +61,9 @@
// IP address reserved for documentation by rfc5737
public static final String TEST_ADDRESS = "192.0.2.4";
+ // HACK (TODO issue 31585407) to wait for the network to actually be usable
+ private static final int NETWORK_SETTLE_GRACE_MS = 200;
+
private static final int SOCKET_TIMEOUT_MS = 5000;
private static final int ICMP_ECHO_REQUEST = 0x08;
private static final int ICMP_ECHO_REPLY = 0x00;
@@ -92,6 +95,7 @@
if (!vpnLatch.await(NETWORK_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
fail("Took too long waiting to establish a VPN-backed connection");
}
+ Thread.sleep(NETWORK_SETTLE_GRACE_MS);
} catch (InterruptedException | PackageManager.NameNotFoundException e) {
fail("Failed to send ping: " + e);
} finally {
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
new file mode 100644
index 0000000..06873fe
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/AdminActionBookkeepingTest.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.deviceowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+
+import java.lang.reflect.Method;
+
+public class AdminActionBookkeepingTest extends BaseDeviceOwnerTest {
+
+ /**
+ * Test: Retrieving security logs should update the corresponding timestamp.
+ */
+ public void testRetrieveSecurityLogs() throws Exception {
+ Thread.sleep(1);
+ final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+ long timeBefore = System.currentTimeMillis();
+ mDevicePolicyManager.retrieveSecurityLogs(getWho());
+ long timeAfter = System.currentTimeMillis();
+
+ final long firstTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+ assertTrue(firstTimestamp > previousTimestamp);
+ assertTrue(firstTimestamp >= timeBefore);
+ assertTrue(firstTimestamp <= timeAfter);
+
+ Thread.sleep(2);
+ timeBefore = System.currentTimeMillis();
+ final boolean preBootSecurityLogsRetrieved =
+ mDevicePolicyManager.retrievePreRebootSecurityLogs(getWho()) != null;
+ timeAfter = System.currentTimeMillis();
+
+ final long secondTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+ if (preBootSecurityLogsRetrieved) {
+ // If the device supports pre-boot security logs, verify that retrieving them updates
+ // the timestamp.
+ assertTrue(secondTimestamp > firstTimestamp);
+ assertTrue(secondTimestamp >= timeBefore);
+ assertTrue(secondTimestamp <= timeAfter);
+ } else {
+ // If the device does not support pre-boot security logs, verify that the attempt to
+ // retrieve them does not update the timestamp.
+ assertEquals(firstTimestamp, secondTimestamp);
+ }
+ }
+
+ /**
+ * Test: Requesting a bug report should update the corresponding timestamp.
+ */
+ public void testRequestBugreport() throws Exception {
+ Thread.sleep(1);
+ final long previousTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+
+ final long timeBefore = System.currentTimeMillis();
+ mDevicePolicyManager.requestBugreport(getWho());
+ final long timeAfter = System.currentTimeMillis();
+
+ final long newTimestamp = mDevicePolicyManager.getLastBugReportRequestTime();
+ assertTrue(newTimestamp > previousTimestamp);
+ assertTrue(newTimestamp >= timeBefore);
+ assertTrue(newTimestamp <= timeAfter);
+ }
+
+ /**
+ * Test: Retrieving network logs should update the corresponding timestamp.
+ */
+ public void testGetLastNetworkLogRetrievalTime() throws Exception {
+ Thread.sleep(1);
+ final long previousTimestamp = mDevicePolicyManager.getLastSecurityLogRetrievalTime();
+
+ // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+ // un-hiding happens.
+ final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+ "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+ setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), true);
+
+ long timeBefore = System.currentTimeMillis();
+ final Method retrieveNetworkLogsMethod = DevicePolicyManager.class.getDeclaredMethod(
+ "retrieveNetworkLogs", ComponentName.class, long.class);
+ retrieveNetworkLogsMethod.invoke(mDevicePolicyManager, getWho(), 0 /* batchToken */);
+ long timeAfter = System.currentTimeMillis();
+
+ final long newTimestamp = mDevicePolicyManager.getLastNetworkLogRetrievalTime();
+ assertTrue(newTimestamp > previousTimestamp);
+ assertTrue(newTimestamp >= timeBefore);
+ assertTrue(newTimestamp <= timeAfter);
+
+ setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+ }
+
+ /**
+ * Helper that allows the host-side test harness to disable network logging after running the
+ * other tests in this file.
+ */
+ public void testDisablingNetworkLogging() throws Exception {
+ // STOPSHIP(b/33068581): Network logging will be un-hidden for O. Remove reflection when the
+ // un-hiding happens.
+ final Method setNetworkLoggingEnabledMethod = DevicePolicyManager.class.getDeclaredMethod(
+ "setNetworkLoggingEnabled", ComponentName.class, boolean.class);
+ setNetworkLoggingEnabledMethod.invoke(mDevicePolicyManager, getWho(), false);
+ }
+}
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
index 195a18b..a5e8da1 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -68,7 +68,7 @@
= new LinkedBlockingQueue();
private TestCallback mCallback;
- private Object mCallbackLock = new Object();
+ private final Object mCallbackLock = new Object();
private final Messenger mMessenger = new Messenger(new CheckHandler());
private final HandlerThread mCallbackThread = new HandlerThread("callback");
diff --git a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
index 3d2c2ff..7a5dee3 100644
--- a/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
+++ b/hostsidetests/devicepolicy/app/VpnApp/src/com/android/cts/vpnfirewall/ReflectorVpnService.java
@@ -16,6 +16,8 @@
package com.android.cts.vpnfirewall;
+import android.R;
+import android.app.Notification;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager.NameNotFoundException;
@@ -33,6 +35,7 @@
public class ReflectorVpnService extends VpnService {
private static String TAG = "ReflectorVpnService";
+ private static final int NOTIFICATION_ID = 1;
private static int MTU = 1799;
private ParcelFileDescriptor mFd = null;
@@ -45,8 +48,13 @@
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
+ // Put ourself in the foreground to stop the system killing us while we wait for orders from
+ // the hostside test.
+ startForeground(NOTIFICATION_ID, new Notification.Builder(this)
+ .setSmallIcon(R.drawable.ic_dialog_alert)
+ .build());
start();
- return START_NOT_STICKY;
+ return START_REDELIVER_INTENT;
}
@Override
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 490afe7..e8bc728 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.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
@@ -136,9 +136,9 @@
protected void installAppAsUser(String appFileName, boolean grantPermissions, int userId)
throws FileNotFoundException, DeviceNotAvailableException {
CLog.d("Installing app " + appFileName + " for user " + userId);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
String result = getDevice().installPackageForUser(
- MigrationHelper.getTestFile(mCtsBuild, appFileName), true, grantPermissions,
- userId, "-t");
+ buildHelper.getTestFile(appFileName), true, grantPermissions, userId, "-t");
assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
result);
}
@@ -148,7 +148,7 @@
executeShellCommand("am force-stop --user " + userId + " " + packageName);
}
- private void executeShellCommand(final String command) throws Exception {
+ protected void executeShellCommand(final String command) throws Exception {
CLog.d("Starting command " + command);
String commandOutput = getDevice().executeShellCommand(command);
CLog.d("Output for command " + command + ": " + commandOutput);
@@ -566,17 +566,25 @@
}
}
- protected void enableComponent(int userId, String componentName)
+ /**
+ * Runs pm enable command to enable a package or component. Returns the command result.
+ */
+ protected String enableComponentOrPackage(int userId, String packageOrComponent)
throws DeviceNotAvailableException {
- String command = "pm enable --user " + userId + " " + componentName;
- CLog.d("Output for command " + command + ": "
- + getDevice().executeShellCommand(command));
+ String command = "pm enable --user " + userId + " " + packageOrComponent;
+ String result = getDevice().executeShellCommand(command);
+ CLog.d("Output for command " + command + ": " + result);
+ return result;
}
- protected void disableComponent(int userId, String componentName)
+ /**
+ * Runs pm disable command to disable a package or component. Returns the command result.
+ */
+ protected String disableComponentOrPackage(int userId, String packageOrComponent)
throws DeviceNotAvailableException {
- String command = "pm disable --user " + userId + " " + componentName;
- CLog.d("Output for command " + command + ": "
- + getDevice().executeShellCommand(command));
+ String command = "pm disable --user " + userId + " " + packageOrComponent;
+ String result = getDevice().executeShellCommand(command);
+ CLog.d("Output for command " + command + ": " + result);
+ return result;
}
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
index 607795f..bb1811f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CustomDeviceOwnerTest.java
@@ -16,8 +16,8 @@
package com.android.cts.devicepolicy;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.cts.devicepolicy.BaseDevicePolicyTest.Settings;
-import com.android.cts.migration.MigrationHelper;
import java.io.File;
import java.lang.Exception;
@@ -135,7 +135,8 @@
if (!mHasFeature) {
return;
}
- final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ final File apk = buildHelper.getTestFile(TEST_APP_APK);
try {
// Install the test and prepare the test apk.
installAppAsUser(PACKAGE_INSTALLER_APK, mPrimaryUserId);
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index fad96ed..036bf40 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -18,12 +18,15 @@
import android.platform.test.annotations.RequiresDevice;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
import java.io.File;
import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
/**
* Set of tests for use cases that apply to profile and device owner.
@@ -93,6 +96,9 @@
private static final String CUSTOMIZATION_APP_PKG = "com.android.cts.customizationapp";
private static final String CUSTOMIZATION_APP_APK = "CtsCustomizationApp.apk";
+ private static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES
+ = "enabled_notification_policy_access_packages";
+
// ID of the user all tests are run as. For device owner this will be the primary user, for
// profile owner it is the user id of the created profile.
protected int mUserId;
@@ -497,7 +503,8 @@
final String PACKAGE_VERIFIER_ENABLE_SETTING = "package_verifier_enable";
final String SECURE_SETTING_CATEGORY = "secure";
final String GLOBAL_SETTING_CATEGORY = "global";
- final File apk = MigrationHelper.getTestFile(mCtsBuild, TEST_APP_APK);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ final File apk = buildHelper.getTestFile(TEST_APP_APK);
String unknownSourceSetting = null;
String packageVerifierEnableSetting = null;
String packageVerifierUserConsentSetting = null;
@@ -556,7 +563,13 @@
if (!mHasFeature) {
return;
}
- executeDeviceTestClass(".AudioRestrictionTest");
+ // This package may need to toggle zen mode for this test, so allow it to do so.
+ allowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+ try {
+ executeDeviceTestClass(".AudioRestrictionTest");
+ } finally {
+ disallowNotificationPolicyAccess(DEVICE_ADMIN_PKG, mUserId);
+ }
}
public void testSuspendPackage() throws Exception {
@@ -585,7 +598,8 @@
}
public void testCannotRemoveUserIfRestrictionSet() throws Exception {
- if (!mHasFeature || !canCreateAdditionalUsers(1)) {
+ // Outside of the primary user, setting DISALLOW_REMOVE_USER would not work.
+ if (!mHasFeature || !canCreateAdditionalUsers(1) || mUserId != getPrimaryUser()) {
return;
}
final int userId = createUser();
@@ -600,6 +614,31 @@
}
}
+ public void testCannotEnableOrDisableDeviceOwnerOrProfileOwner() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ // Try to disable a component in device owner/ profile owner.
+ String result = disableComponentOrPackage(
+ mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+ assertTrue("Should throw SecurityException",
+ result.contains("java.lang.SecurityException"));
+ // Try to disable the device owner/ profile owner package.
+ result = disableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+ assertTrue("Should throw SecurityException",
+ result.contains("java.lang.SecurityException"));
+ // Try to enable a component in device owner/ profile owner.
+ result = enableComponentOrPackage(
+ mUserId, DEVICE_ADMIN_PKG + "/.SetPolicyActivity");
+ assertTrue("Should throw SecurityException",
+ result.contains("java.lang.SecurityException"));
+ // Try to enable the device owner/ profile owner package.
+ result = enableComponentOrPackage(mUserId, DEVICE_ADMIN_PKG);
+ assertTrue("Should throw SecurityException",
+ result.contains("java.lang.SecurityException"));
+
+ }
+
protected void executeDeviceTestClass(String className) throws Exception {
runDeviceTestsAsUser(DEVICE_ADMIN_PKG, className, mUserId);
}
@@ -695,4 +734,46 @@
: "testScreenCapturePossible";
executeDeviceTestMethod(".ScreenCaptureDisabledTest", testMethodName);
}
+
+ /**
+ * Allows packageName to manage notification policy configuration, which
+ * includes toggling zen mode.
+ */
+ private void allowNotificationPolicyAccess(String packageName, int userId)
+ throws DeviceNotAvailableException {
+ List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+ if (!enabledPackages.contains(packageName)) {
+ enabledPackages.add(packageName);
+ setEnabledNotificationPolicyPackages(enabledPackages, userId);
+ }
+ }
+
+ /**
+ * Disallows packageName to manage notification policy configuration, which
+ * includes toggling zen mode.
+ */
+ private void disallowNotificationPolicyAccess(String packageName, int userId)
+ throws DeviceNotAvailableException {
+ List<String> enabledPackages = getEnabledNotificationPolicyPackages(userId);
+ if (enabledPackages.contains(packageName)) {
+ enabledPackages.remove(packageName);
+ setEnabledNotificationPolicyPackages(enabledPackages, userId);
+ }
+ }
+
+ private void setEnabledNotificationPolicyPackages(List<String> packages, int userId)
+ throws DeviceNotAvailableException {
+ getDevice().setSetting(userId, "secure", ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES,
+ String.join(":", packages));
+ }
+
+ private List<String> getEnabledNotificationPolicyPackages(int userId)
+ throws DeviceNotAvailableException {
+ String settingValue = getDevice().getSetting(userId, "secure",
+ ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES);
+ if (settingValue == null) {
+ return new ArrayList<String>();
+ }
+ return new ArrayList<String>(Arrays.asList(settingValue.split(":|\n")));
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
new file mode 100644
index 0000000..9c4018d
--- /dev/null
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusManagedProfileTest.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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.devicepolicy;
+
+/**
+ * Tests for having both device owner and profile owner. Device owner is setup for you in
+ * {@link #setUp()} and it is always the {@link #COMP_DPC_PKG}. You are required to call
+ * {@link #createManagedProfile(int)} yourself to create managed profile on each test case.
+ */
+public class DeviceOwnerPlusManagedProfileTest extends BaseDevicePolicyTest {
+ private static final String DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST =
+ "com.android.cts.comp.DeviceOwnerBindDeviceAdminServiceTest";
+ private static final String MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST =
+ "com.android.cts.comp.ManagedProfileBindDeviceAdminServiceTest";
+
+ private int mProfileUserId;
+
+ private static final String COMP_DPC_PKG = "com.android.cts.comp";
+ private static final String COMP_DPC_APK = "CtsCorpOwnedManagedProfile.apk";
+ private static final String COMP_DPC_ADMIN =
+ COMP_DPC_PKG + "/com.android.cts.comp.AdminReceiver";
+ private static final String COMP_DPC_PKG2 = "com.android.cts.comp2";
+ private static final String COMP_DPC_APK2 = "CtsCorpOwnedManagedProfile2.apk";
+ private static final String COMP_DPC_ADMIN2 =
+ COMP_DPC_PKG2 + "/com.android.cts.comp.AdminReceiver";
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ // We need managed user to be supported in order to create a profile of the user owner.
+ mHasFeature = mHasFeature && hasDeviceFeature("android.software.managed_users");
+ if (mHasFeature) {
+ // Set device owner.
+ installAppAsUser(COMP_DPC_APK, mPrimaryUserId);
+ if (!setDeviceOwner(COMP_DPC_ADMIN, mPrimaryUserId, /*expectFailure*/ false)) {
+ removeAdmin(COMP_DPC_ADMIN, mPrimaryUserId);
+ fail("Failed to set device owner");
+ }
+ }
+ }
+
+ /**
+ * Both device owner and profile are the same package ({@link #COMP_DPC_PKG}).
+ */
+ public void testBindDeviceAdminServiceAsUser_corpOwnedManagedProfile() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ setupManagedProfile(COMP_DPC_APK, COMP_DPC_ADMIN);
+ // Installing a non managing app (neither device owner nor profile owner).
+ installAppAsUser(COMP_DPC_APK2, mPrimaryUserId);
+ installAppAsUser(COMP_DPC_APK2, mProfileUserId);
+
+ // Testing device owner -> profile owner.
+ runDeviceTestsAsUser(
+ COMP_DPC_PKG,
+ DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+ "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+ mPrimaryUserId);
+ // Testing profile owner -> device owner.
+ runDeviceTestsAsUser(
+ COMP_DPC_PKG,
+ MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+ "testBindDeviceAdminServiceForUser_corpOwnedManagedProfile",
+ mProfileUserId);
+ }
+
+ /**
+ * Device owner is {@link #COMP_DPC_PKG} while profile owner is {@link #COMP_DPC_PKG2}.
+ */
+ public void testBindDeviceAdminServiceAsUser_byodPlusDeviceOwner() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+ setupManagedProfile(COMP_DPC_APK2, COMP_DPC_ADMIN2);
+ // Testing device owner -> profile owner.
+ runDeviceTestsAsUser(
+ COMP_DPC_PKG,
+ DEVICE_OWNER_BIND_DEVICE_ADMIN_SERVICE_TEST,
+ "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+ mPrimaryUserId);
+ // Testing profile owner -> device owner.
+ runDeviceTestsAsUser(
+ COMP_DPC_PKG2,
+ MANAGED_PROFILE_BIND_DEVICE_ADMIN_SERVICE_TEST,
+ "testBindDeviceAdminServiceForUser_byodPlusDeviceOwner",
+ mProfileUserId);
+ }
+
+ protected void setupManagedProfile(String apkName, String adminReceiverClassName)
+ throws Exception {
+ mProfileUserId = createManagedProfile(mPrimaryUserId);
+ installAppAsUser(apkName, mProfileUserId);
+ setProfileOwnerOrFail(adminReceiverClassName, mProfileUserId);
+ startUser(mProfileUserId);
+ }
+}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index 2a4c77f..3c31fd8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -324,6 +324,12 @@
try {
installAppAsUser(INTENT_RECEIVER_APK, mPrimaryUserId);
executeDeviceOwnerTest("LockTaskTest");
+ } catch (AssertionError ex) {
+ // STOPSHIP(b/32771855), remove this once we fixed the bug.
+ executeShellCommand("dumpsys activity activities");
+ executeShellCommand("dumpsys window -a");
+ executeShellCommand("dumpsys activity service com.android.systemui");
+ throw ex;
} finally {
getDevice().uninstallPackage(INTENT_RECEIVER_PKG);
}
@@ -400,6 +406,19 @@
"testIsProvisioningAllowedTrueForManagedProfileAction");
}
+ public void testAdminActionBookkeeping() throws Exception {
+ if (!mHasFeature) {
+ return;
+ }
+
+ try {
+ executeDeviceOwnerTest("AdminActionBookkeepingTest");
+ } finally {
+ // Always attempt to disable network logging to bring the device to initial state.
+ executeDeviceTestMethod(".AdminActionBookkeepingTest", "testDisablingNetworkLogging");
+ }
+ }
+
private void executeDeviceOwnerTest(String testClassName) throws Exception {
if (!mHasFeature) {
return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index a05b2b3..d479868 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -260,20 +260,20 @@
// allow_parent_profile_app_linking is not set, try different enabled state combinations.
// We should not have app link handler in parent user no matter whether it is enabled.
- disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testReceivedByBrowserActivityInManaged");
- enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testReceivedByBrowserActivityInManaged");
- disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testTwoReceivers");
- enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testTwoReceivers");
// We now set allow_parent_profile_app_linking, and hence we should have the app handler
@@ -281,20 +281,20 @@
changeUserRestrictionForUser("allow_parent_profile_app_linking", ADD_RESTRICTION_COMMAND,
mProfileUserId);
- disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testReceivedByBrowserActivityInManaged");
- enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- disableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testTwoReceivers");
- disableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ disableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testTwoReceivers");
- enableComponent(mParentUserId, APP_HANDLER_COMPONENT);
- enableComponent(mProfileUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mParentUserId, APP_HANDLER_COMPONENT);
+ enableComponentOrPackage(mProfileUserId, APP_HANDLER_COMPONENT);
assertAppLinkResult("testThreeReceivers");
}
diff --git a/hostsidetests/dumpsys/Android.mk b/hostsidetests/dumpsys/Android.mk
index 9de0e9c..8a3470f 100644
--- a/hostsidetests/dumpsys/Android.mk
+++ b/hostsidetests/dumpsys/Android.mk
@@ -21,9 +21,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsDumpsysHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.dumpsys
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index fee107e..acfc72d 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -16,7 +16,7 @@
package android.dumpsys.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -876,7 +876,8 @@
getDevice().uninstallPackage(TEST_PKG);
// install the test app
- File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ File testAppFile = buildHelper.getTestFile(TEST_APK);
String installResult = getDevice().installPackage(testAppFile, false);
assertNull(
String.format("failed to install atrace test app. Reason: %s", installResult),
diff --git a/hostsidetests/jdwpsecurity/Android.mk b/hostsidetests/jdwpsecurity/Android.mk
index 338a7ae..3c8ead8 100644
--- a/hostsidetests/jdwpsecurity/Android.mk
+++ b/hostsidetests/jdwpsecurity/Android.mk
@@ -23,9 +23,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsJdwpSecurityHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
# Tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
index 186728c..a5570af 100644
--- a/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
+++ b/hostsidetests/jdwpsecurity/src/android/jdwpsecurity/cts/JdwpSecurityHostTest.java
@@ -16,7 +16,7 @@
package android.jdwpsecurity.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.log.LogUtil.CLog;
@@ -85,7 +85,8 @@
getDevice().executeShellCommand("chmod 755 " + getDeviceScriptFilepath());
// Push jar file.
- File jarFile = MigrationHelper.getTestFile(mBuildInfo, DEVICE_JAR_FILENAME);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+ File jarFile = buildHelper.getTestFile(DEVICE_JAR_FILENAME);
boolean success = getDevice().pushFile(jarFile, getDeviceJarFilepath());
assertTrue("Failed to push jar file to " + getDeviceScriptFilepath(), success);
}
diff --git a/hostsidetests/monkey/Android.mk b/hostsidetests/monkey/Android.mk
index 14462d0..7c7ecb5 100644
--- a/hostsidetests/monkey/Android.mk
+++ b/hostsidetests/monkey/Android.mk
@@ -22,9 +22,7 @@
LOCAL_MODULE := CtsMonkeyTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
# prefix zzz intentional to run this last
LOCAL_CTS_TEST_PACKAGE := zzz.android.monkey
diff --git a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
index e601593..5f22b62 100755
--- a/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
+++ b/hostsidetests/monkey/src/com/android/cts/monkey/AbstractMonkeyTest.java
@@ -1,6 +1,6 @@
package com.android.cts.monkey;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -41,9 +41,10 @@
super.setUp();
mDevice = getDevice();
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
for (int i = 0; i < PKGS.length; i++) {
mDevice.uninstallPackage(PKGS[i]);
- File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+ File app = buildHelper.getTestFile(APKS[i]);
mDevice.installPackage(app, false, options);
}
clearLogCat();
diff --git a/hostsidetests/multiuser/Android.mk b/hostsidetests/multiuser/Android.mk
index 1a324fb..ec18912 100644
--- a/hostsidetests/multiuser/Android.mk
+++ b/hostsidetests/multiuser/Android.mk
@@ -22,9 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.host.multiuser
@@ -34,4 +32,4 @@
include $(BUILD_CTS_HOST_JAVA_LIBRARY)
# Build the test APKs using their own makefiles
-include $(call all-makefiles-under,$(LOCAL_PATH))
\ No newline at end of file
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/hostsidetests/net/Android.mk b/hostsidetests/net/Android.mk
index ad97ecd..1c3f053 100644
--- a/hostsidetests/net/Android.mk
+++ b/hostsidetests/net/Android.mk
@@ -21,9 +21,7 @@
LOCAL_MODULE := CtsHostsideNetworkTests
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.net.hostsidenetwork
diff --git a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
index 6642512..f3d7dbd 100644
--- a/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
+++ b/hostsidetests/net/src/com/android/cts/net/HostsideNetworkTestCase.java
@@ -16,7 +16,7 @@
package com.android.cts.net;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
@@ -80,7 +80,8 @@
protected void installPackage(String apk) throws FileNotFoundException,
DeviceNotAvailableException {
- assertNull(getDevice().installPackage(MigrationHelper.getTestFile(mCtsBuild, apk), false));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), false));
}
protected void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/numberblocking/Android.mk b/hostsidetests/numberblocking/Android.mk
index bf2d045..42c7169 100644
--- a/hostsidetests/numberblocking/Android.mk
+++ b/hostsidetests/numberblocking/Android.mk
@@ -25,9 +25,7 @@
LOCAL_MODULE := CtsHostsideNumberBlockingTestCases
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
index 11455a0..5e1a0ec 100644
--- a/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
+++ b/hostsidetests/numberblocking/src/com/android/cts/numberblocking/hostside/NumberBlockingTest.java
@@ -16,7 +16,7 @@
package com.android.cts.numberblocking.hostside;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.tradefed.build.IBuildInfo;
@@ -149,7 +149,8 @@
private void installTestAppForUser(int userId) throws Exception {
LogUtil.CLog.logAndDisplay(Log.LogLevel.INFO, "Installing test app for user: " + userId);
- File testAppFile = MigrationHelper.getTestFile(mCtsBuild, TEST_APK);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ File testAppFile = buildHelper.getTestFile(TEST_APK);
String installResult = getDevice().installPackageForUser(
testAppFile, true /*reinstall*/, userId);
assertNull(String.format(
diff --git a/hostsidetests/os/Android.mk b/hostsidetests/os/Android.mk
index bb5154f..e54703e 100644
--- a/hostsidetests/os/Android.mk
+++ b/hostsidetests/os/Android.mk
@@ -23,7 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.host.os
diff --git a/hostsidetests/os/src/android/os/cts/OsHostTests.java b/hostsidetests/os/src/android/os/cts/OsHostTests.java
index 52a375d..3b2e027 100644
--- a/hostsidetests/os/src/android/os/cts/OsHostTests.java
+++ b/hostsidetests/os/src/android/os/cts/OsHostTests.java
@@ -16,7 +16,7 @@
package android.os.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.ITestDevice;
@@ -145,6 +145,7 @@
* Helper: find a test apk
*/
private File getTestAppFile(String fileName) throws FileNotFoundException {
- return MigrationHelper.getTestFile(mCtsBuild, fileName);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
+ return buildHelper.getTestFile(fileName);
}
}
diff --git a/hostsidetests/retaildemo/Android.mk b/hostsidetests/retaildemo/Android.mk
index 52208ec..ba106cc 100644
--- a/hostsidetests/retaildemo/Android.mk
+++ b/hostsidetests/retaildemo/Android.mk
@@ -25,7 +25,7 @@
LOCAL_JAVA_LIBRARIES := \
tools-common-prebuilt \
cts-tradefed \
- tradefed-prebuilt
+ tradefed
LOCAL_CTS_TEST_PACKAGE := android.host.retaildemo
diff --git a/hostsidetests/sample/Android.mk b/hostsidetests/sample/Android.mk
index 8d8a076..bfdaeda 100644
--- a/hostsidetests/sample/Android.mk
+++ b/hostsidetests/sample/Android.mk
@@ -25,7 +25,7 @@
LOCAL_MODULE := CtsSampleHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/security/Android.mk b/hostsidetests/security/Android.mk
index 85492de..7943785 100644
--- a/hostsidetests/security/Android.mk
+++ b/hostsidetests/security/Android.mk
@@ -28,9 +28,7 @@
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.host.security
diff --git a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
index a8c35d2..f304607 100644
--- a/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
+++ b/hostsidetests/security/src/android/security/cts/SELinuxHostTest.java
@@ -18,7 +18,7 @@
import android.platform.test.annotations.RestrictedBuildTest;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.CollectingOutputReceiver;
import com.android.tradefed.device.DeviceNotAvailableException;
@@ -111,7 +111,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
/* obtain sepolicy file from running device */
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
index 703895a..ff9e62b 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/Android.mk
@@ -23,7 +23,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
LOCAL_CTS_TEST_PACKAGE := android.server
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
index e10e288..06fd7da 100755
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/AndroidManifest.xml
@@ -19,6 +19,9 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
package="android.server.cts">
+ <!-- virtual display test permissions -->
+ <uses-permission android:name="android.permission.CAPTURE_VIDEO_OUTPUT" />
+
<uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
<application>
@@ -163,6 +166,9 @@
<activity android:name=".TurnScreenOnActivity"
android:exported="true"
/>
+ <activity android:name=".TurnScreenOnDismissKeyguardActivity"
+ android:exported="true"
+ />
<activity android:name=".SingleTaskActivity"
android:exported="true"
android:launchMode="singleTask"
@@ -221,6 +227,9 @@
<activity android:name=".DismissKeyguardActivity"
android:exported="true"
/>
+ <activity android:name=".DismissKeyguardMethodActivity"
+ android:exported="true"
+ />
<activity android:name=".WallpaperActivity"
android:exported="true"
android:theme="@style/WallpaperTheme"
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
index 71ed5f5..119f7bc 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/AbstractLifecycleLogActivity.java
@@ -58,7 +58,8 @@
" size=" + buildCoordString(config.screenWidthDp, config.screenHeightDp) +
" displaySize=" + buildCoordString(point.x, point.y) +
" metricsSize=" + buildCoordString(metrics.widthPixels, metrics.heightPixels) +
- " smallestScreenWidth=" + config.smallestScreenWidthDp;
+ " smallestScreenWidth=" + config.smallestScreenWidthDp +
+ " densityDpi=" + config.densityDpi;
Log.i(getTag(), line);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
index d77f8af..6dab9dd 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/BroadcastReceiverActivity.java
@@ -19,6 +19,7 @@
import static android.view.WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD;
import android.app.Activity;
+import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -64,6 +65,10 @@
if (extras.getBoolean("dismissKeyguard")) {
getWindow().addFlags(FLAG_DISMISS_KEYGUARD);
}
+ if (extras.getBoolean("dismissKeyguardMethod")) {
+ getSystemService(KeyguardManager.class).dismissKeyguard(
+ BroadcastReceiverActivity.this, new KeyguardDismissLoggerCallback(), null);
+ }
}
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java
new file mode 100644
index 0000000..18228e7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/DismissKeyguardMethodActivity.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.app.Activity;
+import android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+public class DismissKeyguardMethodActivity extends Activity {
+
+ private final String TAG = "DismissKeyguardMethodActivity";
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getSystemService(KeyguardManager.class).dismissKeyguard(this,
+ new KeyguardDismissLoggerCallback(), null);
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java
new file mode 100644
index 0000000..efc0c79
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/KeyguardDismissLoggerCallback.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.app.KeyguardManager;
+import android.app.KeyguardManager.KeyguardDismissCallback;
+import android.util.Log;
+
+public class KeyguardDismissLoggerCallback extends KeyguardDismissCallback {
+
+ private final String TAG = "KeyguardDismissLoggerCallback";
+
+ @Override
+ public void onDismissError() {
+ Log.i(TAG, "onDismissError");
+ }
+
+ @Override
+ public void onDismissSucceeded() {
+ Log.i(TAG, "onDismissSucceeded");
+ }
+
+ @Override
+ public void onDismissCancelled() {
+ Log.i(TAG, "onDismissCancelled");
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
index bf77276..8d1d358 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/LaunchingActivity.java
@@ -21,6 +21,7 @@
import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
import android.app.Activity;
+import android.app.ActivityOptions;
import android.content.Intent;
import android.content.ComponentName;
import android.net.Uri;
@@ -59,10 +60,16 @@
.build();
newIntent.setData(data);
}
- } else {
- // We're all set, just launch.
}
- startActivity(newIntent);
+ ActivityOptions options = null;
+ final int displayId = extras.getInt("display_id", -1);
+ if (displayId != -1) {
+ options = ActivityOptions.makeBasic();
+ options.setLaunchDisplayId(displayId);
+ newIntent.addFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK);
+ }
+
+ startActivity(newIntent, options != null ? options.toBundle() : null);
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java
new file mode 100644
index 0000000..9d262a7
--- /dev/null
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/TurnScreenOnDismissKeyguardActivity.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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 android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+public class TurnScreenOnDismissKeyguardActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);
+ getSystemService(KeyguardManager.class).dismissKeyguard(this,
+ new KeyguardDismissLoggerCallback(), null);
+ }
+}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
index 05f7b91..38e0d61 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/app/src/android/server/cts/VirtualDisplayActivity.java
@@ -37,7 +37,7 @@
private static final String TAG = "VirtualDisplayActivity";
private static final int DEFAULT_DENSITY_DPI = 160;
- private static final String KEY_DENSITY_DPI = "densityDpi";
+ private static final String KEY_DENSITY_DPI = "density_dpi";
private DisplayManager mDisplayManager;
private VirtualDisplay mVirtualDisplay;
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
index 856bd58..9c909c2 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerActivityVisibilityTests.java
@@ -41,6 +41,11 @@
executeShellCommand(AM_START_HOME_ACTIVITY_COMMAND);
mAmWmState.waitForHomeActivityVisible(mDevice);
+ /* TODO: Find a proper way to wait until launcher activity
+ * becomes fully visible. It appears that both VisibleBehindActivity
+ * and home activity are visible at some point before the former
+ * disappears.*/
+ Thread.sleep(3000);
mAmWmState.computeState(mDevice, null);
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
@@ -124,7 +129,9 @@
public void testTranslucentActivityOverDockedStack() throws Exception {
launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+ mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME, TEST_ACTIVITY_NAME});
launchActivityInStack(TRANSLUCENT_ACTIVITY_NAME, DOCKED_STACK_ID);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME,
TRANSLUCENT_ACTIVITY_NAME}, false /* compareTaskAndStackBounds */);
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
index 8b77ff4..2c733d1 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDisplayTests.java
@@ -25,6 +25,7 @@
import java.util.regex.Matcher;
import java.util.regex.Pattern;
+import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
import static android.server.cts.StateLogger.log;
/**
@@ -34,75 +35,229 @@
public class ActivityManagerDisplayTests extends ActivityManagerTestBase {
private static final String DUMPSYS_ACTIVITY_PROCESSES = "dumpsys activity processes";
+ private static final String TEST_ACTIVITY_NAME = "TestActivity";
private static final String VIRTUAL_DISPLAY_ACTIVITY = "VirtualDisplayActivity";
+ private static final int INVALID_DENSITY_DPI = -1;
private static final int CUSTOM_DENSITY_DPI = 222;
/** Temp storage used for parsing. */
private final LinkedList<String> mDumpLines = new LinkedList<>();
+ private boolean mVirtualDisplayCreated;
+
+ @Override
+ protected void tearDown() throws Exception {
+ if (mVirtualDisplayCreated) {
+ executeShellCommand(getDestroyVirtualDisplayCommand());
+ }
+ super.tearDown();
+ }
+
/**
* Tests that the global configuration is equal to the default display's override configuration.
*/
public void testDefaultDisplayOverrideConfiguration() throws Exception {
- final DisplaysState ds = getDisplaysStates();
- assertNotNull("Global configuration must not be empty.", ds.mGlobalConfig);
- final String primaryDisplayOverrideConfig = ds.mDisplayConfigs.get(0);
+ final ReportedDisplays reportedDisplays = getDisplaysStates();
+ assertNotNull("Global configuration must not be empty.", reportedDisplays.mGlobalConfig);
+ final DisplayState primaryDisplay = reportedDisplays.getDisplayState(DEFAULT_DISPLAY_ID);
assertEquals("Primary display's configuration should not be equal to global configuration.",
- ds.mGlobalConfig, primaryDisplayOverrideConfig);
+ reportedDisplays.mGlobalConfig, primaryDisplay.mOverrideConfig);
}
/**
* Tests that secondary display has override configuration set.
*/
public void testCreateVirtualDisplayWithCustomConfig() throws Exception {
- // Start an activity that is able to create virtual displays.
- executeShellCommand(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
- mAmWmState.computeState(mDevice, new String[] { VIRTUAL_DISPLAY_ACTIVITY },
- false /* compareTaskAndStackBounds */);
- final DisplaysState originalDS = getDisplaysStates();
- final int originalDisplayCount = originalDS.mDisplayConfigs.size();
-
- // Create virtual display with custom density dpi.
- executeShellCommand(getCreateVirtualDisplayCommand(CUSTOM_DENSITY_DPI));
-
- // Wait for the virtual display to be created and get configurations.
- DisplaysState ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
- assertEquals("New virtual display should be created",
- originalDisplayCount + 1, ds.mDisplayConfigs.size());
-
- // Find the id of newly added display.
- int newDisplayId = -1;
- for (Integer displayId : ds.mDisplayConfigs.keySet()) {
- if (!originalDS.mDisplayConfigs.containsKey(displayId)) {
- newDisplayId = displayId;
- break;
- }
- }
- assertFalse(-1 == newDisplayId);
+ // Create new virtual display.
+ final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
// Find the density of created display.
- final String newDisplayConfig = ds.mDisplayConfigs.get(newDisplayId);
- final String[] configParts = newDisplayConfig.split(" ");
- int newDensityDpi = -1;
- for (String part : configParts) {
- if (part.endsWith("dpi")) {
- final String densityDpiString = part.substring(0, part.length() - 3);
- newDensityDpi = Integer.parseInt(densityDpiString);
- break;
- }
- }
+ final int newDensityDpi = newDisplay.getDpi();
assertEquals(CUSTOM_DENSITY_DPI, newDensityDpi);
// Destroy the created display.
executeShellCommand(getDestroyVirtualDisplayCommand());
}
- private DisplaysState getDisplaysStateAfterCreation(int expectedDisplayCount)
- throws DeviceNotAvailableException {
- DisplaysState ds = getDisplaysStates();
+ /**
+ * Tests launching an activity on virtual display.
+ */
+ public void testLaunchActivityOnSecondaryDisplay() throws Exception {
+ // Create new virtual display.
+ final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
- while (ds.mDisplayConfigs.size() != expectedDisplayCount) {
+ // Launch activity on new secondary display.
+ executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME, newDisplay.mDisplayId));
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+ mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+ TEST_ACTIVITY_NAME);
+
+ // Check that activity is on the right display.
+ final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+ final ActivityManagerState.ActivityStack frontStack
+ = mAmWmState.getAmState().getStackById(frontStackId);
+ assertEquals("Activity launched on secondary display must be resumed",
+ getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ assertEquals("Front stack must be on external display",
+ newDisplay.mDisplayId, frontStack.mDisplayId);
+
+ // Check that activity config corresponds to display config.
+ final ReportedSizes reportedSizes = getLastReportedSizesForActivity(TEST_ACTIVITY_NAME);
+ assertEquals("Activity launched on secondary display must have proper configuration",
+ CUSTOM_DENSITY_DPI, reportedSizes.densityDpi);
+ }
+
+ /**
+ * Tests launching an activity on virtual display and then launching another activity via shell
+ * command and without specifying the display id - it must appear on the same external display.
+ */
+ public void testConsequentLaunchActivity() throws Exception {
+ // Create new virtual display.
+ final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+ // Launch activity on new secondary display.
+ executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME, newDisplay.mDisplayId));
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+ mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+ TEST_ACTIVITY_NAME);
+
+ // Launch second activity without specifying display.
+ executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY));
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+ // Check that activity is launched in focused stack on external display.
+ mAmWmState.assertFocusedActivity("Launched activity must be focused", LAUNCHING_ACTIVITY);
+ final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+ final ActivityManagerState.ActivityStack frontStack
+ = mAmWmState.getAmState().getStackById(frontStackId);
+ assertEquals("Launched activity must be resumed in front stack",
+ getActivityComponentName(LAUNCHING_ACTIVITY), frontStack.mResumedActivity);
+ assertEquals("Front stack must be on external display",
+ newDisplay.mDisplayId, frontStack.mDisplayId);
+ }
+
+ /**
+ * Tests launching an activity on virtual display and then launching another activity from the
+ * first one - it must appear on the secondary display, because it was launched from there.
+ */
+ public void testConsequentLaunchActivityFromSecondaryDisplay() throws Exception {
+ // Create new virtual display.
+ final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI);
+
+ // Launch activity on new secondary display.
+ executeShellCommand(getAmStartCmd(LAUNCHING_ACTIVITY, newDisplay.mDisplayId));
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+ mAmWmState.assertFocusedActivity("Activity launched on secondary display must be resumed",
+ LAUNCHING_ACTIVITY);
+
+ // Launch second activity from app on secondary display without specifying display id.
+ launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask */,
+ TEST_ACTIVITY_NAME);
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+
+ // Check that activity is launched in focused stack on external display.
+ mAmWmState.assertFocusedActivity("Launched activity must be focused", TEST_ACTIVITY_NAME);
+ final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+ final ActivityManagerState.ActivityStack frontStack
+ = mAmWmState.getAmState().getStackById(frontStackId);
+ assertEquals("Launched activity must be resumed in front stack",
+ getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ assertEquals("Front stack must be on external display",
+ newDisplay.mDisplayId, frontStack.mDisplayId);
+ }
+
+ /**
+ * Tests launching an activity to secondary display from activity on primary display.
+ */
+ public void testLaunchActivityFromAppToSecondaryDisplay() throws Exception {
+ // Start launching activity.
+ launchActivityInDockStack(LAUNCHING_ACTIVITY);
+ // Create new virtual display.
+ final DisplayState newDisplay = createVirtualDisplay(CUSTOM_DENSITY_DPI,
+ true /* launchInSplitScreen */);
+
+ // Launch activity on secondary display from the app on primary display.
+ launchActivity(false /* toSide */, false /* randomData */, false /* multipleTask*/,
+ TEST_ACTIVITY_NAME, newDisplay.mDisplayId);
+
+ // Check that activity is launched on external display.
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+ mAmWmState.assertFocusedActivity("Activity launched on secondary display must be focused",
+ TEST_ACTIVITY_NAME);
+ final int frontStackId = mAmWmState.getAmState().getFrontStackId(newDisplay.mDisplayId);
+ final ActivityManagerState.ActivityStack frontStack
+ = mAmWmState.getAmState().getStackById(frontStackId);
+ assertEquals("Launched activity must be resumed in front stack",
+ getActivityComponentName(TEST_ACTIVITY_NAME), frontStack.mResumedActivity);
+ assertEquals("Front stack must be on external display",
+ newDisplay.mDisplayId, frontStack.mDisplayId);
+ }
+
+ /** Find the display that was not originally reported in oldDisplays and added in newDisplays */
+ private DisplayState findNewDisplayId(ReportedDisplays oldDisplays,
+ ReportedDisplays newDisplays) {
+ for (Integer displayId : newDisplays.mDisplayStates.keySet()) {
+ if (!oldDisplays.mDisplayStates.containsKey(displayId)) {
+ return newDisplays.getDisplayState(displayId);
+ }
+ }
+
+ return null;
+ }
+
+ /** Create new virtual display with custom density. */
+ private DisplayState createVirtualDisplay(int densityDpi) throws Exception {
+ return createVirtualDisplay(densityDpi, false /* launchInSplitScreen */);
+ }
+
+ /**
+ * Create new virtual display.
+ * @param densityDpi provide custom density for the display.
+ * @param launchInSplitScreen start {@link VirtualDisplayActivity} to side from
+ * {@link LaunchingActivity} on primary display.
+ * @return {@link DisplayState} of newly created display.
+ * @throws Exception
+ */
+ private DisplayState createVirtualDisplay(int densityDpi,
+ boolean launchInSplitScreen) throws Exception {
+ // Start an activity that is able to create virtual displays.
+ if (launchInSplitScreen) {
+ launchActivityToSide(false /* randomData */, false /* multipleTaskFlag */,
+ VIRTUAL_DISPLAY_ACTIVITY);
+ } else {
+ executeShellCommand(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+ }
+ mAmWmState.computeState(mDevice, new String[] {VIRTUAL_DISPLAY_ACTIVITY},
+ false /* compareTaskAndStackBounds */);
+ final ReportedDisplays originalDS = getDisplaysStates();
+ final int originalDisplayCount = originalDS.mDisplayStates.size();
+
+ // Create virtual display with custom density dpi.
+ executeShellCommand(getCreateVirtualDisplayCommand(densityDpi));
+ mVirtualDisplayCreated = true;
+
+ // Wait for the virtual display to be created and get configurations.
+ final ReportedDisplays ds = getDisplaysStateAfterCreation(originalDisplayCount + 1);
+ assertEquals("New virtual display must be created",
+ originalDisplayCount + 1, ds.mDisplayStates.size());
+
+ // Find the newly added display.
+ final DisplayState newDisplay = findNewDisplayId(originalDS, ds);
+ assertNotNull("New virtual display must be created", newDisplay);
+
+ return newDisplay;
+ }
+
+ /** Wait for provided number of displays and report their configurations. */
+ private ReportedDisplays getDisplaysStateAfterCreation(int expectedDisplayCount)
+ throws DeviceNotAvailableException {
+ ReportedDisplays ds = getDisplaysStates();
+
+ while (!ds.isValidState(expectedDisplayCount)) {
log("***Waiting for the correct number of displays...");
try {
Thread.sleep(1000);
@@ -115,7 +270,7 @@
return ds;
}
- private DisplaysState getDisplaysStates() throws DeviceNotAvailableException {
+ private ReportedDisplays getDisplaysStates() throws DeviceNotAvailableException {
final CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
mDevice.executeShellCommand(DUMPSYS_ACTIVITY_PROCESSES, outputReceiver);
String dump = outputReceiver.getOutput();
@@ -123,11 +278,34 @@
Collections.addAll(mDumpLines, dump.split("\\n"));
- return DisplaysState.create(mDumpLines);
+ return ReportedDisplays.create(mDumpLines);
}
/** Contains the configurations applied to attached displays. */
- private static final class DisplaysState {
+ private static final class DisplayState {
+ private int mDisplayId;
+ private String mOverrideConfig;
+
+ private DisplayState(int displayId, String overrideConfig) {
+ mDisplayId = displayId;
+ mOverrideConfig = overrideConfig;
+ }
+
+ private int getDpi() {
+ final String[] configParts = mOverrideConfig.split(" ");
+ for (String part : configParts) {
+ if (part.endsWith("dpi")) {
+ final String densityDpiString = part.substring(0, part.length() - 3);
+ return Integer.parseInt(densityDpiString);
+ }
+ }
+
+ return -1;
+ }
+ }
+
+ /** Contains the configurations applied to attached displays. */
+ private static final class ReportedDisplays {
private static final Pattern sGlobalConfigurationPattern =
Pattern.compile("mGlobalConfiguration: (\\{.*\\})");
private static final Pattern sDisplayOverrideConfigurationsPattern =
@@ -136,10 +314,10 @@
Pattern.compile("(\\d+): (\\{.*\\})");
private String mGlobalConfig;
- private Map<Integer, String> mDisplayConfigs = new HashMap<>();
+ private Map<Integer, DisplayState> mDisplayStates = new HashMap<>();
- static DisplaysState create(LinkedList<String> dump) {
- final DisplaysState result = new DisplaysState();
+ static ReportedDisplays create(LinkedList<String> dump) {
+ final ReportedDisplays result = new ReportedDisplays();
while (!dump.isEmpty()) {
final String line = dump.pop().trim();
@@ -147,13 +325,14 @@
Matcher matcher = sDisplayOverrideConfigurationsPattern.matcher(line);
if (matcher.matches()) {
log(line);
- while (DisplaysState.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
+ while (ReportedDisplays.shouldContinueExtracting(dump, sDisplayConfigPattern)) {
final String displayOverrideConfigLine = dump.pop().trim();
log(displayOverrideConfigLine);
matcher = sDisplayConfigPattern.matcher(displayOverrideConfigLine);
matcher.matches();
final Integer displayId = Integer.valueOf(matcher.group(1));
- result.mDisplayConfigs.put(displayId, matcher.group(2));
+ result.mDisplayStates.put(displayId,
+ new DisplayState(displayId, matcher.group(2)));
}
continue;
}
@@ -177,14 +356,34 @@
final String line = dump.peek().trim();
return matchingPattern.matcher(line).matches();
}
+
+ DisplayState getDisplayState(int displayId) {
+ return mDisplayStates.get(displayId);
+ }
+
+ /** Check if reported state is valid. */
+ boolean isValidState(int expectedDisplayCount) {
+ if (mDisplayStates.size() != expectedDisplayCount) {
+ return false;
+ }
+
+ for (Map.Entry<Integer, DisplayState> entry : mDisplayStates.entrySet()) {
+ final DisplayState ds = entry.getValue();
+ if (ds.mDisplayId != DEFAULT_DISPLAY_ID && ds.getDpi() == -1) {
+ return false;
+ }
+ }
+ return true;
+ }
}
private static String getCreateVirtualDisplayCommand(int densityDpi) {
- StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
+ final StringBuilder commandBuilder
+ = new StringBuilder(getAmStartCmd(VIRTUAL_DISPLAY_ACTIVITY));
commandBuilder.append(" -f 0x20000000");
commandBuilder.append(" --es command create_display");
- if (densityDpi != -1) {
- commandBuilder.append(" --ei densityDpi ").append(densityDpi);
+ if (densityDpi != INVALID_DENSITY_DPI) {
+ commandBuilder.append(" --ei density_dpi ").append(densityDpi);
}
return commandBuilder.toString();
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
index c305bb1..0cc9ace 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/ActivityManagerDockedStackTests.java
@@ -62,9 +62,9 @@
public void testLaunchToSide() throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
launchActivityToSide();
- mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME});
-
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
@@ -74,6 +74,7 @@
launchActivityInDockStack(LAUNCHING_ACTIVITY);
final String[] waitForFirstVisible = new String[] {TEST_ACTIVITY_NAME};
final String[] waitForSecondVisible = new String[] {NO_RELAUNCH_ACTIVITY_NAME};
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
// Launch activity to side.
launchActivityToSide();
@@ -106,7 +107,9 @@
public void testLaunchToSideMultiple() throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
- final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+ final String[] waitForActivitiesVisible =
+ new String[] {TEST_ACTIVITY_NAME, LAUNCHING_ACTIVITY};
// Launch activity to side.
launchActivityToSide();
@@ -145,11 +148,16 @@
private void launchTargetToSide(String targetActivityName,
boolean taskCountMustIncrement) throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
- final String[] waitForActivitiesVisible = new String[] {targetActivityName};
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+
+ final String[] waitForActivitiesVisible =
+ new String[] {targetActivityName, LAUNCHING_ACTIVITY};
// Launch activity to side with data.
launchActivityToSide(true, false, targetActivityName);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+ mAmWmState.assertContainsStack(
+ "Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
int taskNumberInitial = mAmWmState.getAmState().getStackById(FULLSCREEN_WORKSPACE_STACK_ID)
.getTasks().size();
mAmWmState.assertNotNull("Launched to side activity must be in fullscreen stack.",
@@ -195,7 +203,9 @@
public void testLaunchToSideMultipleWithFlag() throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
- final String[] waitForActivitiesVisible = new String[] {TEST_ACTIVITY_NAME};
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
+ final String[] waitForActivitiesVisible =
+ new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
// Launch activity to side.
launchActivityToSide();
@@ -222,15 +232,17 @@
public void testRotationWhenDocked() throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
launchActivityToSide();
- final String[] waitForActivitiesVisible = new String[] {LAUNCHING_ACTIVITY};
- mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
// Rotate device single steps (90°) 0-1-2-3.
// Each time we compute the state we implicitly assert valid bounds.
+ String[] waitForActivitiesVisible =
+ new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
setDeviceRotation(0);
mAmWmState.computeState(mDevice, waitForActivitiesVisible);
setDeviceRotation(1);
@@ -255,13 +267,16 @@
public void testRotationWhenDockedWhileLocked() throws Exception {
launchActivityInDockStack(LAUNCHING_ACTIVITY);
+ mAmWmState.computeState(mDevice, new String[] {LAUNCHING_ACTIVITY});
launchActivityToSide();
- final String[] waitForActivitiesVisible = new String[] {LAUNCHING_ACTIVITY};
- mAmWmState.computeState(mDevice, waitForActivitiesVisible);
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+ mAmWmState.assertSanity();
mAmWmState.assertContainsStack(
"Must contain fullscreen stack.", FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.assertContainsStack("Must contain docked stack.", DOCKED_STACK_ID);
+ String[] waitForActivitiesVisible =
+ new String[] {LAUNCHING_ACTIVITY, TEST_ACTIVITY_NAME};
sleepDevice();
setDeviceRotation(0);
wakeUpAndUnlockDevice();
@@ -285,7 +300,9 @@
public void testResizeDockedStack() throws Exception {
launchActivityInDockStack(DOCKED_ACTIVITY_NAME);
+ mAmWmState.computeState(mDevice, new String[] {DOCKED_ACTIVITY_NAME});
launchActivityInStack(TEST_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
+ mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
resizeDockedStack(STACK_SIZE, STACK_SIZE, TASK_SIZE, TASK_SIZE);
mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME, DOCKED_ACTIVITY_NAME},
false /* compareTaskAndStackBounds */);
@@ -300,12 +317,14 @@
}
public void testActivityLifeCycleOnResizeDockedStack() throws Exception {
+ final String[] waitTestActivityName = new String[] {TEST_ACTIVITY_NAME};
executeShellCommand(getAmStartCmd(TEST_ACTIVITY_NAME));
- mAmWmState.computeState(mDevice, new String[] {TEST_ACTIVITY_NAME});
+ mAmWmState.computeState(mDevice, waitTestActivityName);
final Rectangle fullScreenBounds =
mAmWmState.getWmState().getStack(FULLSCREEN_WORKSPACE_STACK_ID).getBounds();
moveActivityToDockStack(TEST_ACTIVITY_NAME);
+ mAmWmState.computeState(mDevice, waitTestActivityName);
launchActivityInStack(NO_RELAUNCH_ACTIVITY_NAME, FULLSCREEN_WORKSPACE_STACK_ID);
mAmWmState.computeState(mDevice,
@@ -317,15 +336,15 @@
Rectangle newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, true);
resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
+ mAmWmState.computeState(mDevice,
+ new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
// We resize twice to make sure we cross an orientation change threshold for both
// activities.
newBounds = computeNewDockBounds(fullScreenBounds, initialDockBounds, false);
resizeDockedStack(newBounds.width, newBounds.height, newBounds.width, newBounds.height);
-
mAmWmState.computeState(mDevice,
new String[]{TEST_ACTIVITY_NAME, NO_RELAUNCH_ACTIVITY_NAME});
-
assertActivityLifecycle(TEST_ACTIVITY_NAME, true);
assertActivityLifecycle(NO_RELAUNCH_ACTIVITY_NAME, false);
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
index 28827f4..c74168d 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardLockedTests.java
@@ -82,4 +82,38 @@
assertKeyguardGone();
mAmWmState.assertVisibility("ShowWhenLockedActivity", true);
}
+
+ public void testDismissKeyguardActivity_method() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
+ clearLogcat();
+ gotoKeyguard();
+ mAmWmState.computeState(mDevice, null);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+ enterAndConfirmLockCredential();
+ mAmWmState.waitForKeyguardGone(mDevice);
+ mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+ mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+ assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ assertOnDismissSucceededInLogcat();
+ }
+
+ public void testDismissKeyguardActivity_method_cancelled() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
+ clearLogcat();
+ gotoKeyguard();
+ mAmWmState.computeState(mDevice, null);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+ pressBackButton();
+ assertOnDismissCancelledInLogcat();
+ mAmWmState.computeState(mDevice, new String[] {});
+ mAmWmState.assertVisibility("DismissKeyguardMethodActivity", false);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ unlockDeviceWithCredential();
+ }
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
index 0ba77e0..ca86637 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTestBase.java
@@ -16,6 +16,11 @@
package android.server.cts;
+import static android.server.cts.StateLogger.log;
+
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
public class KeyguardTestBase extends ActivityManagerTestBase {
protected void assertShowingAndOccluded() {
@@ -31,4 +36,36 @@
protected void assertKeyguardGone() {
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
}
+
+ protected void assertOnDismissSucceededInLogcat() throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissSucceeded");
+ }
+
+ protected void assertOnDismissCancelledInLogcat() throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissCancelled");
+ }
+
+ protected void assertOnDismissErrorInLogcat() throws Exception {
+ assertInLogcat("KeyguardDismissLoggerCallback", "onDismissError");
+ }
+
+ private void assertInLogcat(String activityName, String entry) throws Exception {
+ final Pattern pattern = Pattern.compile("(.+)" + entry);
+ int tries = 0;
+ while (tries < 5) {
+ final String[] lines = getDeviceLogsForComponent(activityName);
+ log("Looking at logcat");
+ for (int i = lines.length - 1; i >= 0; i--) {
+ final String line = lines[i].trim();
+ log(line);
+ Matcher matcher = pattern.matcher(line);
+ if (matcher.matches()) {
+ return;
+ }
+ }
+ tries++;
+ Thread.sleep(500);
+ }
+ fail("Not in logcat: " + entry);
+ }
}
diff --git a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
index b3de9fd..d323d97 100644
--- a/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
+++ b/hostsidetests/services/activityandwindowmanager/activitymanager/src/android/server/cts/KeyguardTests.java
@@ -170,6 +170,52 @@
assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
}
+ public void testDismissKeyguardActivity_method() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
+ clearLogcat();
+ gotoKeyguard();
+ mAmWmState.computeState(mDevice, null);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ executeShellCommand(getAmStartCmd("DismissKeyguardMethodActivity"));
+ mAmWmState.waitForKeyguardGone(mDevice);
+ mAmWmState.computeState(mDevice, new String[] { "DismissKeyguardMethodActivity"});
+ mAmWmState.assertVisibility("DismissKeyguardMethodActivity", true);
+ assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ assertOnDismissSucceededInLogcat();
+ }
+
+ public void testDismissKeyguardActivity_method_notTop() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
+ clearLogcat();
+ gotoKeyguard();
+ mAmWmState.computeState(mDevice, null);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ executeShellCommand(getAmStartCmd("BroadcastReceiverActivity"));
+ executeShellCommand(getAmStartCmd("TestActivity"));
+ executeShellCommand("am broadcast -a trigger_broadcast --ez dismissKeyguardMethod true");
+ assertOnDismissErrorInLogcat();
+ }
+
+ public void testDismissKeyguardActivity_method_turnScreenOn() throws Exception {
+ if (!isHandheld()) {
+ return;
+ }
+ clearLogcat();
+ sleepDevice();
+ mAmWmState.computeState(mDevice, null);
+ assertTrue(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ executeShellCommand(getAmStartCmd("TurnScreenOnDismissKeyguardActivity"));
+ mAmWmState.waitForKeyguardGone(mDevice);
+ mAmWmState.computeState(mDevice, new String[] { "TurnScreenOnDismissKeyguardActivity"});
+ mAmWmState.assertVisibility("TurnScreenOnDismissKeyguardActivity", true);
+ assertFalse(mAmWmState.getAmState().getKeyguardControllerState().keyguardShowing);
+ assertOnDismissSucceededInLogcat();
+ }
+
/**
* Tests whether a FLAG_DISMISS_KEYGUARD activity repeatedly dismissed Keyguard, i.e. whenever
* lockscreen would show it gets dismissed immediately.
diff --git a/hostsidetests/services/activityandwindowmanager/util/Android.mk b/hostsidetests/services/activityandwindowmanager/util/Android.mk
index ac91d35..993ba94 100644
--- a/hostsidetests/services/activityandwindowmanager/util/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/util/Android.mk
@@ -23,7 +23,7 @@
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_MODULE := cts-amwm-util
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
index dc42f71..19f9365 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityAndWindowManagersState.java
@@ -43,6 +43,7 @@
// Clone of android DisplayMetrics.DENSITY_DEFAULT (DENSITY_MEDIUM)
// (Needed in host-side tests to convert dp to px.)
private static final int DISPLAY_DENSITY_DEFAULT = 160;
+ static final int DEFAULT_DISPLAY_ID = 0;
// Default minimal size of resizable task, used if none is set explicitly.
// Must be kept in sync with 'default_minimal_size_resizable_task' dimen from frameworks/base.
@@ -351,8 +352,8 @@
}
void assertFrontStack(String msg, int stackId) throws Exception {
- assertEquals(msg, stackId, mAmState.getFrontStackId());
- assertEquals(msg, stackId, mWmState.getFrontStackId());
+ assertEquals(msg, stackId, mAmState.getFrontStackId(DEFAULT_DISPLAY_ID));
+ assertEquals(msg, stackId, mWmState.getFrontStackId(DEFAULT_DISPLAY_ID));
}
void assertFocusedStack(String msg, int stackId) throws Exception {
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
index 9799bea..aff9eba 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerState.java
@@ -25,9 +25,11 @@
import java.lang.String;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
@@ -45,7 +47,7 @@
private static final int HOME_ACTIVITY_TYPE = 1;
private static final int RECENTS_ACTIVITY_TYPE = 2;
- private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+)");
+ private final Pattern mDisplayIdPattern = Pattern.compile("Display #(\\d+).*");
private final Pattern mStackIdPattern = Pattern.compile("Stack #(\\d+)\\:");
private final Pattern mResumedActivityPattern =
Pattern.compile("ResumedActivity\\: ActivityRecord\\{(.+) u(\\d+) (\\S+) (\\S+)\\}");
@@ -53,10 +55,12 @@
Pattern.compile("mFocusedStack=ActivityStack\\{(.+) stackId=(\\d+), (.+)\\}(.+)");
private final Pattern[] mExtractStackExitPatterns =
- { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern};
+ { mStackIdPattern, mResumedActivityPattern, mFocusedStackPattern, mDisplayIdPattern };
- // Stacks in z-order with the top most at the front of the list.
+ // Stacks in z-order with the top most at the front of the list, starting with primary display.
private final List<ActivityStack> mStacks = new ArrayList();
+ // Stacks on all attached displays, in z-order with the top most at the front of the list.
+ private final Map<Integer, List<ActivityStack>> mDisplayStacks = new HashMap<>();
private KeyguardControllerState mKeyguardControllerState;
private int mFocusedStackId = -1;
private String mResumedActivityRecord = null;
@@ -134,6 +138,7 @@
if (stack != null) {
mStacks.add(stack);
+ mDisplayStacks.get(currentDisplayId).add(stack);
if (stack.mResumedActivity != null) {
mResumedActivities.add(stack.mResumedActivity);
}
@@ -169,9 +174,10 @@
matcher = mDisplayIdPattern.matcher(line);
if (matcher.matches()) {
log(line);
- final String displayId = matcher.group(2);
+ final String displayId = matcher.group(1);
log(displayId);
currentDisplayId = Integer.parseInt(displayId);
+ mDisplayStacks.put(currentDisplayId, new ArrayList<>());
}
}
}
@@ -185,8 +191,8 @@
mKeyguardControllerState = null;
}
- int getFrontStackId() {
- return mStacks.get(0).mStackId;
+ int getFrontStackId(int displayId) {
+ return mDisplayStacks.get(displayId).get(0).mStackId;
}
int getFocusedStackId() {
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
index 6b9c2f3..f5da421 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/ActivityManagerTestBase.java
@@ -71,16 +71,19 @@
protected static final String AM_MOVE_TOP_ACTIVITY_TO_PINNED_STACK_COMMAND =
"am stack move-top-activity-to-pinned-stack 1 0 0 500 500";
- protected static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
+ static final String LAUNCHING_ACTIVITY = "LaunchingActivity";
private static final String AM_RESIZE_DOCKED_STACK = "am stack resize-docked-stack ";
static final String AM_MOVE_TASK = "am stack move-task ";
private static final String INPUT_KEYEVENT_HOME = "input keyevent 3";
+ private static final String INPUT_KEYEVENT_BACK = "input keyevent 4";
private static final String LOCK_CREDENTIAL = "1234";
+ private static final int INVALID_DISPLAY_ID = -1;
+
static String componentName = "android.server.cts";
/** A reference to the device under test. */
@@ -108,6 +111,11 @@
return base;
}
+ protected static String getAmStartCmd(final String activityName, final int displayId) {
+ return "am start -n " + getActivityComponentName(activityName) + " -f 0x18000000"
+ + " --display " + displayId;
+ }
+
protected static String getAmStartCmdOverHome(final String activityName) {
return "am start --activity-task-on-home -n " + getActivityComponentName(activityName);
}
@@ -205,6 +213,11 @@
mDevice.executeShellCommand(command, outputReceiver);
}
+ protected void launchActivity(boolean toSide, boolean randomData, boolean multipleTask,
+ String targetActivityName) throws Exception {
+ launchActivity(toSide, randomData, multipleTask, targetActivityName, INVALID_DISPLAY_ID);
+ }
+
/**
* Launch specific target activity. It uses existing instance of {@link #LAUNCHING_ACTIVITY}, so
* that one should be started first.
@@ -214,10 +227,11 @@
* @param targetActivityName Target activity to be launched. Only class name should be provided,
* package name of {@link #LAUNCHING_ACTIVITY} will be added
* automatically.
+ * @param displayId Display id where target activity should be launched.
* @throws Exception
*/
protected void launchActivity(boolean toSide, boolean randomData, boolean multipleTask,
- String targetActivityName) throws Exception {
+ String targetActivityName, int displayId) throws Exception {
StringBuilder commandBuilder = new StringBuilder(getAmStartCmd(LAUNCHING_ACTIVITY));
commandBuilder.append(" -f 0x20000000");
if (toSide) {
@@ -232,6 +246,9 @@
if (targetActivityName != null) {
commandBuilder.append(" --es target_activity ").append(targetActivityName);
}
+ if (displayId != INVALID_DISPLAY_ID) {
+ commandBuilder.append(" --ei display_id ").append(displayId);
+ }
executeShellCommand(commandBuilder.toString());
}
@@ -288,6 +305,10 @@
executeShellCommand(INPUT_KEYEVENT_HOME);
}
+ protected void pressBackButton() throws DeviceNotAvailableException {
+ executeShellCommand(INPUT_KEYEVENT_BACK);
+ }
+
// Utility method for debugging, not used directly here, but useful, so kept around.
protected void printStacksAndTasks() throws DeviceNotAvailableException {
CollectingOutputReceiver outputReceiver = new CollectingOutputReceiver();
@@ -568,7 +589,7 @@
private static final Pattern sDestroyPattern = Pattern.compile("(.+): onDestroy");
private static final Pattern sNewConfigPattern = Pattern.compile(
"(.+): config size=\\((\\d+),(\\d+)\\) displaySize=\\((\\d+),(\\d+)\\)" +
- " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+)");
+ " metricsSize=\\((\\d+),(\\d+)\\) smallestScreenWidth=(\\d+) densityDpi=(\\d+)");
private static final Pattern sDisplayStatePattern =
Pattern.compile("Display Power: state=(.+)");
@@ -580,13 +601,14 @@
int metricsWidth;
int metricsHeight;
int smallestWidthDp;
+ int densityDpi;
@Override
public String toString() {
return "ReportedSizes: {widthDp=" + widthDp + " heightDp=" + heightDp +
" displayWidth=" + displayWidth + " displayHeight=" + displayHeight +
" metricsWidth=" + metricsWidth + " metricsHeight=" + metricsHeight +
- " smallestWidthDp=" + smallestWidthDp + "}";
+ " smallestWidthDp=" + smallestWidthDp + " densityDpi=" + densityDpi + "}";
}
}
@@ -605,6 +627,7 @@
details.metricsWidth = Integer.parseInt(matcher.group(6));
details.metricsHeight = Integer.parseInt(matcher.group(7));
details.smallestWidthDp = Integer.parseInt(matcher.group(8));
+ details.densityDpi = Integer.parseInt(matcher.group(9));
return details;
}
}
diff --git a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
index 3faf4f0..ba1148c 100644
--- a/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
+++ b/hostsidetests/services/activityandwindowmanager/util/src/android/server/cts/WindowManagerState.java
@@ -16,6 +16,7 @@
package android.server.cts;
+import static android.server.cts.ActivityAndWindowManagersState.DEFAULT_DISPLAY_ID;
import static android.server.cts.StateLogger.log;
import static android.server.cts.StateLogger.logE;
@@ -26,8 +27,10 @@
import java.awt.*;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
+import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -87,16 +90,23 @@
private static final Pattern sInputMethodWindowPattern =
Pattern.compile("mInputMethodWindow=Window\\{([0-9a-fA-F]+) u\\d+ .+\\}.*");
+ private static final Pattern sDisplayIdPattern =
+ Pattern.compile("Display: mDisplayId=(\\d+)");
+
private static final Pattern[] sExtractStackExitPatterns = {
sStackIdPattern, sWindowPattern, sStartingWindowPattern, sExitingWindowPattern,
sDebuggerWindowPattern, sFocusedWindowPattern, sAppErrorFocusedWindowPattern,
sWaitingForDebuggerFocusedWindowPattern,
sFocusedAppPattern, sLastAppTransitionPattern, sDefaultPinnedStackBoundsPattern,
- sPinnedStackMovementBoundsPattern};
+ sPinnedStackMovementBoundsPattern, sDisplayIdPattern };
// Windows in z-order with the top most at the front of the list.
private List<WindowState> mWindowStates = new ArrayList();
- private List<WindowStack> mStacks = new ArrayList();
+ // Stacks in z-order with the top most at the front of the list, starting with primary display.
+ private final List<WindowStack> mStacks = new ArrayList();
+ // Stacks on all attached displays, in z-order with the top most at the front of the list.
+ private final Map<Integer, List<WindowStack>> mDisplayStacks
+ = new HashMap<>();
private List<Display> mDisplays = new ArrayList();
private String mFocusedWindow = null;
private String mFocusedApp = null;
@@ -158,12 +168,15 @@
Collections.addAll(mSysDump, sysDump.split("\\n"));
+ int currentDisplayId = DEFAULT_DISPLAY_ID;
while (!mSysDump.isEmpty()) {
final Display display =
Display.create(mSysDump, sExtractStackExitPatterns);
if (display != null) {
log(display.toString());
mDisplays.add(display);
+ currentDisplayId = display.mDisplayId;
+ mDisplayStacks.put(currentDisplayId, new ArrayList<>());
continue;
}
@@ -172,6 +185,7 @@
if (stack != null) {
mStacks.add(stack);
+ mDisplayStacks.get(currentDisplayId).add(stack);
continue;
}
@@ -353,8 +367,8 @@
return mLastTransition;
}
- int getFrontStackId() {
- return mStacks.get(0).mStackId;
+ int getFrontStackId(int displayId) {
+ return mDisplayStacks.get(displayId).get(0).mStackId;
}
public int getRotation() {
@@ -677,8 +691,6 @@
static class Display extends WindowContainer {
private static final String TAG = "[Display] ";
- private static final Pattern sDisplayIdPattern =
- Pattern.compile("Display: mDisplayId=(\\d+)");
private static final Pattern sDisplayInfoPattern =
Pattern.compile("(.+) (\\d+)dpi cur=(\\d+)x(\\d+) app=(\\d+)x(\\d+) (.+)");
diff --git a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
index e93607f..fd07930 100644
--- a/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
+++ b/hostsidetests/services/activityandwindowmanager/windowmanager/Android.mk
@@ -22,7 +22,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt CtsServicesHostTestCases
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed CtsServicesHostTestCases
LOCAL_STATIC_JAVA_LIBRARIES := cts-amwm-util
LOCAL_CTS_TEST_PACKAGE := android.server.cts
diff --git a/hostsidetests/shortcuts/hostside/Android.mk b/hostsidetests/shortcuts/hostside/Android.mk
index 56b2e60..830ec94 100644
--- a/hostsidetests/shortcuts/hostside/Android.mk
+++ b/hostsidetests/shortcuts/hostside/Android.mk
@@ -24,9 +24,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed-prebuilt
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := tools-common-prebuilt cts-tradefed tradefed
# tag this module as a cts test artifact
LOCAL_COMPATIBILITY_SUITE := cts
diff --git a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
index fbd344b..c703e7f 100644
--- a/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
+++ b/hostsidetests/shortcuts/hostside/src/android/content/pm/cts/shortcuthost/BaseShortcutManagerHostTest.java
@@ -15,7 +15,7 @@
*/
package android.content.pm.cts.shortcuthost;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestResult;
@@ -102,9 +102,9 @@
protected void installAppAsUser(String appFileName, int userId) throws FileNotFoundException,
DeviceNotAvailableException {
CLog.i("Installing app " + appFileName + " for user " + userId);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuild);
String result = getDevice().installPackageForUser(
- MigrationHelper.getTestFile(mCtsBuild, appFileName), true, true,
- userId, "-t");
+ buildHelper.getTestFile(appFileName), true, true, userId, "-t");
assertNull("Failed to install " + appFileName + " for user " + userId + ": " + result,
result);
}
diff --git a/hostsidetests/sustainedperf/Android.mk b/hostsidetests/sustainedperf/Android.mk
index 22c6d45..a9f06e4 100644
--- a/hostsidetests/sustainedperf/Android.mk
+++ b/hostsidetests/sustainedperf/Android.mk
@@ -24,7 +24,7 @@
LOCAL_COMPATIBILITY_SUITE := cts
LOCAL_MODULE := CtsSustainedPerformanceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/hostsidetests/systemui/Android.mk b/hostsidetests/systemui/Android.mk
index 1c0dd06..d4305f5 100644
--- a/hostsidetests/systemui/Android.mk
+++ b/hostsidetests/systemui/Android.mk
@@ -22,9 +22,7 @@
LOCAL_MODULE := CtsSystemUiHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.host.systemui
diff --git a/hostsidetests/theme/Android.mk b/hostsidetests/theme/Android.mk
index 00ca6ba..7875b4d 100644
--- a/hostsidetests/theme/Android.mk
+++ b/hostsidetests/theme/Android.mk
@@ -25,9 +25,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsThemeHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.host.theme
diff --git a/hostsidetests/theme/android_device.py b/hostsidetests/theme/android_device.py
index 6687494..68f7404 100644
--- a/hostsidetests/theme/android_device.py
+++ b/hostsidetests/theme/android_device.py
@@ -89,6 +89,11 @@
def getOrientation(self):
return int(self.runShellCommand("dumpsys | grep SurfaceOrientation")[0].split()[1])
+ def getHWType(self):
+ (output, err) = self.runShellCommand("dumpsys | grep android.hardware.type")
+ output = output.strip()
+ return output
+
def runAdbDevices():
devices = subprocess.check_output(["adb", "devices"])
devices = devices.split('\n')[1:]
diff --git a/hostsidetests/theme/app/AndroidManifest.xml b/hostsidetests/theme/app/AndroidManifest.xml
index d9a89c6..2bfc2be 100755
--- a/hostsidetests/theme/app/AndroidManifest.xml
+++ b/hostsidetests/theme/app/AndroidManifest.xml
@@ -32,6 +32,8 @@
</intent-filter>
</activity>
<activity android:name=".GenerateImagesActivity" android:screenOrientation="portrait"
+ android:configChanges=
+ "screenSize|smallestScreenSize|screenLayout|orientation"
android:exported="true" />
</application>
diff --git a/hostsidetests/theme/assets/tvdpi.zip b/hostsidetests/theme/assets/tvdpi.zip
new file mode 100644
index 0000000..3071780
--- /dev/null
+++ b/hostsidetests/theme/assets/tvdpi.zip
Binary files differ
diff --git a/hostsidetests/theme/run_theme_capture_device.py b/hostsidetests/theme/run_theme_capture_device.py
index a516717..20aecf8 100755
--- a/hostsidetests/theme/run_theme_capture_device.py
+++ b/hostsidetests/theme/run_theme_capture_device.py
@@ -27,7 +27,6 @@
CTS_THEME_dict = {
120 : "ldpi",
160 : "mdpi",
- 213 : "tvdpi",
240 : "hdpi",
320 : "xhdpi",
480 : "xxhdpi",
@@ -98,10 +97,15 @@
device = androidDevice(deviceSerial)
density = device.getDensity()
- if CTS_THEME_dict.has_key(density):
- resName = CTS_THEME_dict[density]
+ # Reference images generated for tv should not be categorized by density
+ # rather by tv type. This is because TV uses leanback-specific material
+ # themes.
+ if device.getHWType() == "android.hardware.type.television":
+ resName = "tvdpi"
+ elif CTS_THEME_dict.has_key(density):
+ resName = CTS_THEME_dict[density]
else:
- resName = str(density) + "dpi"
+ resName = str(density) + "dpi"
device.uninstallApk("android.theme.app")
diff --git a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
index 5a5c63b..c87ff63 100644
--- a/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
+++ b/hostsidetests/theme/src/android/theme/cts/ThemeHostTest.java
@@ -16,7 +16,7 @@
package android.theme.cts;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.Log;
import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
@@ -94,6 +94,9 @@
private ExecutorCompletionService<File> mCompletionService;
+ /** the string identifying the hardware type. */
+ private String mHardwareType;
+
@Override
public void setAbi(IAbi abi) {
mAbi = abi;
@@ -110,13 +113,15 @@
mDevice = getDevice();
mDevice.uninstallPackage(APP_PACKAGE_NAME);
+ mHardwareType = mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim();
// Get the APK from the build.
- final File app = MigrationHelper.getTestFile(mBuildInfo, String.format("%s.apk", APK_NAME));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuildInfo);
+ final File app = buildHelper.getTestFile(String.format("%s.apk", APK_NAME));
final String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
mDevice.installPackage(app, true, true, options);
- final String density = getDensityBucketForDevice(mDevice);
+ final String density = getDensityBucketForDevice(mDevice, mHardwareType);
final String zipFile = String.format("/%s.zip", density);
mReferences = extractReferenceImages(zipFile);
@@ -150,7 +155,7 @@
fail("Failed to unzip assets: " + zipFile);
}
} else {
- if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+ if (checkHardwareTypeSkipTest(mHardwareType)) {
Log.logAndDisplay(LogLevel.WARN, LOG_TAG,
"Could not obtain resources for skipped themes test: " + zipFile);
} else {
@@ -178,7 +183,7 @@
}
public void testThemes() throws Exception {
- if (checkHardwareTypeSkipTest(mDevice.executeShellCommand(HARDWARE_TYPE_CMD).trim())) {
+ if (checkHardwareTypeSkipTest(mHardwareType)) {
Log.logAndDisplay(LogLevel.INFO, LOG_TAG, "Skipped themes test for watch");
return;
}
@@ -301,14 +306,17 @@
return receiver.getOutput().contains("OK ");
}
- private static String getDensityBucketForDevice(ITestDevice device) {
+ private static String getDensityBucketForDevice(ITestDevice device, String hardwareType) {
+ if (hardwareType.contains("android.hardware.type.television")) {
+ // references images for tv are under bucket "tvdpi".
+ return "tvdpi";
+ }
final int density;
try {
density = getDensityForDevice(device);
} catch (DeviceNotAvailableException e) {
throw new RuntimeException("Failed to detect device density", e);
}
-
final String bucket;
switch (density) {
case 120:
@@ -317,9 +325,6 @@
case 160:
bucket = "mdpi";
break;
- case 213:
- bucket = "tvdpi";
- break;
case 240:
bucket = "hdpi";
break;
@@ -360,7 +365,6 @@
}
private static boolean checkHardwareTypeSkipTest(String hardwareTypeString) {
- return hardwareTypeString.contains("android.hardware.type.watch")
- || hardwareTypeString.contains("android.hardware.type.television");
+ return hardwareTypeString.contains("android.hardware.type.watch");
}
}
diff --git a/hostsidetests/trustedvoice/Android.mk b/hostsidetests/trustedvoice/Android.mk
index 9d6237f..d80f725 100644
--- a/hostsidetests/trustedvoice/Android.mk
+++ b/hostsidetests/trustedvoice/Android.mk
@@ -23,7 +23,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsTrustedVoiceHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed ddmlib-prebuilt tradefed
LOCAL_CTS_TEST_PACKAGE := android.host.trustedvoice
diff --git a/hostsidetests/tv/Android.mk b/hostsidetests/tv/Android.mk
index bb5795b..cb5e2bd 100644
--- a/hostsidetests/tv/Android.mk
+++ b/hostsidetests/tv/Android.mk
@@ -21,9 +21,7 @@
LOCAL_MODULE := CtsHostsideTvTests
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.tv.hostsidetv
diff --git a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
index fe917ae..67cd752 100644
--- a/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
+++ b/hostsidetests/tv/src/com/android/cts/tv/TvInputManagerHostTest.java
@@ -16,9 +16,9 @@
package com.android.cts.tv;
-import com.android.ddmlib.Log.LogLevel;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.VersionCodes;
-import com.android.cts.migration.MigrationHelper;
+import com.android.ddmlib.Log.LogLevel;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.DeviceNotAvailableException;
import com.android.tradefed.device.ITestDevice;
@@ -51,8 +51,8 @@
private void installPackage(String apk) throws FileNotFoundException,
DeviceNotAvailableException {
- assertNull(getDevice().installPackage(
- MigrationHelper.getTestFile(mCtsBuildInfo, apk), true));
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mCtsBuildInfo);
+ assertNull(getDevice().installPackage(buildHelper.getTestFile(apk), true));
}
private void uninstallPackage(String packageName, boolean shouldSucceed)
diff --git a/hostsidetests/ui/Android.mk b/hostsidetests/ui/Android.mk
index 7060bdf..e2457c5 100644
--- a/hostsidetests/ui/Android.mk
+++ b/hostsidetests/ui/Android.mk
@@ -22,9 +22,7 @@
LOCAL_MODULE := CtsUiHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
diff --git a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
index 74e35fe..1b49eca 100644
--- a/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/InstallTimeTest.java
@@ -16,13 +16,13 @@
package android.ui.cts;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.MeasureRun;
import com.android.compatibility.common.util.MeasureTime;
import com.android.compatibility.common.util.MetricsReportLog;
import com.android.compatibility.common.util.ResultType;
import com.android.compatibility.common.util.ResultUnit;
import com.android.compatibility.common.util.Stat;
-import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.Log;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.build.IBuildInfo;
@@ -78,7 +78,7 @@
String.format("%s#%s", getClass().getName(), "testInstallTime"), REPORT_LOG_NAME,
streamName);
final int NUMBER_REPEAT = 10;
- final IBuildInfo build = mBuild;
+ final CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
final ITestDevice device = mDevice;
double[] result = MeasureTime.measure(NUMBER_REPEAT, new MeasureRun() {
@Override
@@ -87,7 +87,7 @@
}
@Override
public void run(int i) throws Exception {
- File app = MigrationHelper.getTestFile(build, APK);
+ File app = buildHelper.getTestFile(APK);
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
device.installPackage(app, false, options);
}
diff --git a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
index 04ee37e..9cfd957 100644
--- a/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
+++ b/hostsidetests/ui/src/android/ui/cts/TaskSwitchingTest.java
@@ -16,9 +16,9 @@
package android.ui.cts;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.compatibility.common.util.MetricsStore;
import com.android.compatibility.common.util.ReportLog;
-import com.android.cts.migration.MigrationHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestIdentifier;
import com.android.ddmlib.testrunner.TestRunResult;
@@ -77,9 +77,10 @@
super.setUp();
mDevice = getDevice();
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
for (int i = 0; i < PACKAGES.length; i++) {
mDevice.uninstallPackage(PACKAGES[i]);
- File app = MigrationHelper.getTestFile(mBuild, APKS[i]);
+ File app = buildHelper.getTestFile(APKS[i]);
mDevice.installPackage(app, false, options);
}
}
diff --git a/hostsidetests/usage/Android.mk b/hostsidetests/usage/Android.mk
index 72b9473..482ba91 100644
--- a/hostsidetests/usage/Android.mk
+++ b/hostsidetests/usage/Android.mk
@@ -21,7 +21,7 @@
# Must match the package name in CtsTestCaseList.mk
LOCAL_MODULE := CtsAppUsageHostTestCases
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed
LOCAL_CTS_TEST_PACKAGE := android.host.app.usage
diff --git a/hostsidetests/usb/Android.mk b/hostsidetests/usb/Android.mk
index a96c5d8..bc98445 100644
--- a/hostsidetests/usb/Android.mk
+++ b/hostsidetests/usb/Android.mk
@@ -21,9 +21,7 @@
LOCAL_MODULE := CtsUsbTests
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
-
-LOCAL_STATIC_JAVA_LIBRARIES := cts-migration-lib
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_CTS_TEST_PACKAGE := android.usb
diff --git a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
index fe230a3..81cc265 100644
--- a/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
+++ b/hostsidetests/usb/src/com/android/cts/usb/TestUsbTest.java
@@ -15,7 +15,7 @@
*/
package com.android.cts.usb;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
import com.android.ddmlib.testrunner.TestRunResult;
import com.android.tradefed.build.IBuildInfo;
@@ -62,7 +62,8 @@
super.setUp();
mDevice = getDevice();
mDevice.uninstallPackage(PACKAGE_NAME);
- File app = MigrationHelper.getTestFile(mBuild, APK_NAME);
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ File app = buildHelper.getTestFile(APK_NAME);
String[] options = {AbiUtils.createAbiFlag(mAbi.getName())};
mDevice.installPackage(app, false, options);
}
diff --git a/hostsidetests/webkit/Android.mk b/hostsidetests/webkit/Android.mk
index 535267c..6fe433c 100644
--- a/hostsidetests/webkit/Android.mk
+++ b/hostsidetests/webkit/Android.mk
@@ -21,7 +21,7 @@
LOCAL_MODULE := CtsHostsideWebViewTests
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
LOCAL_CTS_TEST_PACKAGE := android.webkit.hostside
diff --git a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
index 4359bf4..b91efb7 100644
--- a/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
+++ b/hostsidetests/webkit/app/src/com/android/cts/webkit/WebViewDeviceSideStartupTest.java
@@ -16,7 +16,8 @@
package com.android.cts.webkit;
-
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.cts.util.NullWebViewUtils;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
@@ -25,6 +26,7 @@
import android.webkit.CookieSyncManager;
import android.webkit.cts.CtsTestServer;
import android.webkit.cts.WebViewOnUiThread;
+import android.webkit.WebView;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -36,6 +38,8 @@
* once - after that we will reuse the same webview provider).
* This works because the instrumentation used to run device-tests from the host-side terminates the
* testing process after each run.
+ * OBS! When adding a test here - remember to add a corresponding host-side test that will start the
+ * device-test added here! See com.android.cts.webkit.WebViewHostSideStartupTest.
*/
public class WebViewDeviceSideStartupTest
extends ActivityInstrumentationTestCase2<WebViewStartupCtsActivity> {
@@ -95,4 +99,49 @@
assertTrue(m.matches());
assertEquals("42", m.group(1)); // value got incremented
}
+
+ @UiThreadTest
+ public void testGetCurrentWebViewPackageOnUiThread() throws Throwable {
+ runCurrentWebViewPackageTest(true /* alreadyOnMainThread */);
+ }
+
+ public void testGetCurrentWebViewPackage() throws Throwable {
+ runCurrentWebViewPackageTest(false /* alreadyOnMainThread */);
+ }
+
+ private void runCurrentWebViewPackageTest(boolean alreadyOnMainThread) throws Exception {
+ PackageManager pm = mActivity.getPackageManager();
+ if (pm.hasSystemFeature(PackageManager.FEATURE_WEBVIEW)) {
+ PackageInfo webViewPackage = WebView.getCurrentWebViewPackage();
+ // Ensure that getCurrentWebViewPackage returns a package recognized by the package
+ // manager.
+ assertPackageEquals(pm.getPackageInfo(webViewPackage.packageName, 0), webViewPackage);
+
+ // Create WebView on the app's main thread
+ if (alreadyOnMainThread) {
+ mActivity.createAndAttachWebView();
+ } else {
+ getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mActivity.createAndAttachWebView();
+ }
+ });
+ }
+
+ // Ensure we are still using the same WebView package.
+ assertPackageEquals(webViewPackage, WebView.getCurrentWebViewPackage());
+ } else {
+ // if WebView isn't supported the API should return null.
+ assertNull(WebView.getCurrentWebViewPackage());
+ }
+ }
+
+ private void assertPackageEquals(PackageInfo expected, PackageInfo actual) {
+ if (expected == null) assertNull(actual);
+ assertEquals(expected.packageName, actual.packageName);
+ assertEquals(expected.versionCode, actual.versionCode);
+ assertEquals(expected.versionName, actual.versionName);
+ assertEquals(expected.lastUpdateTime, actual.lastUpdateTime);
+ }
}
diff --git a/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
index ba37beb..90f24f7 100644
--- a/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
+++ b/hostsidetests/webkit/src/com/android/cts/webkit/WebViewHostSideStartupTest.java
@@ -39,6 +39,16 @@
"testCookieManagerBlockingUiThread"));
}
+ public void testWebViewVersionApiOnUiThread() throws DeviceNotAvailableException {
+ assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+ "testGetCurrentWebViewPackageOnUiThread"));
+ }
+
+ public void testWebViewVersionApi() throws DeviceNotAvailableException {
+ assertTrue(runDeviceTest(DEVICE_WEBVIEW_STARTUP_PKG, DEVICE_WEBVIEW_STARTUP_TEST_CLASS,
+ "testGetCurrentWebViewPackage"));
+ }
+
private boolean runDeviceTest(String packageName, String testClassName,
String testMethodName) throws DeviceNotAvailableException {
testClassName = packageName + "." + testClassName;
diff --git a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java b/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
index f691150..decbd4c 100644
--- a/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
+++ b/libs/deviceutil/src/android/cts/util/MediaPerfUtils.java
@@ -54,14 +54,15 @@
public static String addPerformanceHeadersToLog(
DeviceReportLog log, String message, int round, String codecName,
MediaFormat configFormat, MediaFormat inputFormat, MediaFormat outputFormat) {
+ String mime = configFormat.getString(MediaFormat.KEY_MIME);
+ int width = configFormat.getInteger(MediaFormat.KEY_WIDTH);
+ int height = configFormat.getInteger(MediaFormat.KEY_HEIGHT);
+
log.addValue("round", round, ResultType.NEUTRAL, ResultUnit.NONE);
log.addValue("codec_name", codecName, ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("mime_type", configFormat.getString(MediaFormat.KEY_MIME),
- ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("width", configFormat.getInteger(MediaFormat.KEY_WIDTH),
- ResultType.NEUTRAL, ResultUnit.NONE);
- log.addValue("height", configFormat.getInteger(MediaFormat.KEY_HEIGHT),
- ResultType.NEUTRAL, ResultUnit.NONE);
+ log.addValue("mime_type", mime, ResultType.NEUTRAL, ResultUnit.NONE);
+ log.addValue("width", width, ResultType.NEUTRAL, ResultUnit.NONE);
+ log.addValue("height", height, ResultType.NEUTRAL, ResultUnit.NONE);
log.addValue("config_format", formatForReport(configFormat),
ResultType.NEUTRAL, ResultUnit.NONE);
log.addValue("input_format", formatForReport(inputFormat),
@@ -71,6 +72,16 @@
message += " codec=" + codecName + " round=" + round + " configFormat=" + configFormat
+ " inputFormat=" + inputFormat + " outputFormat=" + outputFormat;
+
+ Range<Double> reported =
+ MediaUtils.getVideoCapabilities(codecName, mime)
+ .getAchievableFrameRatesFor(width, height);
+ if (reported != null) {
+ log.addValue("reported_low", reported.getLower(), ResultType.NEUTRAL, ResultUnit.FPS);
+ log.addValue("reported_high", reported.getUpper(), ResultType.NEUTRAL, ResultUnit.FPS);
+ message += " reported=" + reported.getLower() + "-" + reported.getUpper();
+ }
+
return message;
}
diff --git a/libs/migration/Android.mk b/libs/migration/Android.mk
deleted file mode 100644
index 11173d6..0000000
--- a/libs/migration/Android.mk
+++ /dev/null
@@ -1,34 +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.
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt
-
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_MODULE := cts-migration-lib
-
-# Tag this module as a cts test artifact
-LOCAL_COMPATIBILITY_SUITE := cts
-
-LOCAL_SDK_VERSION := current
-
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/libs/migration/src/com/android/cts/migration/MigrationHelper.java b/libs/migration/src/com/android/cts/migration/MigrationHelper.java
deleted file mode 100644
index 0595486..0000000
--- a/libs/migration/src/com/android/cts/migration/MigrationHelper.java
+++ /dev/null
@@ -1,59 +0,0 @@
-package com.android.cts.migration;
-
-import com.android.tradefed.build.IBuildInfo;
-import com.android.tradefed.log.LogUtil.CLog;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.lang.reflect.Constructor;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-
-/**
- * A temporary helper to enable tests to work with both cts v1 and v2.
- */
-public class MigrationHelper {
-
- private static final String COMPATIBILITY_BUILD_HELPER =
- "com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper";
- private static final String CTS_BUILD_HELPER =
- "com.android.cts.tradefed.build.CtsBuildHelper";
-
- public static File getTestFile(IBuildInfo mBuild, String filename)
- throws FileNotFoundException {
- try {
- Class<?> cls = Class.forName(COMPATIBILITY_BUILD_HELPER);
- Constructor<?> cons = cls.getConstructor(IBuildInfo.class);
- Object instance = cons.newInstance(mBuild);
- Method method = cls.getMethod("getTestsDir");
- File dir = (File) method.invoke(instance);
- File file = new File(dir, filename);
- CLog.i("Looking for test file %s in dir %s", filename, dir.getAbsolutePath());
- if (file.exists()) {
- CLog.i("File %s found", filename);
- return file;
- }
- } catch (ClassNotFoundException | NoSuchMethodException | InstantiationException |
- IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
- // Ignore and fall back to CtsBuildHelper
- }
- try {
- Class<?> cls = Class.forName(CTS_BUILD_HELPER);
- Method builder = cls.getMethod("createBuildHelper", IBuildInfo.class);
- Object helper = builder.invoke(null, mBuild);
- Method method = cls.getMethod("getTestApp", String.class);
- File file = (File) method.invoke(helper, filename);
- CLog.i("Looking for test file %s as %s", filename, file.getAbsolutePath());
- if (file.exists()) {
- CLog.i("File %s found", filename);
- return file;
- }
- } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException |
- IllegalArgumentException | InvocationTargetException e) {
- // Ignore
- }
- throw new FileNotFoundException("Couldn't load file " + filename);
- }
-
-}
diff --git a/test_defs.sh b/test_defs.sh
index 5d5090d..cc92685 100644
--- a/test_defs.sh
+++ b/test_defs.sh
@@ -22,7 +22,7 @@
COMMON_JARS="
ddmlib-prebuilt\
hosttestlib\
- tradefed-prebuilt"
+ tradefed"
checkFile() {
if [ ! -f "$1" ]; then
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
index 1256546..4ce99ce 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityManagerTest.java
@@ -173,7 +173,7 @@
}
public void testInterrupt() throws Exception {
- // The APIs are heavily tested in the android.accessibiliyservice package.
+ // The APIs are heavily tested in the android.accessibilityservice package.
// This just makes sure the call does not throw an exception.
waitForAccessibilityEnabled();
mAccessibilityManager.interrupt();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
index ce096fe..220ea5e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEndToEndTest.java
@@ -30,6 +30,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.view.accessibility.AccessibilityEvent;
+import android.view.accessibility.AccessibilityManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
@@ -330,7 +331,7 @@
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
try {
// create the notification to send
- channel.setVibration(true);
+ channel.enableVibration(true);
channel.setLights(true);
channel.setBypassDnd(true);
notificationManager.createNotificationChannel(channel);
@@ -390,6 +391,37 @@
}
}
+ @MediumTest
+ public void testInterrupt_notifiesService() {
+ getInstrumentation()
+ .getUiAutomation(UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES);
+ InstrumentedAccessibilityService service = InstrumentedAccessibilityService.enableService(
+ this, InstrumentedAccessibilityService.class);
+ try {
+ assertFalse(service.wasOnInterruptCalled());
+
+ getActivity().runOnUiThread(() -> {
+ AccessibilityManager accessibilityManager = (AccessibilityManager) getActivity()
+ .getSystemService(Service.ACCESSIBILITY_SERVICE);
+ accessibilityManager.interrupt();
+ });
+
+ Object waitObject = service.getInterruptWaitObject();
+ synchronized (waitObject) {
+ if (!service.wasOnInterruptCalled()) {
+ try {
+ waitObject.wait(TIMEOUT_ASYNC_PROCESSING);
+ } catch (InterruptedException e) {
+ // Do nothing
+ }
+ }
+ }
+ assertTrue(service.wasOnInterruptCalled());
+ } finally {
+ service.disableSelfAndRemove();
+ }
+ }
+
/**
* Compares all properties of the <code>first</code> and the
* <code>second</code>.
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
index 127b6cc..486e4fa 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGlobalActionsTest.java
@@ -107,8 +107,11 @@
waitForIdle();
// Clean up.
+ // The GLOBAL_ACTION_HOME is needed in the case where additional
+ // notifications showing up, we need to clear them as well for the upcoming
+ // new tests to work properly.
getInstrumentation().getUiAutomation().performGlobalAction(
- AccessibilityService.GLOBAL_ACTION_BACK);
+ AccessibilityService.GLOBAL_ACTION_HOME);
// Sleep a bit so the UI is settled.
waitForIdle();
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
index 4a9ce08..31c78c5 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/InstrumentedAccessibilityService.java
@@ -30,6 +30,9 @@
sInstances = new HashMap<>();
private final Handler mHandler = new Handler();
+ final Object mInterruptWaitObject = new Object();
+ public boolean mOnInterruptCalled;
+
@Override
protected void onServiceConnected() {
@@ -53,7 +56,10 @@
@Override
public void onInterrupt() {
- // Stub method.
+ synchronized (mInterruptWaitObject) {
+ mOnInterruptCalled = true;
+ mInterruptWaitObject.notifyAll();
+ }
}
public void disableSelfAndRemove() {
@@ -70,6 +76,16 @@
assertTrue("Timed out waiting for runOnServiceSync()", sr.waitForComplete());
}
+ public boolean wasOnInterruptCalled() {
+ synchronized (mInterruptWaitObject) {
+ return mOnInterruptCalled;
+ }
+ }
+
+ public Object getInterruptWaitObject() {
+ return mInterruptWaitObject;
+ }
+
private static final class SyncRunnable implements Runnable {
private final CountDownLatch mLatch = new CountDownLatch(1);
private final Runnable mTarget;
diff --git a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
index 543a385..deb1854 100644
--- a/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
+++ b/tests/admin/src/android/admin/cts/DevicePolicyManagerTest.java
@@ -671,11 +671,13 @@
}
/**
- * Test that managed provisioning is pre-installed if and only if the device declares the
- * device admin feature.
+ * Test that managed provisioning is pre-installed if the device declares the device admin
+ * feature.
*/
public void testManagedProvisioningPreInstalled() throws Exception {
- assertEquals(mDeviceAdmin, isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
+ if (mDeviceAdmin) {
+ assertTrue(isPackageInstalledOnSystemImage(MANAGED_PROVISIONING_PKG));
+ }
}
private void assertDeviceOwnerMessage(String message) {
diff --git a/tests/app/src/android/app/cts/NotificationChannelTest.java b/tests/app/src/android/app/cts/NotificationChannelTest.java
index 943f0bf..cf96532 100644
--- a/tests/app/src/android/app/cts/NotificationChannelTest.java
+++ b/tests/app/src/android/app/cts/NotificationChannelTest.java
@@ -45,7 +45,7 @@
assertEquals(false, channel.shouldShowLights());
assertEquals(false, channel.shouldVibrate());
assertEquals(NotificationManager.IMPORTANCE_DEFAULT, channel.getImportance());
- assertEquals(null, channel.getRingtone());
+ assertEquals(null, channel.getSound());
}
public void testWriteToParcel() {
@@ -70,18 +70,27 @@
public void testVibration() {
NotificationChannel channel =
new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
- channel.setVibration(true);
+ channel.enableVibration(true);
assertTrue(channel.shouldVibrate());
- channel.setVibration(false);
+ channel.enableVibration(false);
assertFalse(channel.shouldVibrate());
}
+ public void testVibrationPattern() {
+ final long[] pattern = new long[] {1, 7, 1, 7, 3};
+ NotificationChannel channel =
+ new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
+ assertNull(channel.getVibrationPattern());
+ channel.setVibrationPattern(pattern);
+ assertEquals(pattern, channel.getVibrationPattern());
+ }
+
public void testRingtone() {
Uri expected = new Uri.Builder().scheme("fruit").appendQueryParameter("favorite", "bananas")
.build();
NotificationChannel channel =
new NotificationChannel("1", "one", NotificationManager.IMPORTANCE_DEFAULT);
- channel.setRingtone(expected);
- assertEquals(expected, channel.getRingtone());
+ channel.setSound(expected);
+ assertEquals(expected, channel.getSound());
}
}
diff --git a/tests/app/src/android/app/cts/NotificationManagerTest.java b/tests/app/src/android/app/cts/NotificationManagerTest.java
index 672e5af..7cc5d6a 100644
--- a/tests/app/src/android/app/cts/NotificationManagerTest.java
+++ b/tests/app/src/android/app/cts/NotificationManagerTest.java
@@ -24,13 +24,14 @@
import android.content.Intent;
import android.net.Uri;
import android.provider.Telephony.Threads;
-import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.test.AndroidTestCase;
import android.util.Log;
import android.app.stubs.R;
+import java.util.Arrays;
+
public class NotificationManagerTest extends AndroidTestCase {
final String TAG = NotificationManagerTest.class.getSimpleName();
final boolean DEBUG = false;
@@ -55,8 +56,9 @@
public void testCreateChannel() {
NotificationChannel channel =
new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
- channel.setVibration(true);
- channel.setRingtone(new Uri.Builder().scheme("test").build());
+ channel.enableVibration(true);
+ channel.setVibrationPattern(new long[] {5, 8, 2, 1});
+ channel.setSound(new Uri.Builder().scheme("test").build());
channel.setLights(true);
channel.setBypassDnd(true);
channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
@@ -248,7 +250,8 @@
assertEquals(expected.shouldShowLights(), actual.shouldShowLights());
assertEquals(expected.getImportance(), actual.getImportance());
assertEquals(expected.getLockscreenVisibility(), actual.getLockscreenVisibility());
- assertEquals(expected.getRingtone(), actual.getRingtone());
+ assertEquals(expected.getSound(), actual.getSound());
assertEquals(expected.canBypassDnd(), actual.canBypassDnd());
+ assertTrue(Arrays.equals(expected.getVibrationPattern(), actual.getVibrationPattern()));
}
}
diff --git a/tests/app/src/android/app/cts/SystemFeaturesTest.java b/tests/app/src/android/app/cts/SystemFeaturesTest.java
index aca79fc..1a6bf4c 100644
--- a/tests/app/src/android/app/cts/SystemFeaturesTest.java
+++ b/tests/app/src/android/app/cts/SystemFeaturesTest.java
@@ -467,6 +467,10 @@
}
public void testUsbAccessory() {
+ // USB accessory mode is only a requirement for devices with USB ports supporting
+ // peripheral mode. As there is no public API to distinguish a device with only host
+ // mode support from having both peripheral and host support, the test may have
+ // false negatives.
if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) &&
!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEVISION) &&
!mPackageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
diff --git a/tests/backup/src/android/backup/cts/BackupQuotaTest.java b/tests/backup/src/android/backup/cts/BackupQuotaTest.java
index 6e211f8..bec28c7 100644
--- a/tests/backup/src/android/backup/cts/BackupQuotaTest.java
+++ b/tests/backup/src/android/backup/cts/BackupQuotaTest.java
@@ -156,10 +156,6 @@
out.append(str);
}
return out.toString();
- } finally {
- if (br != null) {
- closeQuietly(br);
- }
}
}
@@ -167,7 +163,7 @@
String command) throws Exception {
final ParcelFileDescriptor pfd =
instrumentation.getUiAutomation().executeShellCommand(command);
- return new FileInputStream(pfd.getFileDescriptor());
+ return new ParcelFileDescriptor.AutoCloseInputStream(pfd);
}
private static void closeQuietly(AutoCloseable closeable) {
diff --git a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
index 2969753..bbc4c75 100644
--- a/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/AllocationTest.java
@@ -494,6 +494,10 @@
});
stopCapture();
+ if (VERBOSE) Log.v(TAG, "Cleanup Renderscript cache");
+ scriptGraph.close();
+ RenderScriptSingleton.clearContext();
+ RenderScriptSingleton.setContext(getContext());
}
}
});
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 67c08fe..11071fc 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -149,11 +149,13 @@
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_EXTERNAL));
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
} else if (lensFacing == CameraCharacteristics.LENS_FACING_BACK) {
assertTrue("System doesn't have back camera feature",
mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA));
+ } else if (lensFacing == CameraCharacteristics.LENS_FACING_EXTERNAL) {
+ assertTrue("System doesn't have external camera feature",
+ mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
} else {
fail("Unknown camera lens facing " + lensFacing.toString());
}
@@ -166,10 +168,11 @@
assertTrue("Missing system feature: FEATURE_CAMERA_ANY",
ids.length == 0
|| mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY));
- assertTrue("Missing system feature: FEATURE_CAMERA or FEATURE_CAMERA_FRONT",
+ assertTrue("Missing system feature: FEATURE_CAMERA, FEATURE_CAMERA_FRONT or FEATURE_CAMERA_EXTERNAL",
ids.length == 0
|| mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA)
- || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT));
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT)
+ || mPackageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_EXTERNAL));
}
// Test: that properties can be queried from each device, without exceptions.
diff --git a/tests/fragment/res/layout/nested_inflated_fragment_child.xml b/tests/fragment/res/layout/nested_inflated_fragment_child.xml
new file mode 100644
index 0000000..9a11bc4
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_child.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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="match_parent"
+ android:layout_height="wrap_content"
+ android:text="Test" />
+</LinearLayout>
diff --git a/tests/fragment/res/layout/nested_inflated_fragment_parent.xml b/tests/fragment/res/layout/nested_inflated_fragment_parent.xml
new file mode 100644
index 0000000..026ba45
--- /dev/null
+++ b/tests/fragment/res/layout/nested_inflated_fragment_parent.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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">
+ <fragment android:name="android.fragment.cts.NestedInflatedFragmentTest$InflatedChildFragment"
+ android:id="@+id/child_fragment"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
+</LinearLayout>
diff --git a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
index 89812c3..0d71a34 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentLifecycleTest.java
@@ -17,26 +17,39 @@
package android.fragment.cts;
-import android.app.FragmentController;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertNotSame;
+import static junit.framework.TestCase.assertNull;
+import static junit.framework.TestCase.assertSame;
+import static junit.framework.TestCase.assertTrue;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentController;
import android.app.FragmentHostCallback;
import android.app.FragmentManager;
import android.app.FragmentManager.FragmentLifecycleCallbacks;
+import android.app.FragmentManagerNonConfig;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
-import android.os.Debug;
+import android.os.Parcelable;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.test.suitebuilder.annotation.MediumTest;
+import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-
import android.view.Window;
import android.widget.TextView;
+
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -44,12 +57,6 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
-import static junit.framework.Assert.assertNotNull;
-import static junit.framework.TestCase.*;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
-
@MediumTest
@RunWith(AndroidJUnit4.class)
public class FragmentLifecycleTest {
@@ -393,6 +400,47 @@
});
}
+ /**
+ * Test to ensure that when dispatch* is called that the fragment manager
+ * doesn't cause the contained fragment states to change even if no state changes.
+ */
+ @Test
+ public void noPrematureStateChange() throws Throwable {
+ final FragmentController fc = FragmentTestUtil.createController(mActivityRule);
+ FragmentTestUtil.resume(mActivityRule, fc, null);
+
+ mActivityRule.runOnUiThread(() -> {
+ fc.getFragmentManager().beginTransaction()
+ .add(new StrictFragment(), "1")
+ .commitNow();
+ });
+
+ Pair<Parcelable, FragmentManagerNonConfig> savedState =
+ FragmentTestUtil.destroy(mActivityRule, fc);
+
+ final FragmentController fragmentController = FragmentTestUtil.createController(mActivityRule);
+
+ mActivityRule.runOnUiThread(() -> {
+ fragmentController.attachHost(null);
+ fragmentController.dispatchCreate();
+ fragmentController.dispatchActivityCreated();
+ fragmentController.noteStateNotSaved();
+ fragmentController.execPendingActions();
+ fragmentController.dispatchStart();
+ fragmentController.reportLoaderStart();
+ fragmentController.dispatchResume();
+ fragmentController.restoreAllState(savedState.first, savedState.second);
+ fragmentController.dispatchResume();
+ });
+
+ FragmentManager fm = fragmentController.getFragmentManager();
+
+ StrictFragment fragment1 = (StrictFragment) fm.findFragmentByTag("1");
+
+ assertNotNull(fragment1);
+ assertFalse(fragment1.mCalledOnResume);
+ }
+
private void executePendingTransactions(final FragmentManager fm) throws Throwable {
mActivityRule.runOnUiThread(new Runnable() {
@Override
diff --git a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
index aec626f..5e66722 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentTransitionTest.java
@@ -25,11 +25,13 @@
import android.app.Fragment;
import android.app.FragmentManager;
+import android.app.FragmentTransaction;
import android.app.Instrumentation;
import android.app.SharedElementCallback;
import android.cts.util.transition.TargetTracking;
import android.cts.util.transition.TrackingTransition;
import android.graphics.Rect;
+import android.os.Bundle;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
@@ -594,6 +596,109 @@
verifyNoOtherTransitions(fragment2);
}
+ // Ensure that shared element without matching transition name doesn't error out
+ @Test
+ public void sharedElementMismatch() throws Throwable {
+ final TransitionFragment fragment1 = setupInitialFragment();
+
+ // Now do a transition to scene2
+ TransitionFragment fragment2 = new TransitionFragment();
+ fragment2.setLayoutId(R.layout.scene2);
+
+ final View startBlue = findBlue();
+ final View startGreen = findGreen();
+ final Rect startBlueBounds = getBoundsOnScreen(startBlue);
+
+ mFragmentManager.beginTransaction()
+ .addSharedElement(startBlue, "fooSquare")
+ .replace(R.id.fragmentContainer, fragment2)
+ .setAllowOptimization(mOptimize)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+
+ fragment1.waitForTransition();
+ fragment2.waitForTransition();
+
+ final View endBlue = findBlue();
+ final View endGreen = findGreen();
+
+ if (mOptimize) {
+ verifyAndClearTransition(fragment1.exitTransition, null, startGreen, startBlue);
+ } else {
+ verifyAndClearTransition(fragment1.exitTransition, startBlueBounds, startGreen);
+ verifyAndClearTransition(fragment2.sharedElementEnter, startBlueBounds, startBlue);
+ }
+ verifyNoOtherTransitions(fragment1);
+
+ verifyAndClearTransition(fragment2.enterTransition, null, endGreen, endBlue);
+ verifyNoOtherTransitions(fragment2);
+ }
+
+ // Ensure that using the same source or target shared element results in an exception.
+ @Test
+ public void sharedDuplicateTargetNames() throws Throwable {
+ setupInitialFragment();
+
+ final View startBlue = findBlue();
+ final View startGreen = findGreen();
+
+ FragmentTransaction ft = mFragmentManager.beginTransaction();
+ ft.addSharedElement(startBlue, "blueSquare");
+ try {
+ ft.addSharedElement(startGreen, "blueSquare");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+
+ try {
+ ft.addSharedElement(startBlue, "greenSquare");
+ fail("Expected IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ // Test that invisible fragment views don't participate in transitions
+ @Test
+ public void invisibleNoTransitions() throws Throwable {
+ if (!mOptimize) {
+ return; // only optimized transitions can avoid interaction
+ }
+ // enter transition
+ TransitionFragment fragment = new InvisibleFragment();
+ fragment.setLayoutId(R.layout.scene1);
+ mFragmentManager.beginTransaction()
+ .setAllowOptimization(mOptimize)
+ .add(R.id.fragmentContainer, fragment)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.waitForExecution(mActivityRule);
+ fragment.waitForNoTransition();
+ verifyNoOtherTransitions(fragment);
+
+ // exit transition
+ mFragmentManager.beginTransaction()
+ .setAllowOptimization(mOptimize)
+ .remove(fragment)
+ .addToBackStack(null)
+ .commit();
+
+ fragment.waitForNoTransition();
+ verifyNoOtherTransitions(fragment);
+
+ // reenter transition
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+ fragment.waitForNoTransition();
+ verifyNoOtherTransitions(fragment);
+
+ // return transition
+ FragmentTestUtil.popBackStackImmediate(mActivityRule);
+ fragment.waitForNoTransition();
+ verifyNoOtherTransitions(fragment);
+ }
+
private TransitionFragment setupInitialFragment() throws Throwable {
TransitionFragment fragment1 = new TransitionFragment();
fragment1.setLayoutId(R.layout.scene1);
@@ -856,6 +961,13 @@
setSharedElementEnterTransition(sharedElementEnterTransition);
setSharedElementReturnTransition(sharedElementReturnTransition);
}
+ }
+ public static class InvisibleFragment extends TransitionFragment {
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ view.setVisibility(View.INVISIBLE);
+ super.onViewCreated(view, savedInstanceState);
+ }
}
}
diff --git a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
index 1599307..82890df 100644
--- a/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
+++ b/tests/fragment/src/android/fragment/cts/FragmentViewTests.java
@@ -24,6 +24,7 @@
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.Instrumentation;
+import android.os.Bundle;
import android.os.Debug;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
@@ -870,6 +871,34 @@
assertNotNull(findViewById(R.id.textC));
}
+ // Test that adding a fragment with invisible or gone views does not end up with the view
+ // being visible
+ @Test
+ public void addInvisibleAndGoneFragments() throws Throwable {
+ FragmentTestUtil.setContentView(mActivityRule, R.layout.simple_container);
+ ViewGroup container = (ViewGroup)
+ mActivityRule.getActivity().findViewById(R.id.fragmentContainer);
+ final FragmentManager fm = mActivityRule.getActivity().getFragmentManager();
+
+ final StrictViewFragment fragment1 = new InvisibleFragment();
+ fm.beginTransaction().add(R.id.fragmentContainer, fragment1).addToBackStack(null).commit();
+ FragmentTestUtil.executePendingTransactions(mActivityRule);
+ FragmentTestUtil.assertChildren(container, fragment1);
+
+ assertEquals(View.INVISIBLE, fragment1.getView().getVisibility());
+
+ final InvisibleFragment fragment2 = new InvisibleFragment();
+ fragment2.visibility = View.GONE;
+ fm.beginTransaction()
+ .replace(R.id.fragmentContainer, fragment2)
+ .addToBackStack(null)
+ .commit();
+ FragmentTestUtil.executePendingTransactions(mActivityRule);
+ FragmentTestUtil.assertChildren(container, fragment2);
+
+ assertEquals(View.GONE, fragment2.getView().getVisibility());
+ }
+
private View findViewById(int viewId) {
return mActivityRule.getActivity().findViewById(viewId);
}
@@ -883,4 +912,13 @@
fragments[i].getView());
}
}
-}
+
+ public static class InvisibleFragment extends StrictViewFragment {
+ public int visibility = View.INVISIBLE;
+
+ @Override
+ public void onViewCreated(View view, Bundle savedInstanceState) {
+ view.setVisibility(visibility);
+ super.onViewCreated(view, savedInstanceState);
+ }
+ }}
diff --git a/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
new file mode 100644
index 0000000..e24eb39
--- /dev/null
+++ b/tests/fragment/src/android/fragment/cts/NestedInflatedFragmentTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.fragment.cts;
+
+import android.app.Fragment;
+import android.app.FragmentManager;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.MediumTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class NestedInflatedFragmentTest {
+ private static final String TAG = "NestedInflatedFragmentTest";
+
+ @Rule
+ public ActivityTestRule<FragmentTestActivity> mActivityRule =
+ new ActivityTestRule<>(FragmentTestActivity.class);
+
+ @Test
+ public void inflatedChildFragment() throws Throwable {
+ mActivityRule.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ final FragmentTestActivity activity = mActivityRule.getActivity();
+ final FragmentManager fm = activity.getFragmentManager();
+
+ ParentFragment parentFragment = new ParentFragment();
+ fm.beginTransaction().add(android.R.id.content, parentFragment).commitNow();
+
+ fm.beginTransaction().replace(android.R.id.content, new SimpleFragment())
+ .addToBackStack(null).commit();
+ fm.executePendingTransactions();
+
+ fm.popBackStackImmediate();
+ }
+ });
+ }
+
+ public static class ParentFragment extends Fragment {
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.nested_inflated_fragment_parent, container, false);
+ }
+ }
+
+ public static class InflatedChildFragment extends Fragment {
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ return inflater.inflate(R.layout.nested_inflated_fragment_child, container, false);
+ }
+ }
+
+ public static class SimpleFragment extends Fragment {
+ @Nullable
+ @Override
+ public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
+ @Nullable Bundle savedInstanceState) {
+ TextView textView = new TextView(inflater.getContext());
+ textView.setText("Simple fragment");
+ return textView;
+ }
+ }
+}
diff --git a/tests/fragment/src/android/fragment/cts/TransitionFragment.java b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
index 3fede11..6513691 100644
--- a/tests/fragment/src/android/fragment/cts/TransitionFragment.java
+++ b/tests/fragment/src/android/fragment/cts/TransitionFragment.java
@@ -53,9 +53,11 @@
setSharedElementEnterTransition(sharedElementEnter);
setSharedElementReturnTransition(sharedElementReturn);
enterTransition.addListener(mListener);
+ sharedElementEnter.addListener(mListener);
reenterTransition.addListener(mListener);
exitTransition.addListener(mListener);
returnTransition.addListener(mListener);
+ sharedElementReturn.addListener(mListener);
}
@Override
diff --git a/tests/jdwp/runner/host-side/Android.mk b/tests/jdwp/runner/host-side/Android.mk
index 426663d..7398f69 100644
--- a/tests/jdwp/runner/host-side/Android.mk
+++ b/tests/jdwp/runner/host-side/Android.mk
@@ -20,7 +20,7 @@
LOCAL_MODULE := cts-dalvik-host-test-runner
-LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed-prebuilt compatibility-host-util
+LOCAL_JAVA_LIBRARIES := cts-tradefed tradefed compatibility-host-util
LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib
diff --git a/tests/libcore/luni/Android.mk b/tests/libcore/luni/Android.mk
index 1879367..f722f5fe 100644
--- a/tests/libcore/luni/Android.mk
+++ b/tests/libcore/luni/Android.mk
@@ -24,6 +24,7 @@
core-tests \
cts-core-test-runner \
mockito-target-minus-junit4 \
+ tzdata_update2-tests \
tzdata_update-tests
# Don't include this package in any target
diff --git a/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
index 2da6a3b..b096987 100644
--- a/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/sensor/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -222,17 +222,17 @@
deviceWakeUpTimeMs = -1;
}
builder.append("\n");
- builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
- builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
- append("ms, ");
+ builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+ builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+ append("us, ");
builder.append("Accuracy=").append(event.accuracy).append(", ");
builder.append("Values=").append(Arrays.toString(event.values));
++i;
} else {
builder.append("\n");
builder.append("ReceivedTimestamp=")
- .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
- .append("ms Flush complete Event");
+ .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+ .append("us Flush complete Event");
++j;
}
}
@@ -245,17 +245,17 @@
deviceWakeUpTimeMs = -1;
}
builder.append("\n");
- builder.append("Timestamp=").append(event.timestamp/1000000).append("ms, ");
- builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000000).
- append("ms, ");
+ builder.append("Timestamp=").append(event.timestamp/1000).append("us, ");
+ builder.append("ReceivedTimestamp=").append(event.receivedTimestamp/1000).
+ append("us, ");
builder.append("Accuracy=").append(event.accuracy).append(", ");
builder.append("Values=").append(Arrays.toString(event.values));
}
for (;j < mTimeStampFlushCompleteEvents.size(); ++j) {
builder.append("\n");
builder.append("ReceivedTimestamp=")
- .append(mTimeStampFlushCompleteEvents.get(j)/1000000)
- .append("ms Flush complete Event");
+ .append(mTimeStampFlushCompleteEvents.get(j)/1000)
+ .append("us Flush complete Event");
}
}
diff --git a/tests/signature/src/android/signature/cts/JDiffClassDescription.java b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
index 0cba3b4..35e97d0 100644
--- a/tests/signature/src/android/signature/cts/JDiffClassDescription.java
+++ b/tests/signature/src/android/signature/cts/JDiffClassDescription.java
@@ -31,6 +31,7 @@
import java.util.HashSet;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import java.util.Set;
/**
@@ -759,7 +760,12 @@
field.toReadableString(mAbsoluteClassName),
"Non-compatible field modifiers found when looking for " +
field.toSignatureString());
- } else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
+ } else if (!checkFieldValueCompliance(field, f)) {
+ mResultObserver.notifyFailure(FailureType.MISMATCH_FIELD,
+ field.toReadableString(mAbsoluteClassName),
+ "Incorrect field value found when looking for " +
+ field.toSignatureString());
+ }else if (!f.getType().getCanonicalName().equals(field.mFieldType)) {
// type name does not match, but this might be a generic
String genericTypeName = null;
Type type = f.getGenericType();
@@ -787,6 +793,194 @@
}
/**
+ * Checks whether the field values are compatible.
+ *
+ * @param apiField The field as defined by the platform API.
+ * @param deviceField The field as defined by the device under test.
+ */
+ private boolean checkFieldValueCompliance(JDiffField apiField, Field deviceField)
+ throws IllegalAccessException {
+ if ((apiField.mModifier & Modifier.FINAL) == 0 ||
+ (apiField.mModifier & Modifier.STATIC) == 0) {
+ // Only final static fields can have fixed values.
+ return true;
+ }
+ if (apiField.getValueString() == null) {
+ // If we don't define a constant value for it, then it can be anything.
+ return true;
+ }
+ // Some fields may be protected or package-private
+ deviceField.setAccessible(true);
+ switch(apiField.mFieldType) {
+ case "byte":
+ return Objects.equals(apiField.getValueString(),
+ Byte.toString(deviceField.getByte(null)));
+ case "char":
+ return Objects.equals(apiField.getValueString(),
+ Integer.toString(deviceField.getChar(null)));
+ case "short":
+ return Objects.equals(apiField.getValueString(),
+ Short.toString(deviceField.getShort(null)));
+ case "int":
+ return Objects.equals(apiField.getValueString(),
+ Integer.toString(deviceField.getInt(null)));
+ case "long":
+ return Objects.equals(apiField.getValueString(),
+ Long.toString(deviceField.getLong(null)) + "L");
+ case "float":
+ return Objects.equals(apiField.getValueString(),
+ canonicalizeFloatingPoint(
+ Float.toString(deviceField.getFloat(null)), "f"));
+ case "double":
+ return Objects.equals(apiField.getValueString(),
+ canonicalizeFloatingPoint(
+ Double.toString(deviceField.getDouble(null)), ""));
+ case "boolean":
+ return Objects.equals(apiField.getValueString(),
+ Boolean.toString(deviceField.getBoolean(null)));
+ case "java.lang.String":
+ String value = apiField.getValueString();
+ // Remove the quotes the value string is wrapped in
+ value = unescapeFieldStringValue(value.substring(1, value.length() - 1));
+ return Objects.equals(value, deviceField.get(null));
+ default:
+ return true;
+ }
+ }
+
+ /**
+ * Canonicalize the string representation of floating point numbers.
+ *
+ * This needs to be kept in sync with the doclava canonicalization.
+ */
+ private static final String canonicalizeFloatingPoint(String val, String suffix) {
+ if (val.equals("Infinity")) {
+ return "(1.0" + suffix + "/0.0" + suffix + ")";
+ } else if (val.equals("-Infinity")) {
+ return "(-1.0" + suffix + "/0.0" + suffix + ")";
+ } else if (val.equals("NaN")) {
+ return "(0.0" + suffix + "/0.0" + suffix + ")";
+ }
+
+ String str = val.toString();
+ if (str.indexOf('E') != -1) {
+ return str + suffix;
+ }
+
+ // 1.0 is the only case where a trailing "0" is allowed.
+ // 1.00 is canonicalized as 1.0.
+ int i = str.length() - 1;
+ int d = str.indexOf('.');
+ while (i >= d + 2 && str.charAt(i) == '0') {
+ str = str.substring(0, i--);
+ }
+ return str + suffix;
+ }
+
+
+ // This unescapes the string format used by doclava and so needs to be kept in sync with any
+ // changes made to that format.
+ private static String unescapeFieldStringValue(String str) {
+ final int N = str.length();
+
+ // If there's no special encoding strings in the string then just return it.
+ if (str.indexOf('\\') == -1) {
+ return str;
+ }
+
+ final StringBuilder buf = new StringBuilder(str.length());
+ char escaped = 0;
+ final int START = 0;
+ final int CHAR1 = 1;
+ final int CHAR2 = 2;
+ final int CHAR3 = 3;
+ final int CHAR4 = 4;
+ final int ESCAPE = 5;
+ int state = START;
+
+ for (int i=0; i<N; i++) {
+ final char c = str.charAt(i);
+ switch (state) {
+ case START:
+ if (c == '\\') {
+ state = ESCAPE;
+ } else {
+ buf.append(c);
+ }
+ break;
+ case ESCAPE:
+ switch (c) {
+ case '\\':
+ buf.append('\\');
+ state = START;
+ break;
+ case 't':
+ buf.append('\t');
+ state = START;
+ break;
+ case 'b':
+ buf.append('\b');
+ state = START;
+ break;
+ case 'r':
+ buf.append('\r');
+ state = START;
+ break;
+ case 'n':
+ buf.append('\n');
+ state = START;
+ break;
+ case 'f':
+ buf.append('\f');
+ state = START;
+ break;
+ case '\'':
+ buf.append('\'');
+ state = START;
+ break;
+ case '\"':
+ buf.append('\"');
+ state = START;
+ break;
+ case 'u':
+ state = CHAR1;
+ escaped = 0;
+ break;
+ }
+ break;
+ case CHAR1:
+ case CHAR2:
+ case CHAR3:
+ case CHAR4:
+ escaped <<= 4;
+ if (c >= '0' && c <= '9') {
+ escaped |= c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ escaped |= 10 + (c - 'a');
+ } else if (c >= 'A' && c <= 'F') {
+ escaped |= 10 + (c - 'A');
+ } else {
+ throw new RuntimeException(
+ "bad escape sequence: '" + c + "' at pos " + i + " in: \""
+ + str + "\"");
+ }
+ if (state == CHAR4) {
+ buf.append(escaped);
+ state = START;
+ } else {
+ state++;
+ }
+ break;
+ }
+ }
+ if (state != START) {
+ throw new RuntimeException("unfinished escape sequence: " + str);
+ }
+ return buf.toString();
+ }
+
+
+ /**
* Finds the reflected field specified by the field description.
*
* @param field the field description to find
diff --git a/tests/signature/tests/Android.mk b/tests/signature/tests/Android.mk
index f17ee47..0c9c24c 100644
--- a/tests/signature/tests/Android.mk
+++ b/tests/signature/tests/Android.mk
@@ -21,6 +21,6 @@
LOCAL_MODULE := signature-tests
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed signature-hostside
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed signature-hostside
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tests/signature/tests/run_unit_tests.sh b/tests/signature/tests/run_unit_tests.sh
index 19ce8d2..02f914c 100755
--- a/tests/signature/tests/run_unit_tests.sh
+++ b/tests/signature/tests/run_unit_tests.sh
@@ -36,7 +36,7 @@
fi;
JAR_DIR=${ANDROID_BUILD_TOP}/out/host/$OS/framework
-JARS="tradefed-prebuilt.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
+JARS="tradefed.jar hosttestlib.jar signature-hostside.jar signature-tests.jar"
for JAR in $JARS; do
checkFile ${JAR_DIR}/${JAR}
diff --git a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
index 9cd84c7..6e477ae 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/JDiffClassDescriptionTest.java
@@ -252,7 +252,7 @@
"public transient java.lang.String TRANSIENT_FIELD");
}
- public void testPacakgeField() {
+ public void testPackageField() {
JDiffClassDescription clz = createNormalClass();
JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
"PACAKGE_FIELD", "java.lang.String", 0, VALUE);
@@ -279,6 +279,30 @@
assertEquals(field.toSignatureString(), "protected java.lang.String PROTECTED_FIELD");
}
+ public void testFieldValue() {
+ JDiffClassDescription clz = createNormalClass();
+ JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+ "VALUE_FIELD", "java.lang.String",
+ Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"\\u2708\"");
+ clz.addField(field);
+ clz.checkSignatureCompliance();
+ assertEquals(field.toSignatureString(),
+ "public static final java.lang.String VALUE_FIELD");
+ }
+
+ public void testFieldValueChanged() {
+ ExpectFailure observer = new ExpectFailure(FailureType.MISMATCH_FIELD);
+ JDiffClassDescription clz = createNormalClass(observer);
+ JDiffClassDescription.JDiffField field = new JDiffClassDescription.JDiffField(
+ "VALUE_FIELD", "java.lang.String",
+ Modifier.PUBLIC | Modifier.FINAL | Modifier.STATIC , "\"✈\"");
+ clz.addField(field);
+ clz.checkSignatureCompliance();
+ assertEquals(field.toSignatureString(),
+ "public static final java.lang.String VALUE_FIELD");
+ observer.validate();
+ }
+
public void testInnerClass() {
JDiffClassDescription clz = new JDiffClassDescription(
"android.signature.cts.tests.data", "NormalClass.InnerClass", new NoFailures());
@@ -311,7 +335,8 @@
clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
clz.setModifier(Modifier.PUBLIC | Modifier.STATIC | Modifier.ABSTRACT);
clz.addMethod(
- new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+ new JDiffClassDescription.JDiffMethod("doSomething",
+ Modifier.PUBLIC | Modifier.ABSTRACT, "void"));
clz.checkSignatureCompliance();
assertEquals(clz.toSignatureString(), "public interface NormalClass.InnerInterface");
}
@@ -322,7 +347,8 @@
clz.setType(JDiffClassDescription.JDiffType.INTERFACE);
clz.setModifier(Modifier.PUBLIC | Modifier.ABSTRACT);
clz.addMethod(
- new JDiffClassDescription.JDiffMethod("doSomething", Modifier.PUBLIC, "void"));
+ new JDiffClassDescription.JDiffMethod("doSomething",
+ Modifier.ABSTRACT| Modifier.PUBLIC, "void"));
clz.checkSignatureCompliance();
assertEquals(clz.toSignatureString(), "public interface NormalInterface");
}
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
index 5acd696..db47967 100644
--- a/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
+++ b/tests/signature/tests/src/android/signature/cts/tests/data/NormalClass.java
@@ -47,6 +47,7 @@
public static String STATIC_FIELD;
public volatile String VOLATILE_FIELD;
public transient String TRANSIENT_FIELD;
+ public final static String VALUE_FIELD = "\u2708";
String PACAKGE_FIELD;
private String PRIVATE_FIELD;
protected String PROTECTED_FIELD;
diff --git a/tests/tests/bionic/Android.build.copy.libs.mk b/tests/tests/bionic/Android.build.copy.libs.mk
index dd7d4e0..6c2d546 100644
--- a/tests/tests/bionic/Android.build.copy.libs.mk
+++ b/tests/tests/bionic/Android.build.copy.libs.mk
@@ -49,6 +49,7 @@
libtest_check_order_reloc_siblings_e.so \
libtest_check_order_reloc_siblings_f.so \
libtest_check_order_reloc_siblings.so \
+ libtest_check_rtld_next_from_library.so \
libtest_dlopen_from_ctor_main.so \
libtest_dlopen_from_ctor.so \
libtest_dlopen_weak_undefined_func.so \
diff --git a/tests/tests/content/src/android/content/cts/ContentProviderTest.java b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
index e7d8a05..dc4a031 100644
--- a/tests/tests/content/src/android/content/cts/ContentProviderTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentProviderTest.java
@@ -226,6 +226,11 @@
// cannot trigger this callback reliably
}
+ public void testRefresh_DefaultImplReturnsFalse() {
+ MockContentProvider provider = new MockContentProvider();
+ assertFalse(provider.refresh(null, null, null));
+ }
+
public void testGetIContentProvider() {
MockContentProvider mockContentProvider = new MockContentProvider();
diff --git a/tests/tests/content/src/android/content/cts/ContentResolverTest.java b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
index ea1227c..fa9a2a7 100644
--- a/tests/tests/content/src/android/content/cts/ContentResolverTest.java
+++ b/tests/tests/content/src/android/content/cts/ContentResolverTest.java
@@ -910,6 +910,44 @@
}
}
+ public void testRefresh_DefaultImplReturnsFalse() {
+ boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+ assertFalse(refreshed);
+ MockContentProvider.assertRefreshed(TABLE1_URI);
+ }
+
+ public void testRefresh_ReturnsProviderValue() {
+ try {
+ MockContentProvider.setRefreshReturnValue(true);
+ boolean refreshed = mContentResolver.refresh(TABLE1_URI, null, null);
+ assertTrue(refreshed);
+ MockContentProvider.assertRefreshed(TABLE1_URI);
+ } finally {
+ MockContentProvider.setRefreshReturnValue(false);
+ }
+ }
+
+ public void testRefresh_NullUriThrowsImmediately() {
+ try {
+ mContentResolver.refresh(null, null, null);
+ fail("did not throw NullPointerException when uri is null.");
+ } catch (NullPointerException e) {
+ //expected.
+ }
+ }
+
+ public void testRefresh_CancellableThrowsImmediately() {
+ CancellationSignal cancellationSignal = new CancellationSignal();
+ cancellationSignal.cancel();
+
+ try {
+ mContentResolver.refresh(TABLE1_URI, null, cancellationSignal);
+ fail("Expected OperationCanceledException");
+ } catch (OperationCanceledException ex) {
+ // expected
+ }
+ }
+
public void testRegisterContentObserver() {
final MockContentObserver mco = new MockContentObserver();
diff --git a/tests/tests/content/src/android/content/cts/MockContentProvider.java b/tests/tests/content/src/android/content/cts/MockContentProvider.java
index bddc82d..e422c34 100644
--- a/tests/tests/content/src/android/content/cts/MockContentProvider.java
+++ b/tests/tests/content/src/android/content/cts/MockContentProvider.java
@@ -16,22 +16,15 @@
package android.content.cts;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.UnsupportedEncodingException;
-import java.util.HashMap;
+import static junit.framework.Assert.assertEquals;
+import android.annotation.Nullable;
import android.content.ContentProvider;
+import android.content.ContentProvider.PipeDataWriter;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.UriMatcher;
-import android.content.ContentProvider.PipeDataWriter;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.database.SQLException;
@@ -45,6 +38,15 @@
import android.text.TextUtils;
import android.util.Log;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.UnsupportedEncodingException;
+import java.util.HashMap;
+
public class MockContentProvider extends ContentProvider
implements PipeDataWriter<String> {
@@ -62,6 +64,9 @@
private static final int SELF_ID = 6;
private static final int CRASH_ID = 6;
+ private static @Nullable Uri sRefreshedUri;
+ private static boolean sRefreshReturnValue;
+
private final String mAuthority;
private final String mDbName;
private final UriMatcher URL_MATCHER;
@@ -385,6 +390,13 @@
}
}
+ @Override
+ public boolean refresh(Uri uri, @Nullable Bundle args,
+ @Nullable CancellationSignal cancellationSignal) {
+ sRefreshedUri = uri;
+ return sRefreshReturnValue;
+ }
+
private void crashOnLaunchIfNeeded() {
if (getCrashOnLaunch(getContext())) {
// The test case wants us to crash our process on first launch.
@@ -413,6 +425,14 @@
}
}
+ public static void setRefreshReturnValue(boolean value) {
+ sRefreshReturnValue = value;
+ }
+
+ public static void assertRefreshed(Uri expectedUri) {
+ assertEquals(sRefreshedUri, expectedUri);
+ }
+
private static File getCrashOnLaunchFile(Context context) {
return context.getFileStreamPath("MockContentProvider.crashonlaunch");
}
diff --git a/tests/tests/display/src/android/display/cts/DisplayTest.java b/tests/tests/display/src/android/display/cts/DisplayTest.java
index 48da789..4e24981 100644
--- a/tests/tests/display/src/android/display/cts/DisplayTest.java
+++ b/tests/tests/display/src/android/display/cts/DisplayTest.java
@@ -61,6 +61,7 @@
(float)(SECONDARY_DISPLAY_DPI + 1) / DisplayMetrics.DENSITY_DEFAULT;
// Matches com.android.internal.R.string.display_manager_overlay_display_name.
private static final String OVERLAY_DISPLAY_NAME_PREFIX = "Overlay #";
+ private static final String OVERLAY_DISPLAY_TYPE = "type OVERLAY";
private DisplayManager mDisplayManager;
private WindowManager mWindowManager;
@@ -115,15 +116,15 @@
}
}
- private boolean isSecondarySize(Display display) {
- final Point p = new Point();
- display.getSize(p);
- return p.x == SECONDARY_DISPLAY_WIDTH && p.y == SECONDARY_DISPLAY_HEIGHT;
+ /** Check if the display is an overlay display, created by this test. */
+ private boolean isSecondaryDisplay(Display display) {
+ return display.toString().contains(OVERLAY_DISPLAY_TYPE);
}
+ /** Get the overlay display, created by this test. */
private Display getSecondaryDisplay(Display[] displays) {
for (Display display : displays) {
- if (isSecondarySize(display)) {
+ if (isSecondaryDisplay(display)) {
return display;
}
}
@@ -143,7 +144,7 @@
if (display.getDisplayId() == Display.DEFAULT_DISPLAY) {
hasDefaultDisplay = true;
}
- if (isSecondarySize(display)) {
+ if (isSecondaryDisplay(display)) {
hasSecondaryDisplay = true;
}
}
@@ -234,22 +235,6 @@
}
/**
- * Test that the getCurrentSizeRange method returns correct values.
- */
- public void testGetCurrentSizeRange() {
- Display display = getSecondaryDisplay(mDisplayManager.getDisplays());
-
- Point smallest = new Point();
- Point largest = new Point();
- display.getCurrentSizeRange(smallest, largest);
-
- assertEquals(SECONDARY_DISPLAY_WIDTH, smallest.x);
- assertEquals(SECONDARY_DISPLAY_HEIGHT, smallest.y);
- assertEquals(SECONDARY_DISPLAY_WIDTH, largest.x);
- assertEquals(SECONDARY_DISPLAY_HEIGHT, largest.y);
- }
-
- /**
* Test that the getFlags method returns no flag bits set for the overlay display.
*/
public void testFlags() {
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
new file mode 100644
index 0000000..41dc97d
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorSpaceTest.java
@@ -0,0 +1,742 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.graphics.cts;
+
+import android.graphics.ColorSpace;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+import java.util.function.DoubleUnaryOperator;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ColorSpaceTest {
+ // Column-major RGB->XYZ transform matrix for the sRGB color space
+ private static final float[] SRGB_TO_XYZ = {
+ 0.412391f, 0.212639f, 0.019331f,
+ 0.357584f, 0.715169f, 0.119195f,
+ 0.180481f, 0.072192f, 0.950532f
+ };
+ // Column-major XYZ->RGB transform matrix for the sRGB color space
+ private static final float[] XYZ_TO_SRGB = {
+ 3.240970f, -0.969244f, 0.055630f,
+ -1.537383f, 1.875968f, -0.203977f,
+ -0.498611f, 0.041555f, 1.056971f
+ };
+
+ private static final float[] SRGB_PRIMARIES_xyY =
+ { 0.640f, 0.330f, 0.300f, 0.600f, 0.150f, 0.060f };
+ private static final float[] SRGB_WHITE_POINT_xyY = { 0.3127f, 0.3290f };
+
+ private static final float[] SRGB_PRIMARIES_XYZ = {
+ 1.939394f, 1.000000f, 0.090909f,
+ 0.500000f, 1.000000f, 0.166667f,
+ 2.500000f, 1.000000f, 13.166667f
+ };
+ private static final float[] SRGB_WHITE_POINT_XYZ = { 0.950456f, 1.000f, 1.089058f };
+
+ private static final DoubleUnaryOperator sIdentity = DoubleUnaryOperator.identity();
+
+ @Test
+ public void testNamedColorSpaces() {
+ for (ColorSpace.Named named : ColorSpace.Named.values()) {
+ ColorSpace colorSpace = ColorSpace.get(named);
+ assertNotNull(colorSpace.getName());
+ assertNotNull(colorSpace);
+ assertEquals(named.ordinal(), colorSpace.getId());
+ }
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullName() {
+ new ColorSpace.Rgb(null, new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testEmptyName() {
+ new ColorSpace.Rgb("", new float[6], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+ }
+
+ @Test
+ public void testName() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+ sIdentity, sIdentity, 0.0f, 1.0f);
+ assertEquals("Test", cs.getName());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testPrimariesLength() {
+ new ColorSpace.Rgb("Test", new float[7], new float[2], sIdentity, sIdentity, 0.0f, 1.0f);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testWhitePointLength() {
+ new ColorSpace.Rgb("Test", new float[6], new float[1], sIdentity, sIdentity, 0.0f, 1.0f);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullOETF() {
+ new ColorSpace.Rgb("Test", new float[6], new float[2], null, sIdentity, 0.0f, 1.0f);
+ }
+
+ @Test
+ public void testOETF() {
+ DoubleUnaryOperator op = Math::sqrt;
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+ op, sIdentity, 0.0f, 1.0f);
+ assertEquals(op, cs.getOetf());
+ assertEquals(0.5, cs.getOetf().applyAsDouble(0.25), 1e-5);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testNullEOTF() {
+ new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, null, 0.0f, 1.0f);
+ }
+
+ @Test
+ public void testEOTF() {
+ DoubleUnaryOperator op = x -> x * x;
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", new float[6], new float[2],
+ sIdentity, op, 0.0f, 1.0f);
+ assertEquals(op, cs.getEotf());
+ assertEquals(0.0625, cs.getEotf().applyAsDouble(0.25), 1e-5);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testInvalidRange() {
+ new ColorSpace.Rgb("Test", new float[6], new float[2], sIdentity, sIdentity, 2.0f, 1.0f);
+ }
+
+ @Test
+ public void testRanges() {
+ ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float m1 = cs.getMinValue(0);
+ float m2 = cs.getMinValue(1);
+ float m3 = cs.getMinValue(2);
+
+ assertEquals(0.0f, m1, 1e-9f);
+ assertEquals(0.0f, m2, 1e-9f);
+ assertEquals(0.0f, m3, 1e-9f);
+
+ m1 = cs.getMaxValue(0);
+ m2 = cs.getMaxValue(1);
+ m3 = cs.getMaxValue(2);
+
+ assertEquals(1.0f, m1, 1e-9f);
+ assertEquals(1.0f, m2, 1e-9f);
+ assertEquals(1.0f, m3, 1e-9f);
+
+ cs = ColorSpace.get(ColorSpace.Named.CIE_LAB);
+
+ m1 = cs.getMinValue(0);
+ m2 = cs.getMinValue(1);
+ m3 = cs.getMinValue(2);
+
+ assertEquals(0.0f, m1, 1e-9f);
+ assertEquals(-128.0f, m2, 1e-9f);
+ assertEquals(-128.0f, m3, 1e-9f);
+
+ m1 = cs.getMaxValue(0);
+ m2 = cs.getMaxValue(1);
+ m3 = cs.getMaxValue(2);
+
+ assertEquals(100.0f, m1, 1e-9f);
+ assertEquals(128.0f, m2, 1e-9f);
+ assertEquals(128.0f, m3, 1e-9f);
+
+ cs = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+ m1 = cs.getMinValue(0);
+ m2 = cs.getMinValue(1);
+ m3 = cs.getMinValue(2);
+
+ assertEquals(0.0f, m1, 1e-9f);
+ assertEquals(0.0f, m2, 1e-9f);
+ assertEquals(0.0f, m3, 1e-9f);
+
+ m1 = cs.getMaxValue(0);
+ m2 = cs.getMaxValue(1);
+ m3 = cs.getMaxValue(2);
+
+ assertEquals(2.0f, m1, 1e-9f);
+ assertEquals(2.0f, m2, 1e-9f);
+ assertEquals(2.0f, m3, 1e-9f);
+ }
+
+ @Test
+ public void testMat3x3() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+ float[] rgbToXYZ = cs.getTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+ }
+ }
+
+ @Test
+ public void testMat3x3Inverse() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+ float[] xyzToRGB = cs.getInverseTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+ }
+ }
+
+ @Test
+ public void testMat3x3Primaries() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+ float[] primaries = cs.getPrimaries();
+
+ assertNotNull(primaries);
+ assertEquals(6, primaries.length);
+
+ assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-5f);
+ assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-5f);
+ assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-5f);
+ assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-5f);
+ assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-5f);
+ assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-5f);
+ }
+
+ @Test
+ public void testMat3x3WhitePoint() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_TO_XYZ, sIdentity, sIdentity);
+
+ float[] whitePoint = cs.getWhitePoint();
+
+ assertNotNull(whitePoint);
+ assertEquals(2, whitePoint.length);
+
+ assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-5f);
+ assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-5f);
+ }
+
+ @Test
+ public void testXYZFromPrimaries_xyY() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_xyY, SRGB_WHITE_POINT_xyY,
+ sIdentity, sIdentity, 0.0f, 1.0f);
+
+ float[] rgbToXYZ = cs.getTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+ }
+
+ float[] xyzToRGB = cs.getInverseTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+ }
+ }
+
+ @Test
+ public void testXYZFromPrimaries_XYZ() {
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("Test", SRGB_PRIMARIES_XYZ, SRGB_WHITE_POINT_XYZ,
+ sIdentity, sIdentity, 0.0f, 1.0f);
+
+ float[] primaries = cs.getPrimaries();
+
+ assertNotNull(primaries);
+ assertEquals(6, primaries.length);
+
+ // SRGB_PRIMARIES_xyY only has 1e-3 of precision, match it
+ assertEquals(SRGB_PRIMARIES_xyY[0], primaries[0], 1e-3f);
+ assertEquals(SRGB_PRIMARIES_xyY[1], primaries[1], 1e-3f);
+ assertEquals(SRGB_PRIMARIES_xyY[2], primaries[2], 1e-3f);
+ assertEquals(SRGB_PRIMARIES_xyY[3], primaries[3], 1e-3f);
+ assertEquals(SRGB_PRIMARIES_xyY[4], primaries[4], 1e-3f);
+ assertEquals(SRGB_PRIMARIES_xyY[5], primaries[5], 1e-3f);
+
+ float[] whitePoint = cs.getWhitePoint();
+
+ assertNotNull(whitePoint);
+ assertEquals(2, whitePoint.length);
+
+ // SRGB_WHITE_POINT_xyY only has 1e-3 of precision, match it
+ assertEquals(SRGB_WHITE_POINT_xyY[0], whitePoint[0], 1e-3f);
+ assertEquals(SRGB_WHITE_POINT_xyY[1], whitePoint[1], 1e-3f);
+
+ float[] rgbToXYZ = cs.getTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(SRGB_TO_XYZ[i], rgbToXYZ[i], 1e-5f);
+ }
+
+ float[] xyzToRGB = cs.getInverseTransform();
+ for (int i = 0; i < 9; i++) {
+ assertEquals(XYZ_TO_SRGB[i], xyzToRGB[i], 1e-5f);
+ }
+ }
+
+ @Test
+ public void testIsSRGB() {
+ assertTrue(ColorSpace.get(ColorSpace.Named.SRGB).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_SRGB).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.LINEAR_EXTENDED_SRGB).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.DISPLAY_P3).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.CIE_LAB).isSrgb());
+ assertFalse(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isSrgb());
+
+ ColorSpace.Rgb cs = new ColorSpace.Rgb("My sRGB", SRGB_TO_XYZ,
+ x -> Math.pow(x, 1.0f / 2.2f), x -> Math.pow(x, 2.2f));
+ assertTrue(cs.isSrgb());
+ }
+
+ @Test
+ public void testIsWideGamut() {
+ assertFalse(ColorSpace.get(ColorSpace.Named.SRGB).isWideGamut());
+ assertFalse(ColorSpace.get(ColorSpace.Named.BT709).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.EXTENDED_SRGB).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.DCI_P3).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.BT2020).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.ACES).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.CIE_LAB).isWideGamut());
+ assertTrue(ColorSpace.get(ColorSpace.Named.CIE_XYZ).isWideGamut());
+ }
+
+ @Test
+ public void testWhitePoint() {
+ ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] whitePoint = cs.getWhitePoint();
+
+ assertNotNull(whitePoint);
+ assertEquals(2, whitePoint.length);
+
+ // Make sure a copy is returned
+ Arrays.fill(whitePoint, Float.NaN);
+ assertArrayNotEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+ assertSame(whitePoint, cs.getWhitePoint(whitePoint));
+ assertArrayEquals(whitePoint, cs.getWhitePoint(), 1e-5f);
+ }
+
+ @Test
+ public void testPrimaries() {
+ ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] primaries = cs.getPrimaries();
+
+ assertNotNull(primaries);
+ assertEquals(6, primaries.length);
+
+ // Make sure a copy is returned
+ Arrays.fill(primaries, Float.NaN);
+ assertArrayNotEquals(primaries, cs.getPrimaries(), 1e-5f);
+ assertSame(primaries, cs.getPrimaries(primaries));
+ assertArrayEquals(primaries, cs.getPrimaries(), 1e-5f);
+ }
+
+ @Test
+ public void testRGBtoXYZMatrix() {
+ ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] rgbToXYZ = cs.getTransform();
+
+ assertNotNull(rgbToXYZ);
+ assertEquals(9, rgbToXYZ.length);
+
+ // Make sure a copy is returned
+ Arrays.fill(rgbToXYZ, Float.NaN);
+ assertArrayNotEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+ assertSame(rgbToXYZ, cs.getTransform(rgbToXYZ));
+ assertArrayEquals(rgbToXYZ, cs.getTransform(), 1e-5f);
+ }
+
+ @Test
+ public void testXYZtoRGBMatrix() {
+ ColorSpace.Rgb cs = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] xyzToRGB = cs.getInverseTransform();
+
+ assertNotNull(xyzToRGB);
+ assertEquals(9, xyzToRGB.length);
+
+ // Make sure a copy is returned
+ Arrays.fill(xyzToRGB, Float.NaN);
+ assertArrayNotEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+ assertSame(xyzToRGB, cs.getInverseTransform(xyzToRGB));
+ assertArrayEquals(xyzToRGB, cs.getInverseTransform(), 1e-5f);
+ }
+
+ @Test
+ public void testRGBtoXYZ() {
+ ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] source = { 0.75f, 0.5f, 0.25f };
+ float[] expected = { 0.3012f, 0.2679f, 0.0840f };
+
+ float[] r1 = cs.toXyz(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayNotEquals(source, r1, 1e-5f);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r3 = { source[0], source[1], source[2] };
+ assertSame(r3, cs.toXyz(r3));
+ assertEquals(3, r3.length);
+ assertArrayEquals(r1, r3, 1e-5f);
+ }
+
+ @Test
+ public void testXYZtoRGB() {
+ ColorSpace cs = ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] source = { 0.3012f, 0.2679f, 0.0840f };
+ float[] expected = { 0.75f, 0.5f, 0.25f };
+
+ float[] r1 = cs.fromXyz(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayNotEquals(source, r1, 1e-5f);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r3 = { source[0], source[1], source[2] };
+ assertSame(r3, cs.fromXyz(r3));
+ assertEquals(3, r3.length);
+ assertArrayEquals(r1, r3, 1e-5f);
+ }
+
+ @Test
+ public void testConnect() {
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getSource());
+ assertSame(ColorSpace.get(ColorSpace.Named.DCI_P3), connector.getDestination());
+
+ connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+
+ assertSame(connector.getDestination(), connector.getSource());
+
+ connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.DCI_P3));
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector.getDestination());
+
+ connector = ColorSpace.connect(ColorSpace.get(ColorSpace.Named.SRGB));
+ assertSame(connector.getSource(), connector.getDestination());
+ }
+
+ @Test
+ public void testConnector() {
+ // Connect color spaces with same white points
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB));
+
+ float[] source = { 1.0f, 0.5f, 0.0f };
+ float[] expected = { 0.8912f, 0.4962f, 0.1164f };
+
+ float[] r1 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayNotEquals(source, r1, 1e-5f);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r3 = { source[0], source[1], source[2] };
+ assertSame(r3, connector.transform(r3));
+ assertEquals(3, r3.length);
+ assertArrayEquals(r1, r3, 1e-5f);
+
+ connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.ADOBE_RGB),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+
+ float[] tmp = source;
+ source = expected;
+ expected = tmp;
+
+ r1 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayNotEquals(source, r1, 1e-5f);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ r3 = new float[] { source[0], source[1], source[2] };
+ assertSame(r3, connector.transform(r3));
+ assertEquals(3, r3.length);
+ assertArrayEquals(r1, r3, 1e-5f);
+ }
+
+ @Test
+ public void testAdaptedConnector() {
+ // Connect color spaces with different white points
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.PRO_PHOTO_RGB));
+
+ float[] source = new float[] { 1.0f, 0.0f, 0.0f };
+ float[] expected = new float[] { 0.70226f, 0.2757f, 0.1036f };
+
+ float[] r = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r);
+ assertEquals(3, r.length);
+ assertArrayNotEquals(source, r, 1e-5f);
+ assertArrayEquals(expected, r, 1e-4f);
+ }
+
+ @Test
+ public void testAdaptedConnectorWithRenderIntent() {
+ // Connect a wider color space to a narrow color space
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.DCI_P3),
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.RenderIntent.RELATIVE);
+
+ float[] source = { 0.9f, 0.9f, 0.9f };
+
+ float[] relative = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(relative);
+ assertEquals(3, relative.length);
+ assertArrayNotEquals(source, relative, 1e-5f);
+ assertArrayEquals(new float[] { 0.8862f, 0.8862f, 0.8862f }, relative, 1e-4f);
+
+ connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.DCI_P3),
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.RenderIntent.ABSOLUTE);
+
+ float[] absolute = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(absolute);
+ assertEquals(3, absolute.length);
+ assertArrayNotEquals(source, absolute, 1e-5f);
+ assertArrayNotEquals(relative, absolute, 1e-5f);
+ assertArrayEquals(new float[] { 0.8475f, 0.9217f, 0.8203f }, absolute, 1e-4f);
+ }
+
+ @Test
+ public void testIdentityConnector() {
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+
+ assertSame(connector.getSource(), connector.getDestination());
+
+ float[] source = new float[] { 0.11112f, 0.22227f, 0.444448f };
+
+ float[] r = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r);
+ assertEquals(3, r.length);
+ assertArrayEquals(source, r, 1e-5f);
+ }
+
+ @Test
+ public void testConnectorTransformIdentity() {
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.DCI_P3),
+ ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+ float[] source = { 1.0f, 0.0f, 0.0f };
+ float[] expected = { 1.0f, 0.0f, 0.0f };
+
+ float[] r1 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r3 = { source[0], source[1], source[2] };
+ assertSame(r3, connector.transform(r3));
+ assertEquals(3, r3.length);
+ assertArrayEquals(r1, r3, 1e-5f);
+ }
+
+ @Test
+ public void testAdaptation() {
+ ColorSpace adapted = ColorSpace.adapt(
+ ColorSpace.get(ColorSpace.Named.SRGB),
+ ColorSpace.ILLUMINANT_D50);
+
+ float[] sRGBD50 = {
+ 0.43602175f, 0.22247513f, 0.01392813f,
+ 0.38510883f, 0.71690667f, 0.09710153f,
+ 0.14308129f, 0.06061824f, 0.71415880f
+ };
+
+ assertArrayEquals(sRGBD50, ((ColorSpace.Rgb) adapted).getTransform(), 1e-7f);
+ }
+
+ @Test
+ public void testImplicitSRGBConnector() {
+ ColorSpace.Connector connector1 = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.DCI_P3));
+
+ assertSame(ColorSpace.get(ColorSpace.Named.SRGB), connector1.getDestination());
+
+ ColorSpace.Connector connector2 = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.DCI_P3),
+ ColorSpace.get(ColorSpace.Named.SRGB));
+
+ float[] source = { 0.6f, 0.9f, 0.7f };
+ assertArrayEquals(
+ connector1.transform(source[0], source[1], source[2]),
+ connector2.transform(source[0], source[1], source[2]), 1e-7f);
+ }
+
+ @Test
+ public void testLab() {
+ ColorSpace.Connector connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.CIE_LAB));
+
+ float[] source = { 100.0f, 0.0f, 0.0f };
+ float[] expected = { 1.0f, 1.0f, 1.0f };
+
+ float[] r1 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ source = new float[] { 100.0f, 0.0f, 54.0f };
+ expected = new float[] { 1.0f, 0.9925f, 0.5762f };
+
+ float[] r2 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r2);
+ assertEquals(3, r2.length);
+ assertArrayEquals(expected, r2, 1e-3f);
+
+ connector = ColorSpace.connect(
+ ColorSpace.get(ColorSpace.Named.CIE_LAB), ColorSpace.RenderIntent.ABSOLUTE);
+
+ source = new float[] { 100.0f, 0.0f, 0.0f };
+ expected = new float[] { 1.0f, 0.9910f, 0.8651f };
+
+ r1 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ source = new float[] { 100.0f, 0.0f, 54.0f };
+ expected = new float[] { 1.0f, 0.9853f, 0.4652f };
+
+ r2 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r2);
+ assertEquals(3, r2.length);
+ assertArrayEquals(expected, r2, 1e-3f);
+ }
+
+ @Test
+ public void testXYZ() {
+ ColorSpace xyz = ColorSpace.get(ColorSpace.Named.CIE_XYZ);
+
+ float[] source = { 0.32f, 0.43f, 0.54f };
+
+ float[] r1 = xyz.toXyz(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(source, r1, 1e-7f);
+
+ float[] r2 = xyz.fromXyz(source[0], source[1], source[2]);
+ assertNotNull(r2);
+ assertEquals(3, r2.length);
+ assertArrayEquals(source, r2, 1e-7f);
+
+ ColorSpace.Connector connector =
+ ColorSpace.connect(ColorSpace.get(ColorSpace.Named.CIE_XYZ));
+
+ float[] expected = { 0.2280f, 0.7541f, 0.8453f };
+
+ float[] r3 = connector.transform(source[0], source[1], source[2]);
+ assertNotNull(r3);
+ assertEquals(3, r3.length);
+ assertArrayEquals(expected, r3, 1e-3f);
+ }
+
+ @Test
+ public void testIDs() {
+ // These cannot change
+ assertEquals(0, ColorSpace.get(ColorSpace.Named.SRGB).getId());
+ assertEquals(-1, ColorSpace.MIN_ID);
+ assertEquals(64, ColorSpace.MAX_ID);
+ }
+
+ @Test
+ public void testFromLinear() {
+ ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] source = { 0.0f, 0.5f, 1.0f };
+ float[] expected = { 0.0f, 0.7354f, 1.0f };
+
+ float[] r1 = colorSpace.fromLinear(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r2 = { source[0], source[1], source[2] };
+ assertSame(r2, colorSpace.fromLinear(r2));
+ assertEquals(3, r2.length);
+ assertArrayEquals(r1, r2, 1e-5f);
+ }
+
+ @Test
+ public void testToLinear() {
+ ColorSpace.Rgb colorSpace = (ColorSpace.Rgb) ColorSpace.get(ColorSpace.Named.SRGB);
+
+ float[] source = { 0.0f, 0.5f, 1.0f };
+ float[] expected = new float[] { 0.0f, 0.2140f, 1.0f };
+
+ float[] r1 = colorSpace.toLinear(source[0], source[1], source[2]);
+ assertNotNull(r1);
+ assertEquals(3, r1.length);
+ assertArrayEquals(expected, r1, 1e-3f);
+
+ float[] r2 = new float[] { source[0], source[1], source[2] };
+ assertSame(r2, colorSpace.toLinear(r2));
+ assertEquals(3, r2.length);
+ assertArrayEquals(r1, r2, 1e-5f);
+ }
+
+ @Test
+ public void testIdempotentTransferFunctions() {
+ Arrays.stream(ColorSpace.Named.values())
+ .map(ColorSpace::get)
+ .filter(cs -> cs.getModel() == ColorSpace.Model.RGB)
+ .map(cs -> (ColorSpace.Rgb) cs)
+ .forEach(cs -> {
+ float[] source = { 0.0f, 0.5f, 1.0f };
+ float[] r = cs.fromLinear(cs.toLinear(source[0], source[1], source[2]));
+ assertArrayEquals(source, r, 1e-3f);
+ });
+ }
+
+ @SuppressWarnings("SameParameterValue")
+ private static void assertArrayNotEquals(float[] a, float[] b, float eps) {
+ for (int i = 0; i < a.length; i++) {
+ if (Float.compare(a[i], b[i]) == 0 || Math.abs(a[i] - b[i]) < eps) {
+ fail("Expected " + a[i] + ", received " + b[i]);
+ }
+ }
+ }
+
+ private static void assertArrayEquals(float[] a, float[] b, float eps) {
+ for (int i = 0; i < a.length; i++) {
+ if (Float.compare(a[i], b[i]) != 0 && Math.abs(a[i] - b[i]) > eps) {
+ fail("Expected " + a[i] + ", received " + b[i]);
+ }
+ }
+ }
+}
diff --git a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
index 2a4dc48..7df4360 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ColorTest.java
@@ -31,7 +31,6 @@
public void testAlpha() {
assertEquals(0xff, Color.alpha(Color.RED));
assertEquals(0xff, Color.alpha(Color.YELLOW));
- new Color();
}
@Test
diff --git a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
index 5fe6026..35185dd 100644
--- a/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
+++ b/tests/tests/graphics/src/android/graphics/drawable/cts/ShapeDrawableTest.java
@@ -262,7 +262,7 @@
// Since Mockito can't mock or spy on protected methods, we have a custom extension
// of StateListDrawable to track calls to protected inflateTag method.
- private class MockShapeDrawable extends ShapeDrawable {
+ public class MockShapeDrawable extends ShapeDrawable {
public boolean inflateTagCalled;
public boolean extendedAttrsSet;
diff --git a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
index cbacd26..402b204 100644
--- a/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
+++ b/tests/tests/graphics2/src/android/graphics2/cts/TextureViewCameraActivity.java
@@ -55,13 +55,7 @@
Assert.assertTrue(mTextureView.isOpaque());
mWidth = width;
mHeight = height;
- PackageManager packageManager = getPackageManager();
- boolean hasRearCamera = packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA);
- boolean hasFrontCamera =
- packageManager.hasSystemFeature(PackageManager.FEATURE_CAMERA_FRONT);
- if (hasRearCamera) {
- mCamera = Camera.open();
- } else if (hasFrontCamera) {
+ if (Camera.getNumberOfCameras() > 0) {
mCamera = Camera.open(0);
} else {
// no camera, and no frame update, so just complete here.
@@ -84,8 +78,10 @@
}
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
- mCamera.stopPreview();
- mCamera.release();
+ if (mCamera != null) {
+ mCamera.stopPreview();
+ mCamera.release();
+ }
return true;
}
diff --git a/tests/tests/icu/Android.mk b/tests/tests/icu/Android.mk
index 0c7afaf..4867268 100644
--- a/tests/tests/icu/Android.mk
+++ b/tests/tests/icu/Android.mk
@@ -56,7 +56,7 @@
descGen \
jsr305lib
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
LOCAL_MODULE := cts-icu-tools
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
index caa6336..77cde44 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyChainTest.java
@@ -61,26 +61,6 @@
}
}
- public void testGetPrivateKeyOnMainThreadFails() throws InterruptedException {
- final CountDownLatch waiter = new CountDownLatch(1);
- new Handler(getContext().getMainLooper()).post(new Runnable() {
- @Override
- public void run() {
- try {
- KeyChain.getPrivateKey(getContext(), "");
- fail("IllegalStateException was expected for calling "
- + "KeyChain.getPrivateKey(Context, String) on main thread");
- } catch (IllegalStateException expected) {
- } catch (Exception invalid) {
- fail("Expected IllegalStateException, received " + invalid);
- } finally {
- waiter.countDown();
- }
- }
- });
- waiter.await();
- }
-
/**
* Tests whether the required algorithms are backed by a Keymaster HAL that
* binds the key material to the specific device it was created or imported
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
index 6deaed4..aed0d42 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyGeneratorTest.java
@@ -271,7 +271,7 @@
continue;
}
}
- if ((i > 0) && ((i % 8 ) == 0)) {
+ if ((i >= 64) && ((i % 8 ) == 0)) {
keyGenerator.init(spec, rng);
SecretKey key = keyGenerator.generateKey();
assertEquals(i, TestUtils.getKeyInfo(key).getKeySize());
diff --git a/tests/tests/location/src/android/location/cts/GeocoderTest.java b/tests/tests/location/src/android/location/cts/GeocoderTest.java
index d96b73f..62d9d25 100644
--- a/tests/tests/location/src/android/location/cts/GeocoderTest.java
+++ b/tests/tests/location/src/android/location/cts/GeocoderTest.java
@@ -17,6 +17,9 @@
package android.location.cts;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
import android.location.Geocoder;
import android.test.AndroidTestCase;
@@ -43,7 +46,21 @@
public void testIsPresent() {
Geocoder geocoder = new Geocoder(getContext());
- assertTrue(geocoder.isPresent());
+ if (isServiceMissing()) {
+ assertFalse(geocoder.isPresent());
+ } else {
+ assertTrue(geocoder.isPresent());
+ }
+ }
+
+ private boolean isServiceMissing() {
+ Context context = getContext();
+ PackageManager pm = context.getPackageManager();
+
+ final Intent intent = new Intent("com.android.location.service.GeocodeProvider");
+ final int flags = PackageManager.MATCH_DIRECT_BOOT_AWARE
+ | PackageManager.MATCH_DIRECT_BOOT_UNAWARE;
+ return pm.queryIntentServices(intent, flags).isEmpty();
}
public void testGetFromLocation() throws IOException, InterruptedException {
diff --git a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
index 509be67..662a1fd 100644
--- a/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
+++ b/tests/tests/location/src/android/location/cts/TestMeasurementUtil.java
@@ -55,6 +55,8 @@
" listener has failed, this indicates a platform bug. Please report the issue with" +
" a full bugreport.";
+ private static final int YEAR_2016 = 2016;
+
// The valid Gnss navigation message type as listed in
// android/hardware/libhardware/include/hardware/gps.h
public static final Set<Integer> GNSS_NAVIGATION_MESSAGE_TYPE =
@@ -70,8 +72,6 @@
GnssNavigationMessage.TYPE_GAL_F
));
- private static final int YEAR_2016 = 2016;
-
/**
* Check if test can be run on the current device.
*
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 23fa502..4b5b1d7 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -1092,7 +1092,9 @@
boolean sawOutputEos = false;
int deadDecoderCounter = 0;
ArrayList<String> frames = new ArrayList<String>();
- while ((waitForEos && !sawOutputEos) || frameIx < frameEndIx) {
+ String buf = null;
+ // After all input buffers are queued, dequeue as many output buffers as possible.
+ while ((waitForEos && !sawOutputEos) || frameIx < frameEndIx || buf != null) {
if (frameIx < frameEndIx) {
if (queueInputBuffer(
media,
@@ -1103,7 +1105,7 @@
}
}
- String buf = dequeueAndReleaseOutputBuffer(info);
+ buf = dequeueAndReleaseOutputBuffer(info);
if (buf != null) {
// Some decoders output a 0-sized buffer at the end. Disregard those.
if (info.size > 0) {
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerStub.java b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
index 947acec..50fb2fd 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerStub.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerStub.java
@@ -32,6 +32,11 @@
private MediaPlayer mMediaPlayer;
private AudioManager mAudioManager;
private static CTSResult mCTSResult;
+ private static final int[] STREAM_TYPES = {
+ AudioManager.STREAM_VOICE_CALL, AudioManager.STREAM_SYSTEM,
+ AudioManager.STREAM_RING, AudioManager.STREAM_MUSIC, AudioManager.STREAM_ALARM,
+ AudioManager.STREAM_NOTIFICATION, AudioManager.STREAM_DTMF,
+ AudioManager.STREAM_ACCESSIBILITY };
public static void setCTSResult(CTSResult cr) {
mCTSResult = cr;
@@ -51,7 +56,7 @@
protected void onPause() {
super.onPause();
try {
- for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+ for (int i : STREAM_TYPES) {
mAudioManager.setStreamMute(i, false);
mAudioManager.setStreamSolo(i, false);
}
@@ -65,7 +70,7 @@
protected void onResume() {
super.onResume();
try {
- for (int i = 0; i < AudioSystem.getNumStreamTypes(); i++) {
+ for (int i : STREAM_TYPES) {
mAudioManager.setStreamMute(i, true);
mAudioManager.setStreamSolo(i, true);
}
diff --git a/tests/tests/media/src/android/media/cts/AudioManagerTest.java b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
index c32be5c..a1754d1 100644
--- a/tests/tests/media/src/android/media/cts/AudioManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioManagerTest.java
@@ -468,7 +468,8 @@
int[] streams = {AudioManager.STREAM_ALARM,
AudioManager.STREAM_MUSIC,
AudioManager.STREAM_VOICE_CALL,
- AudioManager.STREAM_RING};
+ AudioManager.STREAM_RING,
+ AudioManager.STREAM_ACCESSIBILITY};
mAudioManager.adjustVolume(ADJUST_RAISE, 0);
mAudioManager.adjustSuggestedStreamVolume(
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
index 7b74ba7..9b1dc81 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTest.java
@@ -19,11 +19,22 @@
import android.annotation.TargetApi;
import android.content.Context;
+import android.cts.util.MediaUtils;
import android.graphics.Bitmap;
+import android.media.MediaFormat;
+import android.support.test.runner.AndroidJUnit4;
import android.util.Log;
import android.view.View;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.rules.Timeout;
+import org.junit.runner.RunWith;
+import org.junit.Test;
+
@TargetApi(24)
+@RunWith(AndroidJUnit4.class)
public class DecodeAccuracyTest extends DecodeAccuracyTestBase {
private static final String TAG = DecodeAccuracyTest.class.getSimpleName();
@@ -32,12 +43,17 @@
private static final String H264_CROPPED_VIDEO_FILE_NAME = "520x360h264decodertest.mp4";
private static final int ALLOWED_GREATEST_PIXEL_DIFFERENCE = 90;
private static final int OFFSET = 10;
+ private static final int PER_TEST_TIMEOUT_S = 30;
private View videoView;
private VideoViewFactory videoViewFactory;
+ @Rule
+ public Timeout globalTimeout = Timeout.seconds(PER_TEST_TIMEOUT_S);
+
+ @After
@Override
- protected void tearDown() throws Exception {
+ public void tearDown() throws Exception {
if (videoView != null) {
getHelper().cleanUpView(videoView);
}
@@ -48,36 +64,42 @@
}
/* <------------- Tests Using H264 -------------> */
+ @Test
public void testH264GLViewVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new GLSurfaceViewFactory(),
new VideoFormat(H264_VIDEO_FILE_NAME));
}
+ @Test
public void testH264GLViewLargerHeightVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new GLSurfaceViewFactory(),
getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
}
+ @Test
public void testH264GLViewLargerWidthVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new GLSurfaceViewFactory(),
getLargerWidthVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
}
+ @Test
public void testH264SurfaceViewVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new SurfaceViewFactory(),
new VideoFormat(H264_VIDEO_FILE_NAME));
}
+ @Test
public void testH264SurfaceViewLargerHeightVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new SurfaceViewFactory(),
getLargerHeightVideoFormat(new VideoFormat(H264_VIDEO_FILE_NAME)));
}
+ @Test
public void testH264SurfaceViewLargerWidthVideoDecode() throws Exception {
runH264DecodeAccuracyTest(
new SurfaceViewFactory(),
@@ -85,36 +107,42 @@
}
/* <------------- Tests Using VP9 -------------> */
+ @Test
public void testVP9GLViewVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new GLSurfaceViewFactory(),
new VideoFormat(VP9_VIDEO_FILE_NAME));
}
+ @Test
public void testVP9GLViewLargerHeightVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new GLSurfaceViewFactory(),
getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
}
+ @Test
public void testVP9GLViewLargerWidthVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new GLSurfaceViewFactory(),
getLargerWidthVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
}
+ @Test
public void testVP9SurfaceViewVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new SurfaceViewFactory(),
new VideoFormat(VP9_VIDEO_FILE_NAME));
}
+ @Test
public void testVP9SurfaceViewLargerHeightVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new SurfaceViewFactory(),
getLargerHeightVideoFormat(new VideoFormat(VP9_VIDEO_FILE_NAME)));
}
+ @Test
public void testVP9SurfaceViewLargerWidthVideoDecode() throws Exception {
runVP9DecodeAccuracyTest(
new SurfaceViewFactory(),
@@ -122,12 +150,14 @@
}
/* <------------- Tests H264 with cropping -------------> */
+ @Test
public void testH264GLViewCroppedVideoDecode() throws Exception {
runH264DecodeCroppedTest(
new GLSurfaceViewFactory(),
new VideoFormat(H264_CROPPED_VIDEO_FILE_NAME));
}
+ @Test
public void testH264SurfaceViewCroppedVideoDecode() throws Exception {
runH264DecodeCroppedTest(
new SurfaceViewFactory(),
@@ -136,17 +166,23 @@
private void runH264DecodeAccuracyTest(
VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
- runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertestgolden);
+ if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+ runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertestgolden);
+ }
}
private void runVP9DecodeAccuracyTest(
VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
- runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.vp9decodertestgolden);
+ if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_VP9)) {
+ runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.vp9decodertestgolden);
+ }
}
private void runH264DecodeCroppedTest(
VideoViewFactory videoViewFactory, VideoFormat videoFormat) {
- runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertest520x360golden);
+ if (MediaUtils.checkDecoder(MediaFormat.MIMETYPE_VIDEO_AVC)) {
+ runDecodeAccuracyTest(videoViewFactory, videoFormat, R.raw.h264decodertest520x360golden);
+ }
}
private void runDecodeAccuracyTest(
@@ -191,7 +227,8 @@
private void validateResult(
VideoFormat videoFormat, VideoViewSnapshot videoViewSnapshot, int goldenResId) {
- final Bitmap result = getHelper().generateBitmapFromVideoViewSnapshot(videoViewSnapshot);
+ final Bitmap result = checkNotNull("The expected bitmap from snapshot is null",
+ getHelper().generateBitmapFromVideoViewSnapshot(videoViewSnapshot));
final Bitmap golden = getHelper().generateBitmapFromImageResourceId(goldenResId);
final BitmapCompare.Difference difference = BitmapCompare.computeMinimumDifference(
result, golden, videoFormat.getOriginalWidth(), videoFormat.getOriginalHeight());
diff --git a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
index fae1bb4..1ce732d 100644
--- a/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
+++ b/tests/tests/media/src/android/media/cts/DecodeAccuracyTestBase.java
@@ -44,6 +44,8 @@
import android.os.HandlerThread;
import android.os.Looper;
import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.util.Pair;
@@ -73,7 +75,12 @@
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.runner.RunWith;
+
@TargetApi(16)
+@RunWith(AndroidJUnit4.class)
public class DecodeAccuracyTestBase
extends ActivityInstrumentationTestCase2<DecodeAccuracyTestActivity> {
@@ -86,9 +93,12 @@
super(DecodeAccuracyTestActivity.class);
}
+ @Before
@Override
- protected void setUp() throws Exception {
+ public void setUp() throws Exception {
super.setUp();
+ injectInstrumentation(InstrumentationRegistry.getInstrumentation());
+ setActivityInitialTouchMode(false);
mActivity = getActivity();
getInstrumentation().waitForIdleSync();
mContext = getInstrumentation().getTargetContext();
@@ -96,8 +106,9 @@
testHelper = new TestHelper(mContext, mActivity);
}
+ @After
@Override
- protected void tearDown() throws Exception {
+ public void tearDown() throws Exception {
mActivity = null;
super.tearDown();
}
@@ -117,6 +128,11 @@
return reference;
}
+ public static <T> T checkNotNull(String msg, T reference) {
+ assertNotNull(msg, reference);
+ return reference;
+ }
+
public static class SimplePlayer {
public static final long DECODE_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(1) / 2;
@@ -419,6 +435,8 @@
/* Utility class for collecting common test case functionality. */
class TestHelper {
+ private final String TAG = TestHelper.class.getSimpleName();
+
private final Context context;
private final Handler handler;
private final Activity activity;
@@ -473,13 +491,21 @@
}
public synchronized Bitmap generateBitmapFromVideoViewSnapshot(VideoViewSnapshot snapshot) {
+ final long timeOutMs = TimeUnit.SECONDS.toMillis(10);
+ final long start = SystemClock.elapsedRealtime();
handler.post(snapshot);
try {
- while (!snapshot.isBitmapReady()) {
+ while (!snapshot.isBitmapReady()
+ && (SystemClock.elapsedRealtime() - start < timeOutMs)) {
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
+ return null;
+ }
+ if (!snapshot.isBitmapReady()) {
+ Log.e(TAG, "Time out in generateBitmapFromVideoViewSnapshot().");
+ return null;
}
return snapshot.getBitmap();
}
@@ -1165,8 +1191,7 @@
class SurfaceViewSnapshot extends VideoViewSnapshot {
private static final String TAG = SurfaceViewSnapshot.class.getSimpleName();
- private static final int PIXELCOPY_REQUEST_SLEEP_MS = 30;
- private static final int PIXELCOPY_REQUEST_MAX_ATTEMPTS = 20;
+ private static final int PIXELCOPY_REQUEST_SLEEP_MS = 100;
private static final int PIXELCOPY_TIMEOUT_MS = 1000;
private final Thread copyThread;
@@ -1182,15 +1207,13 @@
bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888);
try {
// Wait for SurfaceView to be available.
- for (int i = 0; i < PIXELCOPY_REQUEST_MAX_ATTEMPTS; i++) {
- copyResult = copyHelper.request(surfaceView, bitmap);
- if (copyResult == PixelCopy.SUCCESS) {
- break;
- }
+ while (copyResult != PixelCopy.SUCCESS) {
Thread.sleep(PIXELCOPY_REQUEST_SLEEP_MS);
+ copyResult = copyHelper.request(surfaceView, bitmap);
}
} catch (InterruptedException e) {
- Log.w(TAG, "Pixel Copy is stopped/interrupted before it finishes.", e);
+ Log.e(TAG, "Pixel Copy is stopped/interrupted before it finishes.", e);
+ bitmap = null;
}
copyHelper.release();
}
@@ -1294,10 +1317,10 @@
try {
waitForByteBuffer();
} catch (InterruptedException e) {
- Log.w(TAG, e.getMessage());
- Log.w(TAG, "ByteBuffer may contain incorrect pixels.");
+ Log.e(TAG, e.getMessage());
+ bitmap = null;
+ return;
}
- // Get ByteBuffer anyway. Let the test fail if ByteBuffer contains incorrect pixels.
ByteBuffer byteBuffer = glSurfaceViewFactory.getByteBuffer();
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
byteBuffer.rewind();
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index 13ebeff..3025306 100755
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -501,9 +501,9 @@
private void testTrackSelection(int resid) throws Exception {
AssetFileDescriptor fd1 = null;
+ MediaExtractor ex1 = new MediaExtractor();
try {
fd1 = mResources.openRawResourceFd(resid);
- MediaExtractor ex1 = new MediaExtractor();
ex1.setDataSource(fd1.getFileDescriptor(), fd1.getStartOffset(), fd1.getLength());
ByteBuffer buf1 = ByteBuffer.allocate(1024*1024);
@@ -664,6 +664,9 @@
}
} finally {
+ if (ex1 != null) {
+ ex1.release();
+ }
if (fd1 != null) {
fd1.close();
}
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
index b3f7a35..9dbcd5e 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -423,52 +423,55 @@
Log.i(TAG, "start encoding");
}
EncodingHelper encodingHelper = new EncodingHelper();
- mEncodingSurface = encodingHelper.startEncoding(maxSize.getWidth(), maxSize.getHeight(),
- mEncoderEventListener);
- GlCompositor compositor = new GlCompositor();
- if (DBG) {
- Log.i(TAG, "start composition");
- }
- compositor.startComposition(mEncodingSurface, maxSize.getWidth(), maxSize.getHeight(),
- numDisplays);
- for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+ try {
+ mEncodingSurface = encodingHelper.startEncoding(
+ maxSize.getWidth(), maxSize.getHeight(), mEncoderEventListener);
+ GlCompositor compositor = new GlCompositor();
if (DBG) {
- Log.i(TAG, "create display");
+ Log.i(TAG, "start composition");
}
- for (int k = 0; k < numDisplays; k++) {
- virtualDisplays[k] =
- new VirtualDisplayPresentation(getContext(),
- compositor.getWindowSurface(k),
- maxSize.getWidth()/numDisplays, maxSize.getHeight());
- virtualDisplays[k].createVirtualDisplay();
- virtualDisplays[k].createPresentation();
- }
- if (DBG) {
- Log.i(TAG, "start rendering");
- }
- for (int k = 0; k < NUM_RENDERING; k++) {
- for (int l = 0; l < numDisplays; l++) {
- virtualDisplays[l].doRendering(COLOR_RED);
+ compositor.startComposition(mEncodingSurface,
+ maxSize.getWidth(), maxSize.getHeight(), numDisplays);
+ for (int j = 0; j < NUM_DISPLAY_CREATION; j++) {
+ if (DBG) {
+ Log.i(TAG, "create display");
}
- // do not care how many frames are actually rendered.
- Thread.sleep(1);
+ for (int k = 0; k < numDisplays; k++) {
+ virtualDisplays[k] =
+ new VirtualDisplayPresentation(getContext(),
+ compositor.getWindowSurface(k),
+ maxSize.getWidth()/numDisplays, maxSize.getHeight());
+ virtualDisplays[k].createVirtualDisplay();
+ virtualDisplays[k].createPresentation();
+ }
+ if (DBG) {
+ Log.i(TAG, "start rendering");
+ }
+ for (int k = 0; k < NUM_RENDERING; k++) {
+ for (int l = 0; l < numDisplays; l++) {
+ virtualDisplays[l].doRendering(COLOR_RED);
+ }
+ // do not care how many frames are actually rendered.
+ Thread.sleep(1);
+ }
+ for (int k = 0; k < numDisplays; k++) {
+ virtualDisplays[k].dismissPresentation();
+ virtualDisplays[k].destroyVirtualDisplay();
+ }
+ compositor.recreateWindows();
}
- for (int k = 0; k < numDisplays; k++) {
- virtualDisplays[k].dismissPresentation();
- virtualDisplays[k].destroyVirtualDisplay();
+ if (DBG) {
+ Log.i(TAG, "stop composition");
}
- compositor.recreateWindows();
+ compositor.stopComposition();
+ } finally {
+ if (DBG) {
+ Log.i(TAG, "stop encoding");
+ }
+ encodingHelper.stopEncoding();
+ assertTrue(mCodecConfigReceived);
+ assertTrue(mCodecBufferReceived);
}
- if (DBG) {
- Log.i(TAG, "stop composition");
- }
- compositor.stopComposition();
- if (DBG) {
- Log.i(TAG, "stop encoding");
- }
- encodingHelper.stopEncoding();
- assertTrue(mCodecConfigReceived);
- assertTrue(mCodecBufferReceived);
}
}
@@ -553,15 +556,15 @@
throw new RuntimeException("encoder "+ MIME_TYPE + " not support : " + format.toString());
}
- mEncoder = MediaCodec.createByCodecName(codecName);
- mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
- mEncodingSurface = mEncoder.createInputSurface();
- mEncoder.start();
- mInitCompleted.release();
- if (DBG) {
- Log.i(TAG, "starting encoder");
- }
try {
+ mEncoder = MediaCodec.createByCodecName(codecName);
+ mEncoder.configure(format, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
+ mEncodingSurface = mEncoder.createInputSurface();
+ mEncoder.start();
+ mInitCompleted.release();
+ if (DBG) {
+ Log.i(TAG, "starting encoder");
+ }
ByteBuffer[] encoderOutputBuffers = mEncoder.getOutputBuffers();
MediaCodec.BufferInfo info = new MediaCodec.BufferInfo();
while (!mStopEncoding) {
@@ -596,11 +599,15 @@
e.printStackTrace();
throw e;
} finally {
- mEncoder.stop();
- mEncoder.release();
- mEncoder = null;
- mEncodingSurface.release();
- mEncodingSurface = null;
+ if (mEncoder != null) {
+ mEncoder.stop();
+ mEncoder.release();
+ mEncoder = null;
+ }
+ if (mEncodingSurface != null) {
+ mEncodingSurface.release();
+ mEncodingSurface = null;
+ }
}
}
}
diff --git a/tests/tests/media/src/android/media/cts/EncoderTest.java b/tests/tests/media/src/android/media/cts/EncoderTest.java
index adb2351..e086347 100644
--- a/tests/tests/media/src/android/media/cts/EncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/EncoderTest.java
@@ -161,7 +161,7 @@
try {
pool.shutdown();
assertTrue("timed out waiting for encoder threads",
- pool.awaitTermination(5, TimeUnit.MINUTES));
+ pool.awaitTermination(10, TimeUnit.MINUTES));
} catch (InterruptedException e) {
fail("interrupted while waiting for encoder threads");
}
diff --git a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
index 7258303..2ba10df 100644
--- a/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRecorderTest.java
@@ -976,13 +976,14 @@
boolean success = false;
Surface surface = null;
int noOfFailure = 0;
- final float frameRate = getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H264);
if (!hasH264()) {
MediaUtils.skipTest("no codecs");
return true;
}
+ final float frameRate = getMaxFrameRateForCodec(MediaRecorder.VideoEncoder.H264);
+
try {
if (persistent) {
surface = MediaCodec.createPersistentInputSurface();
diff --git a/tests/tests/mediastress/preconditions/Android.mk b/tests/tests/mediastress/preconditions/Android.mk
index 139bf23..573f083 100644
--- a/tests/tests/mediastress/preconditions/Android.mk
+++ b/tests/tests/mediastress/preconditions/Android.mk
@@ -18,7 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/mediastress/preconditions/tests/Android.mk b/tests/tests/mediastress/preconditions/tests/Android.mk
index 28549f5..e2dae48 100644
--- a/tests/tests/mediastress/preconditions/tests/Android.mk
+++ b/tests/tests/mediastress/preconditions/tests/Android.mk
@@ -20,7 +20,7 @@
LOCAL_STATIC_JAVA_LIBRARIES := easymock
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt compatibility-host-media-preconditions
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed compatibility-host-media-preconditions
LOCAL_MODULE_TAGS := optional
diff --git a/tests/tests/os/Android.mk b/tests/tests/os/Android.mk
index 6697f7e..0c564a7 100644
--- a/tests/tests/os/Android.mk
+++ b/tests/tests/os/Android.mk
@@ -51,3 +51,34 @@
include $(BUILD_CTS_PACKAGE)
include $(call all-makefiles-under,$(LOCAL_PATH))
+
+# platform version check (b/32056228)
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := cts-platform-version-check
+LOCAL_MODULE_CLASS := ETC
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+# Tag this module as a cts test artifact
+LOCAL_COMPATIBILITY_SUITE := cts
+
+cts_platform_version_path := cts/tests/tests/os/assets/platform_versions.txt
+cts_platform_version_string := $(shell cat $(cts_platform_version_path))
+
+include $(BUILD_SYSTEM)/base_rules.mk
+
+$(LOCAL_BUILT_MODULE) : $(cts_platform_version_path) build/core/version_defaults.mk
+ $(hide) if [ -z "$(findstring $(PLATFORM_VERSION),$(cts_platform_version_string))" ]; then \
+ echo "============================================================" 1>&2; \
+ echo "Could not find version \"$(PLATFORM_VERSION)\" in CTS platform version file:" 1>&2; \
+ echo "" 1>&2; \
+ echo " $(cts_platform_version_path)" 1>&2; \
+ echo "" 1>&2; \
+ echo "Most likely PLATFORM_VERSION in build/core/version_defaults.mk" 1>&2; \
+ echo "has changed and a new version must be added to this CTS file." 1>&2; \
+ echo "============================================================" 1>&2; \
+ exit 1; \
+ fi
+ @mkdir -p $(dir $@)
+ echo $(cts_platform_version_string) > $@
diff --git a/tests/tests/os/assets/minijail/isolated-arm.policy b/tests/tests/os/assets/minijail/isolated-arm.policy
index e5e5e6f..2e47d92 100644
--- a/tests/tests/os/assets/minijail/isolated-arm.policy
+++ b/tests/tests/os/assets/minijail/isolated-arm.policy
@@ -41,8 +41,8 @@
mkdir: return EPERM
mknod: return EPERM
-# mmap2: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap2: 1
+# mmap2: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap2: arg3 in 0x24833
_newselect: 1
open: 1
diff --git a/tests/tests/os/assets/minijail/isolated-arm64.policy b/tests/tests/os/assets/minijail/isolated-arm64.policy
index e092751..66be1f7 100644
--- a/tests/tests/os/assets/minijail/isolated-arm64.policy
+++ b/tests/tests/os/assets/minijail/isolated-arm64.policy
@@ -3,7 +3,7 @@
getdents64: 1
getrlimit: 1
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap: arg3 in 0x24833
newfstatat: 1
diff --git a/tests/tests/os/assets/minijail/isolated-common.policy b/tests/tests/os/assets/minijail/isolated-common.policy
index f44486e..48cfd49 100644
--- a/tests/tests/os/assets/minijail/isolated-common.policy
+++ b/tests/tests/os/assets/minijail/isolated-common.policy
@@ -77,9 +77,8 @@
mknodat: return EPERM
mlock: 1
-# mprotect: TODO(rsesek): Restrict arg2 (prot) to ~(PROT_READ | PROT_WRITE | PROT_EXEC)
-# after http://b/31997910 is fixed.
-mprotect: 1
+# mprotect: prot in {PROT_READ|PROT_WRITE|PROT_EXEC}
+mprotect: arg2 in 0x7
mremap: 1
msync: 1
diff --git a/tests/tests/os/assets/minijail/isolated-i386.policy b/tests/tests/os/assets/minijail/isolated-i386.policy
index 43ece54..a5798d0 100644
--- a/tests/tests/os/assets/minijail/isolated-i386.policy
+++ b/tests/tests/os/assets/minijail/isolated-i386.policy
@@ -39,10 +39,9 @@
mkdir: return EPERM
mknod: return EPERM
-# mmap2: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap2: 1
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap2: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap2: arg3 in 0x24833
+mmap: arg3 in 0x24833
_newselect: 1
oldlstat: return EPERM
diff --git a/tests/tests/os/assets/minijail/isolated-x86-64.policy b/tests/tests/os/assets/minijail/isolated-x86-64.policy
index bbbbb90..45ea743 100644
--- a/tests/tests/os/assets/minijail/isolated-x86-64.policy
+++ b/tests/tests/os/assets/minijail/isolated-x86-64.policy
@@ -24,8 +24,8 @@
mkdir: return EPERM
mknod: return EPERM
-# mmap: TODO(rsesek): Restrict arg3 (flags) after http://b/31997910 is fixed.
-mmap: 1
+# mmap: flags in {MAP_SHARED|MAP_PRIVATE|MAP_ANONYMOUS|MAP_STACK|MAP_NORESERVE|MAP_FIXED|MAP_DENYWRITE}
+mmap: arg3 in 0x24833
newfstatat: 1
open: 1
diff --git a/tests/tests/os/assets/platform_versions.txt b/tests/tests/os/assets/platform_versions.txt
new file mode 100644
index 0000000..2638c45
--- /dev/null
+++ b/tests/tests/os/assets/platform_versions.txt
@@ -0,0 +1 @@
+O
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index e39249b..d06171b 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -16,10 +16,16 @@
package android.os.cts;
+import android.content.res.AssetManager;
import android.os.Build;
import android.platform.test.annotations.RestrictedBuildTest;
+import android.support.test.InstrumentationRegistry;
import android.util.Log;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
@@ -29,17 +35,16 @@
public class BuildVersionTest extends TestCase {
private static final String LOG_TAG = "BuildVersionTest";
- private static final Set<String> EXPECTED_RELEASES =
- new HashSet<String>(Arrays.asList("7.1","7.1.1","7.1.2"));
private static final int EXPECTED_SDK = 25;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_TAG = "release-keys";
+ private static final String PLATFORM_VERSIONS_FILE = "platform_versions.txt";
@SuppressWarnings("deprecation")
@RestrictedBuildTest
public void testReleaseVersion() {
// Applications may rely on the exact release version
- assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, EXPECTED_RELEASES);
+ assertAnyOf("BUILD.VERSION.RELEASE", Build.VERSION.RELEASE, getExpectedReleases());
assertEquals("Build.VERSION.SDK", "" + EXPECTED_SDK, Build.VERSION.SDK);
assertEquals("Build.VERSION.SDK_INT", EXPECTED_SDK, Build.VERSION.SDK_INT);
}
@@ -94,4 +99,20 @@
", should be one of: " + permittedValues);
}
}
+
+ private Set<String> getExpectedReleases() {
+ Set<String> expectedReleases = new HashSet<String>();
+ final AssetManager assets =
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getAssets();
+ String line;
+ try (BufferedReader br =
+ new BufferedReader(new InputStreamReader(assets.open(PLATFORM_VERSIONS_FILE)))) {
+ while ((line = br.readLine()) != null) {
+ expectedReleases.add(line);
+ }
+ } catch (IOException e) {
+ fail("Could not open file " + PLATFORM_VERSIONS_FILE + " to run test");
+ }
+ return expectedReleases;
+ }
}
diff --git a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
index f93aacf..2a4b6da 100644
--- a/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/TelephonyManagerPermissionTest.java
@@ -16,31 +16,40 @@
package android.permission.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.media.AudioManager;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
/**
* Test the non-location-related functionality of TelephonyManager.
*/
-public class TelephonyManagerPermissionTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TelephonyManagerPermissionTest {
private boolean mHasTelephony;
TelephonyManager mTelephonyManager = null;
private AudioManager mAudioManager;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mHasTelephony = getContext().getPackageManager().hasSystemFeature(
PackageManager.FEATURE_TELEPHONY);
- mTelephonyManager = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
+ mTelephonyManager =
+ (TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
assertNotNull(mTelephonyManager);
- mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
+ mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
assertNotNull(mAudioManager);
}
@@ -50,7 +59,7 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE}.
*/
- @SmallTest
+ @Test
public void testGetDeviceId() {
if (!mHasTelephony) {
return;
@@ -76,7 +85,7 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE}.
*/
- @SmallTest
+ @Test
public void testGetLine1Number() {
if (!mHasTelephony) {
return;
@@ -96,7 +105,7 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE}.
*/
- @SmallTest
+ @Test
public void testGetSimSerialNumber() {
if (!mHasTelephony) {
return;
@@ -116,7 +125,7 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE}.
*/
- @SmallTest
+ @Test
public void testGetSubscriberId() {
if (!mHasTelephony) {
return;
@@ -136,7 +145,7 @@
* Requires Permission:
* {@link android.Manifest.permission#READ_PHONE_STATE}.
*/
- @SmallTest
+ @Test
public void testVoiceMailNumber() {
if (!mHasTelephony) {
return;
@@ -157,7 +166,7 @@
* {@link android.Manifest.permission#MODIFY_PHONE_STATE} for
* {@link AudioManager#MODE_IN_CALL}.
*/
- @SmallTest
+ @Test
public void testSetMode() {
if (!mHasTelephony) {
return;
@@ -168,9 +177,28 @@
}
/**
+ * Verify that TelephonyManager.setDataEnabled requires Permission.
+ * <p>
+ * Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE}.
+ */
+ @Test
+ public void testSetDataEnabled() {
+ if (!mHasTelephony) {
+ return;
+ }
+ try {
+ mTelephonyManager.setDataEnabled(false);
+ fail("Able to set data enabled");
+ } catch (SecurityException e) {
+ // expected
+ }
+ }
+
+ /**
* Verify that Telephony related broadcasts are protected.
*/
- @SmallTest
+ @Test
public void testProtectedBroadcasts() {
if (!mHasTelephony) {
return;
@@ -215,4 +243,8 @@
} catch (SecurityException e) {}
}
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
}
diff --git a/tests/tests/provider/Android.mk b/tests/tests/provider/Android.mk
index ee51fea..eb0406e 100644
--- a/tests/tests/provider/Android.mk
+++ b/tests/tests/provider/Android.mk
@@ -31,7 +31,7 @@
LOCAL_JAVA_LIBRARIES := android.test.runner telephony-common
LOCAL_STATIC_JAVA_LIBRARIES := \
- ctsdeviceutil ctstestrunner
+ ctsdeviceutil ctstestrunner ub-uiautomator
LOCAL_JNI_SHARED_LIBRARIES := libcts_jni libnativehelper_compat_libc++
diff --git a/tests/tests/provider/AndroidManifest.xml b/tests/tests/provider/AndroidManifest.xml
index 1c34dfa..8c1c3cc 100644
--- a/tests/tests/provider/AndroidManifest.xml
+++ b/tests/tests/provider/AndroidManifest.xml
@@ -51,6 +51,8 @@
</intent-filter>
</activity>
+ <activity android:name="android.provider.cts.GetResultActivity" />
+
<service android:name="android.provider.cts.contacts.account.MockAccountService"
process="android.provider.cts"
android:exported="true">
diff --git a/tests/tests/provider/src/android/provider/cts/GetResultActivity.java b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
new file mode 100644
index 0000000..382ca6f
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/GetResultActivity.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.provider.cts;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+
+import java.util.concurrent.SynchronousQueue;
+import java.util.concurrent.TimeUnit;
+
+public class GetResultActivity extends Activity {
+ private final SynchronousQueue<Result> mResult = new SynchronousQueue<>();
+
+ public static class Result {
+ public final int requestCode;
+ public final int resultCode;
+ public final Intent data;
+
+ public Result(int requestCode, int resultCode, Intent data) {
+ this.requestCode = requestCode;
+ this.resultCode = resultCode;
+ this.data = data;
+ }
+ }
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+ | WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data) {
+ try {
+ mResult.offer(new Result(requestCode, resultCode, data), 5, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ public Result getResult() {
+ final Result result;
+ try {
+ result = mResult.poll(30, TimeUnit.SECONDS);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ if (result == null) {
+ throw new IllegalStateException("Activity didn't receive a Result in 30 seconds");
+ }
+ return result;
+ }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
new file mode 100644
index 0000000..3ede99c
--- /dev/null
+++ b/tests/tests/provider/src/android/provider/cts/MediaStoreUiTest.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.provider.cts;
+
+import android.app.Activity;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.UriPermission;
+import android.content.pm.PackageManager;
+import android.media.MediaScannerConnection;
+import android.net.Uri;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.storage.StorageManager;
+import android.os.storage.StorageVolume;
+import android.provider.DocumentsContract;
+import android.provider.MediaStore;
+import android.provider.cts.GetResultActivity.Result;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+import android.test.InstrumentationTestCase;
+import android.text.format.DateUtils;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+import java.io.OutputStream;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class MediaStoreUiTest extends InstrumentationTestCase {
+
+ private static final int REQUEST_CODE = 42;
+ private static final String CONTENT = "Test";
+
+ private UiDevice mDevice;
+ private GetResultActivity mActivity;
+
+ private File mFile;
+ private Uri mMediaStoreUri;
+
+ @Override
+ public void setUp() throws Exception {
+ mDevice = UiDevice.getInstance(getInstrumentation());
+
+ final Context context = getInstrumentation().getContext();
+ mActivity = launchActivity(context.getPackageName(), GetResultActivity.class, null);
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ if (mFile != null) {
+ mFile.delete();
+ }
+
+ final ContentResolver resolver = mActivity.getContentResolver();
+ for (UriPermission permission : resolver.getPersistedUriPermissions()) {
+ mActivity.revokeUriPermission(
+ permission.getUri(),
+ Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ }
+
+ mActivity.finish();
+ }
+
+ public void testGetDocumentUri() throws Exception {
+ if (!supportsHardware()) return;
+
+ prepareFile();
+
+ final Uri treeUri = acquireAccess(mFile, Environment.DIRECTORY_DOCUMENTS);
+ assertNotNull(treeUri);
+
+ final Uri docUri = MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+ assertNotNull(docUri);
+
+ final ContentResolver resolver = mActivity.getContentResolver();
+ try (ParcelFileDescriptor fd = resolver.openFileDescriptor(docUri, "rw")) {
+ // Test reading
+ try (final BufferedReader reader =
+ new BufferedReader(new FileReader(fd.getFileDescriptor()))) {
+ assertEquals(CONTENT, reader.readLine());
+ }
+
+ // Test writing
+ try (final OutputStream out = new FileOutputStream(fd.getFileDescriptor())) {
+ out.write(CONTENT.getBytes());
+ }
+ }
+ }
+
+ public void testGetDocumentUri_ThrowsWithoutPermission() throws Exception {
+ if (!supportsHardware()) return;
+
+ prepareFile();
+
+ try {
+ MediaStore.getDocumentUri(mActivity, mMediaStoreUri);
+ fail("Expecting SecurityException.");
+ } catch (SecurityException e) {
+ // Expected
+ }
+ }
+
+ private boolean supportsHardware() {
+ final PackageManager pm = getInstrumentation().getContext().getPackageManager();
+ return !pm.hasSystemFeature("android.hardware.type.television")
+ && !pm.hasSystemFeature("android.hardware.type.watch");
+ }
+
+ private void prepareFile() throws Exception {
+ assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState());
+
+ final File documents =
+ Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS);
+ documents.mkdirs();
+ assertTrue(documents.isDirectory());
+
+ mFile = new File(documents, "test.txt");
+ try (OutputStream os = new FileOutputStream(mFile)) {
+ os.write(CONTENT.getBytes());
+ }
+
+ final CountDownLatch latch = new CountDownLatch(1);
+ MediaScannerConnection.scanFile(
+ mActivity,
+ new String[]{ mFile.getAbsolutePath() },
+ new String[]{ "plain/text" },
+ (String path, Uri uri) -> onScanCompleted(uri, latch)
+ );
+ assertTrue(
+ "MediaScanner didn't finish scanning in 30s.", latch.await(30, TimeUnit.SECONDS));
+ }
+
+ private void onScanCompleted(Uri uri, CountDownLatch latch) {
+ mMediaStoreUri = uri;
+ latch.countDown();
+ }
+
+ private Uri acquireAccess(File file, String directoryName) {
+ StorageManager storageManager =
+ (StorageManager) mActivity.getSystemService(Context.STORAGE_SERVICE);
+
+ // Request access from DocumentsUI
+ final StorageVolume volume = storageManager.getStorageVolume(file);
+ final Intent intent = volume.createAccessIntent(directoryName);
+ mActivity.startActivityForResult(intent, REQUEST_CODE);
+
+ // Granting the access
+ BySelector buttonPanelSelector = By.pkg("com.android.documentsui")
+ .res("android:id/buttonPanel");
+ mDevice.wait(Until.hasObject(buttonPanelSelector), 30 * DateUtils.SECOND_IN_MILLIS);
+ final UiObject2 buttonPanel = mDevice.findObject(buttonPanelSelector);
+ final UiObject2 allowButton = buttonPanel.findObject(By.res("android:id/button1"));
+ allowButton.click();
+
+ mDevice.waitForIdle();
+
+ // Check granting result and take persistent permission
+ final Result result = mActivity.getResult();
+ assertEquals(Activity.RESULT_OK, result.resultCode);
+
+ final Intent resultIntent = result.data;
+ final Uri resultUri = resultIntent.getData();
+ final int flags = resultIntent.getFlags()
+ & (Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+ mActivity.getContentResolver().takePersistableUriPermission(resultUri, flags);
+ return resultUri;
+ }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
index 5ec765c..485b39c 100644
--- a/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/MediaStore_Video_MediaTest.java
@@ -228,6 +228,9 @@
private Uri insertVideo(Context context) throws IOException {
File file = new File(Environment.getExternalStorageDirectory(), "testVideo.3gp");
+ // clean up any potential left over entries from a previous aborted run
+ cleanExternalMediaFile(file.getAbsolutePath());
+
new FileCopyHelper(context).copyToExternalStorage(R.raw.testvideo, file);
ContentValues values = new ContentValues();
diff --git a/tests/tests/security/Android.mk b/tests/tests/security/Android.mk
index 4668107..c739fa5 100644
--- a/tests/tests/security/Android.mk
+++ b/tests/tests/security/Android.mk
@@ -26,35 +26,13 @@
LOCAL_JAVA_LIBRARIES := android.test.runner org.apache.http.legacy
LOCAL_JNI_SHARED_LIBRARIES := libctssecurity_jni libcts_jni libnativehelper_compat_libc++ \
- libnativehelper \
- libbinder \
- libutils \
- libmedia \
- libselinux \
- libcutils \
- libcrypto \
- libc++ \
- libbacktrace \
- libui \
- libsonivox \
- libexpat \
- libcamera_client \
- libgui \
- libaudioutils \
- libaudiohal \
- libnbaio \
- libpcre2 \
- libpackagelistparser \
- libpowermanager \
- libbase \
- libunwind \
- libhardware \
- libsync \
- libcamera_metadata \
- libspeexresampler \
- liblzma \
- libstagefright_foundation \
- libeffects
+ libnativehelper \
+ libcutils \
+ libcrypto \
+ libselinux \
+ libc++ \
+ libpcre2 \
+ libpackagelistparser
LOCAL_SRC_FILES := $(call all-java-files-under, src)\
src/android/security/cts/activity/ISecureRandomService.aidl\
diff --git a/tests/tests/security/jni/Android.mk b/tests/tests/security/jni/Android.mk
index 2a94aff..5b8b49e 100644
--- a/tests/tests/security/jni/Android.mk
+++ b/tests/tests/security/jni/Android.mk
@@ -31,39 +31,16 @@
android_security_cts_MMapExecutableTest.cpp \
android_security_cts_EncryptionTest.cpp \
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE) \
- $(TOP)/frameworks/native/include/media/openmax
-
-LOCAL_SHARED_LIBRARIES := libnativehelper \
+LOCAL_SHARED_LIBRARIES := \
+ libnativehelper \
liblog \
- libutils \
- libmedia \
- libselinux \
- libdl \
libcutils \
libcrypto \
+ libselinux \
libc++ \
- libbacktrace \
- libui \
- libsonivox \
- libexpat \
- libcamera_client \
- libgui \
- libaudioutils \
- libaudiohal \
- libnbaio \
libpcre2 \
libpackagelistparser \
- libpowermanager \
- libbase \
- libunwind \
- libhardware \
- libsync \
- libcamera_metadata \
- libspeexresampler \
- liblzma \
- libstagefright_foundation \
- libeffects
+
LOCAL_C_INCLUDES += ndk/sources/cpufeatures
LOCAL_STATIC_LIBRARIES := cpufeatures
diff --git a/tests/tests/security/res/raw/bug_31647370.ogg b/tests/tests/security/res/raw/bug_31647370.ogg
new file mode 100644
index 0000000..31f602a
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_31647370.ogg
Binary files differ
diff --git a/tests/tests/security/res/raw/onekhzsine_90sec.mp3 b/tests/tests/security/res/raw/onekhzsine_90sec.mp3
new file mode 100644
index 0000000..3049011
--- /dev/null
+++ b/tests/tests/security/res/raw/onekhzsine_90sec.mp3
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/BrowserTest.java b/tests/tests/security/src/android/security/cts/BrowserTest.java
index 0948713..f468d66 100644
--- a/tests/tests/security/src/android/security/cts/BrowserTest.java
+++ b/tests/tests/security/src/android/security/cts/BrowserTest.java
@@ -172,7 +172,13 @@
// do a file request
intent.setData(Uri.fromFile(htmlFile));
- mContext.startActivity(intent);
+
+ try {
+ mContext.startActivity(intent);
+ } catch (SecurityException e) {
+ // If browser activity cannot be started, skip the test.
+ continue;
+ }
/*
* Wait 5 seconds for the browser to contact the server, but
diff --git a/tests/tests/security/src/android/security/cts/EffectBundleTest.java b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
index 6361a54..2fa4218 100644
--- a/tests/tests/security/src/android/security/cts/EffectBundleTest.java
+++ b/tests/tests/security/src/android/security/cts/EffectBundleTest.java
@@ -22,50 +22,135 @@
import android.test.InstrumentationTestCase;
import android.util.Log;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
public class EffectBundleTest extends InstrumentationTestCase {
private static final String TAG = "EffectBundleTest";
- private static final int[] BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1};
+ private static final int[] INVALID_BAND_ARRAY = {Integer.MIN_VALUE, -10000, -100, -2, -1};
private static final int mValue0 = 9999; //unlikely values. Should not change
private static final int mValue1 = 13877;
+ private static final int PRESET_CUSTOM = -1; //keep in sync AudioEqualizer.h
+
+ private static final int MEDIA_SHORT = 0;
+ private static final int MEDIA_LONG = 1;
//Testing security bug: 32436341
public void testEqualizer_getParamCenterFreq() throws Exception {
- testGetParam(Equalizer.PARAM_CENTER_FREQ, BAND_ARRAY, mValue0, mValue1);
+ testGetParam(MEDIA_SHORT, Equalizer.PARAM_CENTER_FREQ, INVALID_BAND_ARRAY, mValue0,
+ mValue1);
+ }
+
+ //Testing security bug: 32588352
+ public void testEqualizer_getParamCenterFreq_long() throws Exception {
+ testGetParam(MEDIA_LONG, Equalizer.PARAM_CENTER_FREQ, INVALID_BAND_ARRAY, mValue0, mValue1);
}
//Testing security bug: 32438598
public void testEqualizer_getParamBandLevel() throws Exception {
- testGetParam(Equalizer.PARAM_BAND_LEVEL, BAND_ARRAY, mValue0, mValue1);
+ testGetParam(MEDIA_SHORT, Equalizer.PARAM_BAND_LEVEL, INVALID_BAND_ARRAY, mValue0, mValue1);
+ }
+
+ //Testing security bug: 32584034
+ public void testEqualizer_getParamBandLevel_long() throws Exception {
+ testGetParam(MEDIA_LONG, Equalizer.PARAM_BAND_LEVEL, INVALID_BAND_ARRAY, mValue0, mValue1);
}
//Testing security bug: 32247948
public void testEqualizer_getParamFreqRange() throws Exception {
- testGetParam(Equalizer.PARAM_BAND_FREQ_RANGE, BAND_ARRAY, mValue0, mValue1);
+ testGetParam(MEDIA_SHORT, Equalizer.PARAM_BAND_FREQ_RANGE, INVALID_BAND_ARRAY, mValue0,
+ mValue1);
}
- private void testGetParam(int command, int[] bandArray, int value0, int value1) {
+ //Testing security bug: 32588756
+ public void testEqualizer_getParamFreqRange_long() throws Exception {
+ testGetParam(MEDIA_LONG, Equalizer.PARAM_BAND_FREQ_RANGE, INVALID_BAND_ARRAY, mValue0,
+ mValue1);
+ }
+
+ //Testing security bug: 32448258
+ public void testEqualizer_getParamPresetName() throws Exception {
+ testParamPresetName(MEDIA_SHORT);
+ }
+
+ //Testing security bug: 32588016
+ public void testEqualizer_getParamPresetName_long() throws Exception {
+ testParamPresetName(MEDIA_LONG);
+ }
+
+ private void testParamPresetName(int media) {
+ final int command = Equalizer.PARAM_GET_PRESET_NAME;
+ for (int invalidBand : INVALID_BAND_ARRAY)
+ {
+ final byte testValue = 7;
+ byte reply[] = new byte[Equalizer.PARAM_STRING_SIZE_MAX];
+ Arrays.fill(reply, testValue);
+ if (!eqGetParam(media, command, invalidBand, reply)) {
+ fail("getParam PARAM_GET_PRESET_NAME did not complete successfully");
+ }
+ //Compare
+ if (invalidBand == PRESET_CUSTOM) {
+ final String expectedName = "Custom";
+ int length = 0;
+ while (reply[length] != 0) length++;
+ try {
+ final String presetName = new String(reply, 0, length,
+ StandardCharsets.ISO_8859_1.name());
+ assertEquals("getPresetName custom preset name failed", expectedName,
+ presetName);
+ } catch (Exception e) {
+ Log.w(TAG,"Problem creating reply string.");
+ }
+ } else {
+ for (int i = 0; i< reply.length; i++) {
+ assertEquals(String.format("getParam should not change reply at byte %d", i),
+ testValue, reply[i]);
+ }
+ }
+ }
+ }
+
+ //testing security bug: 32095626
+ public void testEqualizer_setParamBandLevel() throws Exception {
+ final int command = Equalizer.PARAM_BAND_LEVEL;
+ short[] value = { 1000 };
+ for (int invalidBand : INVALID_BAND_ARRAY)
+ {
+ if (!eqSetParam(MEDIA_SHORT, command, invalidBand, value)) {
+ fail("setParam PARAM_BAND_LEVEL did not complete successfully");
+ }
+ }
+ }
+
+ //testing security bug: 32585400
+ public void testEqualizer_setParamBandLevel_long() throws Exception {
+ final int command = Equalizer.PARAM_BAND_LEVEL;
+ short[] value = { 1000 };
+ for (int invalidBand : INVALID_BAND_ARRAY)
+ {
+ if (!eqSetParam(MEDIA_LONG, command, invalidBand, value)) {
+ fail("setParam PARAM_BAND_LEVEL did not complete successfully");
+ }
+ }
+ }
+
+ private boolean eqGetParam(int media, int command, int band, byte[] reply) {
MediaPlayer mp = null;
Equalizer eq = null;
+ boolean status = false;
try {
- mp = MediaPlayer.create(getInstrumentation().getContext(), R.raw.good);
+ mp = MediaPlayer.create(getInstrumentation().getContext(), getMediaId(media));
eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
- for (int band : bandArray)
- {
- AudioEffect af = eq;
- int cmd[] = {command, band};
- int reply[] = {value0, value1};
+ AudioEffect af = eq;
+ int cmd[] = {command, band};
- AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
- int[].class).invoke(af, cmd, reply);
-
- //values should remain the same
- assertEquals("getParam should not change value0", value0, reply[0]);
- assertEquals("getParam should not change value1", value1, reply[1]);
- }
-
+ AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
+ byte[].class).invoke(af, cmd, reply);
+ status = true;
} catch (Exception e) {
Log.w(TAG,"Problem testing equalizer");
+ status = false;
} finally {
if (eq != null) {
eq.release();
@@ -74,5 +159,85 @@
mp.release();
}
}
+ return status;
+ }
+
+ private boolean eqGetParam(int media, int command, int band, int[] reply) {
+ MediaPlayer mp = null;
+ Equalizer eq = null;
+ boolean status = false;
+ try {
+ mp = MediaPlayer.create(getInstrumentation().getContext(), getMediaId(media));
+ eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
+
+ AudioEffect af = eq;
+ int cmd[] = {command, band};
+
+ AudioEffect.class.getDeclaredMethod("getParameter", int[].class,
+ int[].class).invoke(af, cmd, reply);
+ status = true;
+ } catch (Exception e) {
+ Log.w(TAG,"Problem getting parameter from equalizer");
+ status = false;
+ } finally {
+ if (eq != null) {
+ eq.release();
+ }
+ if (mp != null) {
+ mp.release();
+ }
+ }
+ return status;
+ }
+
+ private void testGetParam(int media, int command, int[] bandArray, int value0, int value1) {
+ int reply[] = {value0, value1};
+ for (int invalidBand : INVALID_BAND_ARRAY)
+ {
+ if (!eqGetParam(media, command, invalidBand, reply)) {
+ fail(String.format("getParam for command %d did not complete successfully",
+ command));
+ }
+ assertEquals("getParam should not change value0", value0, reply[0]);
+ assertEquals("getParam should not change value1", value1, reply[1]);
+ }
+ }
+
+ private boolean eqSetParam(int media, int command, int band, short[] value) {
+ MediaPlayer mp = null;
+ Equalizer eq = null;
+ boolean status = false;
+ try {
+ mp = MediaPlayer.create(getInstrumentation().getContext(), getMediaId(media));
+ eq = new Equalizer(0 /*priority*/, mp.getAudioSessionId());
+
+ AudioEffect af = eq;
+ int cmd[] = {command, band};
+
+ AudioEffect.class.getDeclaredMethod("setParameter", int[].class,
+ short[].class).invoke(af, cmd, value);
+ status = true;
+ } catch (Exception e) {
+ Log.w(TAG,"Problem setting parameter in equalizer");
+ status = false;
+ } finally {
+ if (eq != null) {
+ eq.release();
+ }
+ if (mp != null) {
+ mp.release();
+ }
+ }
+ return status;
+ }
+
+ private int getMediaId(int media) {
+ switch (media) {
+ default:
+ case MEDIA_SHORT:
+ return R.raw.good;
+ case MEDIA_LONG:
+ return R.raw.onekhzsine_90sec;
+ }
}
}
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 78ce7e7..c501423 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -62,6 +62,10 @@
public StagefrightTest() {
}
+ public void testStagefright_bug_31647370() throws Exception {
+ doStagefrightTest(R.raw.bug_31647370);
+ }
+
public void testStagefright_bug_32577290() throws Exception {
doStagefrightTest(R.raw.bug_32577290);
}
diff --git a/tests/tests/simpleperf/Android.mk b/tests/tests/simpleperf/Android.mk
index 0cfa49b..342752e 100644
--- a/tests/tests/simpleperf/Android.mk
+++ b/tests/tests/simpleperf/Android.mk
@@ -25,6 +25,7 @@
libbase \
libcutils \
liblog \
+ libprocinfo \
libutils \
liblzma \
libLLVMObject \
diff --git a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
index e7130ba..f4eee35 100644
--- a/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/WiredHeadsetTest.java
@@ -69,7 +69,7 @@
assertConnectionState(connection, Connection.STATE_DISCONNECTED);
}
- public void testInCallShortPress_togglesMute() throws Exception {
+ public void testInCallLongPress_togglesMute() throws Exception {
if (!mShouldTestTelecom) {
return;
}
@@ -83,15 +83,15 @@
// Before the audio state is changed for the first time, the connection might not
// know about its audio state yet.
assertMuteState(incallService, false);
- sendMediaButtonShortPress();
+ sendMediaButtonLongPress();
assertMuteState(connection, true);
assertMuteState(incallService, true);
- sendMediaButtonShortPress();
+ sendMediaButtonLongPress();
assertMuteState(connection, false);
assertMuteState(incallService, false);
}
- public void testInCallLongPress_hangupCall() throws Exception {
+ public void testInCallShortPress_hangupCall() throws Exception {
if (!mShouldTestTelecom) {
return;
}
@@ -105,7 +105,7 @@
connection.setActive();
assertCallState(call, Call.STATE_ACTIVE);
- sendMediaButtonLongPress();
+ sendMediaButtonShortPress();
assertCallState(call, Call.STATE_DISCONNECTED);
assertConnectionState(connection, Connection.STATE_DISCONNECTED);
}
diff --git a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
index abacd68..50820b2 100644
--- a/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/src/android/telephony/cts/TelephonyManagerTest.java
@@ -16,6 +16,13 @@
package android.telephony.cts;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
import android.bluetooth.BluetoothAdapter;
import android.content.ComponentName;
import android.content.Context;
@@ -26,20 +33,28 @@
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Looper;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
import android.telecom.PhoneAccount;
import android.telecom.PhoneAccountHandle;
import android.telecom.TelecomManager;
import android.telephony.CellLocation;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
-import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
-import android.test.AndroidTestCase;
import android.util.Log;
+
import com.android.internal.telephony.PhoneConstants;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.regex.Pattern;
-public class TelephonyManagerTest extends AndroidTestCase {
+@RunWith(AndroidJUnit4.class)
+public class TelephonyManagerTest {
private TelephonyManager mTelephonyManager;
private boolean mOnCellLocationChangedCalled = false;
private ServiceState mServiceState;
@@ -47,25 +62,24 @@
private static final int TOLERANCE = 1000;
private PhoneStateListener mListener;
private static ConnectivityManager mCm;
- private static final String TAG = "android.telephony.cts.TelephonyManagerTest";
+ private static final String TAG = "TelephonyManagerTest";
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Before
+ public void setUp() throws Exception {
mTelephonyManager =
(TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
if (mListener != null) {
// unregister the listener
mTelephonyManager.listen(mListener, PhoneStateListener.LISTEN_NONE);
}
- super.tearDown();
}
+ @Test
public void testListen() throws Throwable {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
@@ -131,6 +145,7 @@
* it's no need to get details of these information, just make sure they are in right
* condition(>0 or not null).
*/
+ @Test
public void testTelephonyManager() {
assertTrue(mTelephonyManager.getNetworkType() >= TelephonyManager.NETWORK_TYPE_UNKNOWN);
assertTrue(mTelephonyManager.getPhoneType() >= TelephonyManager.PHONE_TYPE_NONE);
@@ -145,8 +160,8 @@
assertFalse(mTelephonyManager.getMmsUAProfUrl().isEmpty());
}
- // The following methods may return null. Simply call them to make sure they do not
- // throw any exceptions.
+ // The following methods may return any value depending on the state of the device. Simply
+ // call them to make sure they do not throw any exceptions.
mTelephonyManager.getVoiceMailNumber();
mTelephonyManager.getSimOperatorName();
mTelephonyManager.getNetworkCountryIso();
@@ -165,6 +180,7 @@
mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
mTelephonyManager.getDeviceSoftwareVersion();
mTelephonyManager.getPhoneCount();
+ mTelephonyManager.getDataEnabled();
TelecomManager telecomManager = (TelecomManager) getContext()
.getSystemService(Context.TELECOM_SERVICE);
@@ -174,6 +190,7 @@
mTelephonyManager.isVoicemailVibrationEnabled(defaultAccount);
}
+ @Test
public void testCreateForPhoneAccountHandle(){
TelecomManager telecomManager = getContext().getSystemService(TelecomManager.class);
PhoneAccountHandle handle =
@@ -182,6 +199,7 @@
assertEquals(mTelephonyManager.getSubscriberId(), telephonyManager.getSubscriberId());
}
+ @Test
public void testCreateForPhoneAccountHandle_InvalidHandle(){
PhoneAccountHandle handle =
new PhoneAccountHandle(new ComponentName("com.example.foo", "bar"), "baz");
@@ -191,6 +209,7 @@
/**
* Tests that the phone count returned is valid.
*/
+ @Test
public void testGetPhoneCount() {
int phoneCount = mTelephonyManager.getPhoneCount();
int phoneType = mTelephonyManager.getPhoneType();
@@ -212,6 +231,7 @@
* GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
* only a WiFi device.
*/
+ @Test
public void testGetDeviceId() {
String deviceId = mTelephonyManager.getDeviceId();
verifyDeviceId(deviceId);
@@ -222,6 +242,7 @@
* GSM, a valid MEID or ESN if CDMA, or a valid MAC address if
* only a WiFi device.
*/
+ @Test
public void testGetDeviceIdForSlotId() {
String deviceId = mTelephonyManager.getDeviceId(mTelephonyManager.getDefaultSim());
verifyDeviceId(deviceId);
@@ -391,6 +412,7 @@
private static final String ISO_COUNTRY_CODE_PATTERN = "[a-z]{2}";
+ @Test
public void testGetNetworkCountryIso() {
PackageManager packageManager = getContext().getPackageManager();
String countryCode = mTelephonyManager.getNetworkCountryIso();
@@ -403,6 +425,7 @@
}
}
+ @Test
public void testGetSimCountryIso() {
PackageManager packageManager = getContext().getPackageManager();
String countryCode = mTelephonyManager.getSimCountryIso();
@@ -415,6 +438,7 @@
}
}
+ @Test
public void testGetServiceState() throws InterruptedException {
if (mCm.getNetworkInfo(ConnectivityManager.TYPE_MOBILE) == null) {
Log.d(TAG, "Skipping test that requires ConnectivityManager.TYPE_MOBILE");
@@ -445,4 +469,8 @@
assertEquals(mServiceState, mTelephonyManager.getServiceState());
}
+
+ private static Context getContext() {
+ return InstrumentationRegistry.getContext();
+ }
}
diff --git a/tests/tests/view/AndroidManifest.xml b/tests/tests/view/AndroidManifest.xml
index 1844800..4d181e8 100644
--- a/tests/tests/view/AndroidManifest.xml
+++ b/tests/tests/view/AndroidManifest.xml
@@ -266,6 +266,14 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
+
+ <activity android:name="android.view.cts.TooltipActivity"
+ android:label="TooltipActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/view/res/layout/tooltip_layout.xml b/tests/tests/view/res/layout/tooltip_layout.xml
new file mode 100644
index 0000000..8291b31
--- /dev/null
+++ b/tests/tests/view/res/layout/tooltip_layout.xml
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/tooltip_layout"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <LinearLayout
+ android:id="@+id/tooltip_group"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:orientation="vertical">
+
+ <TextView
+ android:id="@+id/no_tooltip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:text="View with no tooltip"/>
+
+ <TextView
+ android:id="@+id/has_tooltip"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:text="View with tooltip"
+ android:tooltip="tooltip text"/>
+
+ </LinearLayout>
+
+ <TextView
+ android:id="@+id/no_tooltip2"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_margin="10dp"
+ android:text="Another view with no tooltip"/>
+
+ <LinearLayout
+ android:id="@+id/empty_group"
+ android:layout_width="100dp"
+ android:layout_height="30dp"
+ android:layout_margin="10dp"
+ android:background="#ddd"/>
+
+</LinearLayout>
diff --git a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
index 3b61da5..2f874fc 100644
--- a/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
+++ b/tests/tests/view/src/android/view/cts/FrameMetricsListenerTest.java
@@ -191,5 +191,3 @@
(firstDrawFrameMetric == 0) || (firstDrawFrameMetric == 1));
}
}
-
-
diff --git a/tests/tests/view/src/android/view/cts/TooltipActivity.java b/tests/tests/view/src/android/view/cts/TooltipActivity.java
new file mode 100644
index 0000000..6cb9967
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipActivity.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ContextMenu;
+import android.view.View;
+
+public class TooltipActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.tooltip_layout);
+ }
+
+ public void onCreateContextMenu(
+ ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
+ menu.add("context menu");
+ }
+}
diff --git a/tests/tests/view/src/android/view/cts/TooltipTest.java b/tests/tests/view/src/android/view/cts/TooltipTest.java
new file mode 100644
index 0000000..b4c94b0
--- /dev/null
+++ b/tests/tests/view/src/android/view/cts/TooltipTest.java
@@ -0,0 +1,745 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.cts.util.CtsTouchUtils;
+import android.cts.util.PollingCheck;
+import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.LargeTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.ViewGroup;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test {@link View}.
+ */
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class TooltipTest {
+ private static final String LOG_TAG = "TooltipTest";
+
+ private static final long TIMEOUT_DELTA = 10000;
+ private static final long WAIT_MARGIN = 100;
+
+ private Instrumentation mInstrumentation;
+ private Activity mActivity;
+ private ViewGroup mTopmostView;
+ private ViewGroup mGroupView;
+ private View mNoTooltipView;
+ private View mTooltipView;
+ private View mNoTooltipView2;
+ private View mEmptyGroup;
+
+ @Rule
+ public ActivityTestRule<TooltipActivity> mActivityRule =
+ new ActivityTestRule<>(TooltipActivity.class);
+
+ @Rule
+ public ActivityTestRule<CtsActivity> mCtsActivityRule =
+ new ActivityTestRule<>(CtsActivity.class, false, false);
+
+ @Before
+ public void setup() {
+ mInstrumentation = InstrumentationRegistry.getInstrumentation();
+ mActivity = mActivityRule.getActivity();
+ mTopmostView = (ViewGroup) mActivity.findViewById(R.id.tooltip_layout);
+ mGroupView = (ViewGroup) mActivity.findViewById(R.id.tooltip_group);
+ mNoTooltipView = mActivity.findViewById(R.id.no_tooltip);
+ mTooltipView = mActivity.findViewById(R.id.has_tooltip);
+ mNoTooltipView2 = mActivity.findViewById(R.id.no_tooltip2);
+ mEmptyGroup = mActivity.findViewById(R.id.empty_group);
+
+ PollingCheck.waitFor(TIMEOUT_DELTA, mActivity::hasWindowFocus);
+ }
+
+ private void waitOut(long msDelay) {
+ try {
+ Thread.sleep(msDelay + WAIT_MARGIN);
+ } catch (InterruptedException e) {
+ Log.e(LOG_TAG, "Wait interrupted. Test may fail!", e);
+ }
+ }
+
+ private void setTooltip(View view, CharSequence tooltip) throws Throwable {
+ mActivityRule.runOnUiThread(() -> view.setTooltip(tooltip));
+ }
+
+ private boolean hasTooltip(View view) {
+ final View tooltipView = view.getTooltipView();
+ return tooltipView != null && tooltipView.getParent() != null;
+ }
+
+
+ private void addView(ViewGroup parent, View view) throws Throwable {
+ mActivityRule.runOnUiThread(() -> parent.addView(view));
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private void removeView(View view) throws Throwable {
+ mActivityRule.runOnUiThread(() -> ((ViewGroup) (view.getParent())).removeView(view));
+ mInstrumentation.waitForIdleSync();
+ }
+
+ private void callPerformLongClick(View view) throws Throwable {
+ mActivityRule.runOnUiThread(() -> view.performLongClick(0, 0));
+ }
+
+ private void requestLowProfileSystemUi() throws Throwable {
+ final int flag = View.SYSTEM_UI_FLAG_LOW_PROFILE;
+ mActivityRule.runOnUiThread(() -> mTooltipView.setSystemUiVisibility(flag));
+ PollingCheck.waitFor(TIMEOUT_DELTA,
+ () -> (mTooltipView.getWindowSystemUiVisibility() & flag) == flag);
+ }
+
+ private void injectKeyPress(View target, int keyCode, int duration) throws Throwable {
+ if (target != null) {
+ mActivityRule.runOnUiThread(() -> {
+ target.setFocusableInTouchMode(true);
+ target.requestFocus();
+ });
+ mInstrumentation.waitForIdleSync();
+ assertTrue(target.isFocused());
+ }
+ mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode));
+ waitOut(duration);
+ mInstrumentation.sendKeySync(new KeyEvent(KeyEvent.ACTION_UP, keyCode));
+ }
+
+ private void injectArbitraryShortKeyPress() throws Throwable {
+ injectKeyPress(null, KeyEvent.KEYCODE_0, 0);
+ }
+
+ private void injectLongKeyPress(View target, int keyCode) throws Throwable {
+ injectKeyPress(target, keyCode, ViewConfiguration.getLongPressTimeout());
+ }
+
+ private void injectLongEnter(View target) throws Throwable {
+ injectLongKeyPress(target, KeyEvent.KEYCODE_ENTER);
+ }
+
+ private void injectShortClick(View target) {
+ CtsTouchUtils.emulateTapOnViewCenter(mInstrumentation, target);
+ }
+
+ private void injectLongClick(View target) {
+ CtsTouchUtils.emulateLongPressOnView(mInstrumentation, target,
+ target.getWidth() / 2, target.getHeight() / 2);
+ }
+
+ private void injectMotionEvent(MotionEvent event) {
+ mInstrumentation.sendPointerSync(event);
+ }
+
+ private void injectHoverMove(View target, int offsetX, int offsetY) {
+ injectMotionEvent(obtainMouseEvent(
+ target, MotionEvent.ACTION_HOVER_MOVE, offsetX, offsetY));
+ }
+
+ private void injectHoverMove(View target) {
+ injectHoverMove(target, 0, 0);
+ }
+
+ private void injectLongHoverMove(View target) {
+ injectHoverMove(target);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ }
+
+ private static MotionEvent obtainMouseEvent(View target, int action, int offsetX, int offsetY) {
+ final long eventTime = SystemClock.uptimeMillis();
+ final int[] xy = new int[2];
+ target.getLocationOnScreen(xy);
+ MotionEvent event = MotionEvent.obtain(eventTime, eventTime, action,
+ xy[0] + target.getWidth() / 2 + offsetX, xy[1] + target.getHeight() / 2 + offsetY,
+ 0);
+ event.setSource(InputDevice.SOURCE_MOUSE);
+ return event;
+ }
+
+ @Test
+ public void testGetSetTooltip() throws Throwable {
+ // No tooltip set in resource
+ assertEquals(null, mNoTooltipView.getTooltip());
+
+ // Set the tooltip, read it back
+ final String tooltipString1 = "new tooltip";
+ setTooltip(mNoTooltipView, tooltipString1);
+ assertEquals(tooltipString1, mNoTooltipView.getTooltip());
+
+ // Clear the tooltip.
+ setTooltip(mNoTooltipView, null);
+ assertEquals(null, mNoTooltipView.getTooltip());
+
+ // Check the tooltip set in resource
+ assertEquals("tooltip text", mTooltipView.getTooltip());
+
+ // Clear the tooltip set in resource
+ setTooltip(mTooltipView, null);
+ assertEquals(null, mTooltipView.getTooltip());
+
+ // Set the tooltip again, read it back
+ final String tooltipString2 = "new tooltip 2";
+ setTooltip(mTooltipView, tooltipString2);
+ assertEquals(tooltipString2, mTooltipView.getTooltip());
+ }
+
+ @Test
+ public void testNoTooltipWhenNotSet() throws Throwable {
+ callPerformLongClick(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+
+ injectLongClick(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+
+ injectLongEnter(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+
+ injectLongHoverMove(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+ }
+
+ @Test
+ public void testNoTooltipOnDisabledView() throws Throwable {
+ mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+
+ injectLongClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectLongEnter(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectLongHoverMove(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testUpdateOpenTooltip() throws Throwable {
+ callPerformLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ setTooltip(mTooltipView, "updated tooltip");
+ assertTrue(hasTooltip(mTooltipView));
+
+ setTooltip(mTooltipView, null);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testTooltipHidesOnActivityFocusChange() throws Throwable {
+ callPerformLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ CtsActivity activity = mCtsActivityRule.launchActivity(null);
+ PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mActivity.hasWindowFocus());
+ assertFalse(hasTooltip(mTooltipView));
+ activity.finish();
+ }
+
+ @Test
+ public void testTooltipHidesOnWindowFocusChange() throws Throwable {
+ callPerformLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Show a context menu on another widget.
+ mActivity.registerForContextMenu(mNoTooltipView);
+ mActivityRule.runOnUiThread(() -> mNoTooltipView.showContextMenu(0, 0));
+
+ PollingCheck.waitFor(TIMEOUT_DELTA, () -> !mTooltipView.hasWindowFocus());
+ mInstrumentation.waitForIdleSync();
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ // Tests for tooltips triggered by long click.
+
+ @Test
+ public void testShortClickDoesNotShowTooltip() throws Throwable {
+ injectShortClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testPerformLongClickShowsTooltipImmediately() throws Throwable {
+ callPerformLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipBlockedByLongClickListener() throws Throwable {
+ mTooltipView.setOnLongClickListener(v -> true);
+ injectLongClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipBlockedByContextMenu() throws Throwable {
+ mActivity.registerForContextMenu(mTooltipView);
+ injectLongClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipOnNonClickableView() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipOnClickableView() throws Throwable {
+ mTooltipView.setClickable(true);
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipOnLongClickableView() throws Throwable {
+ mTooltipView.setLongClickable(true);
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipOnContextClickableView() throws Throwable {
+ mTooltipView.setContextClickable(true);
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipStaysOnMouseMove() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Tooltip stays while the mouse moves over the widget.
+ injectHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Long-click-triggered tooltip stays while the mouse to another widget.
+ injectHoverMove(mNoTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipHidesAfterUp() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Long-click-triggered tooltip hides after ACTION_UP (with a delay).
+ waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipHidesOnClick() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipHidesOnClickElsewhere() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongClickTooltipHidesOnKey() throws Throwable {
+ injectLongClick(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectArbitraryShortKeyPress();
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ // Tests for tooltips triggered by long key press.
+
+ @Test
+ public void testShortKeyPressDoesNotShowTooltip() throws Throwable {
+ injectKeyPress(null, KeyEvent.KEYCODE_ENTER, 0);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectKeyPress(mTooltipView, KeyEvent.KEYCODE_ENTER, 0);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongArbitraryKeyPressDoesNotShowTooltip() throws Throwable {
+ injectLongKeyPress(mTooltipView, KeyEvent.KEYCODE_0);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressWithoutFocusDoesNotShowTooltip() throws Throwable {
+ injectLongEnter(null);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressOnAnotherViewDoesNotShowTooltip() throws Throwable {
+ injectLongEnter(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipOnNonClickableView() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipOnClickableView() throws Throwable {
+ mTooltipView.setClickable(true);
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipOnLongClickableView() throws Throwable {
+ mTooltipView.setLongClickable(true);
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipOnContextClickableView() throws Throwable {
+ mTooltipView.setContextClickable(true);
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipStaysOnMouseMove() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Tooltip stays while the mouse moves over the widget.
+ injectHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Long-keypress-triggered tooltip stays while the mouse to another widget.
+ injectHoverMove(mNoTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipHidesAfterUp() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Long-keypress-triggered tooltip hides after ACTION_UP (with a delay).
+ waitOut(ViewConfiguration.getLongPressTooltipHideTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipHidesOnClick() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipHidesOnClickElsewhere() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testLongKeyPressTooltipHidesOnKey() throws Throwable {
+ injectLongEnter(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectArbitraryShortKeyPress();
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ // Tests for tooltips triggered by mouse hover.
+
+ @Test
+ public void testMouseClickDoesNotShowTooltip() throws Throwable {
+ injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_DOWN, 0, 0));
+ injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_PRESS, 0, 0));
+ injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_BUTTON_RELEASE, 0, 0));
+ injectMotionEvent(obtainMouseEvent(mTooltipView, MotionEvent.ACTION_UP, 0, 0));
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverDoesNotShowTooltipImmediately() throws Throwable {
+ injectHoverMove(mTooltipView, 0, 0);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectHoverMove(mTooltipView, 1, 1);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectHoverMove(mTooltipView, 2, 2);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverExitCancelsPendingTooltip() throws Throwable {
+ injectHoverMove(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+
+ injectLongHoverMove(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipOnClickableView() throws Throwable {
+ mTooltipView.setClickable(true);
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipOnLongClickableView() throws Throwable {
+ mTooltipView.setLongClickable(true);
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipOnContextClickableView() throws Throwable {
+ mTooltipView.setContextClickable(true);
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipStaysOnMouseMove() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Tooltip stays while the mouse moves over the widget.
+ injectHoverMove(mTooltipView, 1, 1);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectHoverMove(mTooltipView, 2, 2);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnExit() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ // Tooltip hides once the mouse moves out of the widget.
+ injectHoverMove(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnClick() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnClickOnElsewhere() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectShortClick(mNoTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnKey() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ injectArbitraryShortKeyPress();
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnTimeout() throws Throwable {
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ waitOut(ViewConfiguration.getHoverTooltipHideTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipHidesOnShortTimeout() throws Throwable {
+ requestLowProfileSystemUi();
+
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+
+ waitOut(ViewConfiguration.getHoverTooltipHideShortTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipWithHoverListener() throws Throwable {
+ mTooltipView.setOnHoverListener((v, event) -> true);
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipUnsetWhileHovering() throws Throwable {
+ injectHoverMove(mTooltipView);
+ setTooltip(mTooltipView, null);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipDisableWhileHovering() throws Throwable {
+ injectHoverMove(mTooltipView);
+ mActivityRule.runOnUiThread(() -> mTooltipView.setEnabled(false));
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipFromParent() throws Throwable {
+ // Hover listeners should not interfere with tooltip dispatch.
+ mNoTooltipView.setOnHoverListener((v, event) -> true);
+ mTooltipView.setOnHoverListener((v, event) -> true);
+
+ setTooltip(mTopmostView, "tooltip");
+
+ // Hover over a child with a tooltip works normally.
+ injectLongHoverMove(mTooltipView);
+ assertFalse(hasTooltip(mTopmostView));
+ assertTrue(hasTooltip(mTooltipView));
+ injectShortClick(mTopmostView);
+ assertFalse(hasTooltip(mTooltipView));
+
+ // Hover over a child with no tooltip triggers a tooltip on its parent.
+ injectLongHoverMove(mNoTooltipView2);
+ assertFalse(hasTooltip(mNoTooltipView2));
+ assertTrue(hasTooltip(mTopmostView));
+ injectShortClick(mTopmostView);
+ assertFalse(hasTooltip(mTopmostView));
+
+ // Same but the child is and empty view group.
+ injectLongHoverMove(mEmptyGroup);
+ assertFalse(hasTooltip(mEmptyGroup));
+ assertTrue(hasTooltip(mTopmostView));
+ injectShortClick(mTopmostView);
+ assertFalse(hasTooltip(mTopmostView));
+
+ // Hover over a grandchild with no tooltip triggers a tooltip on its grandparent.
+ injectLongHoverMove(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+ assertTrue(hasTooltip(mTopmostView));
+ // Move to another child one level up, the tooltip stays.
+ injectHoverMove(mNoTooltipView2);
+ assertTrue(hasTooltip(mTopmostView));
+ injectShortClick(mTopmostView);
+ assertFalse(hasTooltip(mTopmostView));
+
+ // Set a tooltip on the intermediate parent, now it is showing tooltips.
+ setTooltip(mGroupView, "tooltip");
+ injectLongHoverMove(mNoTooltipView);
+ assertFalse(hasTooltip(mNoTooltipView));
+ assertFalse(hasTooltip(mTopmostView));
+ assertTrue(hasTooltip(mGroupView));
+
+ // Move out of this group, the tooltip is now back on the grandparent.
+ injectLongHoverMove(mNoTooltipView2);
+ assertFalse(hasTooltip(mGroupView));
+ assertTrue(hasTooltip(mTopmostView));
+ injectShortClick(mTopmostView);
+ assertFalse(hasTooltip(mTopmostView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipRemoveWhileWaiting() throws Throwable {
+ // Remove the view while hovering.
+ injectHoverMove(mTooltipView);
+ removeView(mTooltipView);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ addView(mGroupView, mTooltipView);
+
+ // Remove and re-add the view while hovering.
+ injectHoverMove(mTooltipView);
+ removeView(mTooltipView);
+ addView(mGroupView, mTooltipView);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+
+ // Remove the view's parent while hovering.
+ injectHoverMove(mTooltipView);
+ removeView(mGroupView);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ addView(mTopmostView, mGroupView);
+
+ // Remove and re-add view's parent while hovering.
+ injectHoverMove(mTooltipView);
+ removeView(mGroupView);
+ addView(mTopmostView, mGroupView);
+ waitOut(ViewConfiguration.getHoverTooltipShowTimeout());
+ assertFalse(hasTooltip(mTooltipView));
+ }
+
+ @Test
+ public void testMouseHoverTooltipRemoveWhileShowing() throws Throwable {
+ // Remove the view while showing the tooltip.
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ removeView(mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+ addView(mGroupView, mTooltipView);
+ assertFalse(hasTooltip(mTooltipView));
+
+ // Remove the view's parent while showing the tooltip.
+ injectLongHoverMove(mTooltipView);
+ assertTrue(hasTooltip(mTooltipView));
+ removeView(mGroupView);
+ assertFalse(hasTooltip(mTooltipView));
+ addView(mTopmostView, mGroupView);
+ assertFalse(hasTooltip(mTooltipView));
+ }
+}
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
index 9151783..a011b97 100755
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewTest.java
@@ -2574,6 +2574,35 @@
assertTrue(callbackLatch.await(TEST_TIMEOUT, TimeUnit.MILLISECONDS));
}
+ @UiThreadTest
+ public void testGetWebViewClient() throws Exception {
+ // getWebViewClient should return a default WebViewClient if it hasn't been set yet
+ WebView webView = new WebView(getActivity());
+ WebViewClient client = webView.getWebViewClient();
+ assertNotNull(client);
+ assertTrue(client instanceof WebViewClient);
+
+ // getWebViewClient should return the client after it has been set
+ WebViewClient client2 = new WebViewClient();
+ assertNotSame(client, client2);
+ webView.setWebViewClient(client2);
+ assertSame(client2, webView.getWebViewClient());
+ }
+
+ @UiThreadTest
+ public void testGetWebChromeClient() throws Exception {
+ // getWebChromeClient should return null if the client hasn't been set yet
+ WebView webView = new WebView(getActivity());
+ WebChromeClient client = webView.getWebChromeClient();
+ assertNull(client);
+
+ // getWebChromeClient should return the client after it has been set
+ WebChromeClient client2 = new WebChromeClient();
+ assertNotSame(client, client2);
+ webView.setWebChromeClient(client2);
+ assertSame(client2, webView.getWebChromeClient());
+ }
+
private void savePrintedPage(final PrintDocumentAdapter adapter,
final ParcelFileDescriptor descriptor, final FutureTask<Boolean> result) {
adapter.onWrite(new PageRange[] {PageRange.ALL_PAGES}, descriptor,
diff --git a/tests/tests/widget/AndroidManifest.xml b/tests/tests/widget/AndroidManifest.xml
index f2be3c0..d8ab737 100644
--- a/tests/tests/widget/AndroidManifest.xml
+++ b/tests/tests/widget/AndroidManifest.xml
@@ -554,6 +554,13 @@
</intent-filter>
</activity>
+ <activity android:name="android.widget.cts.PointerIconCtsActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+
<receiver android:name="android.widget.cts.appwidget.MyAppWidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
diff --git a/tests/tests/widget/res/layout/pointer_icon_layout.xml b/tests/tests/widget/res/layout/pointer_icon_layout.xml
new file mode 100644
index 0000000..605eed2
--- /dev/null
+++ b/tests/tests/widget/res/layout/pointer_icon_layout.xml
@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/top"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical">
+
+ <Button
+ android:id="@+id/button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Button"/>
+
+ <ImageButton
+ android:id="@+id/image_button"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:src="@drawable/icon_green"/>
+
+ <Spinner
+ android:id="@+id/spinner"
+ android:layout_width="match_parent"
+ android:layout_height="20dp"/>
+
+ <TabHost
+ android:id="@android:id/tabhost"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+
+ <TabWidget
+ android:id="@android:id/tabs"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"/>
+
+ <FrameLayout
+ android:id="@android:id/tabcontent"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"/>
+
+ </TabHost>
+
+</LinearLayout>
diff --git a/tests/tests/widget/res/layout/textview_layout.xml b/tests/tests/widget/res/layout/textview_layout.xml
index 08354b1..7701726 100644
--- a/tests/tests/widget/res/layout/textview_layout.xml
+++ b/tests/tests/widget/res/layout/textview_layout.xml
@@ -277,6 +277,15 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
+ <TextView
+ android:id="@+id/textview_autosize_xy"
+ android:layout_width="100dp"
+ android:layout_height="200dp"
+ android:text="@string/long_text"
+ android:autoSizeText="xy"
+ android:textSize="50dp"
+ android:autoSizeStepGranularity="2dp" />
+
</LinearLayout>
</ScrollView>
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
new file mode 100644
index 0000000..c0c6b78
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconCtsActivity.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class PointerIconCtsActivity extends Activity {
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.pointer_icon_layout);
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/PointerIconTest.java b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
new file mode 100644
index 0000000..32d07a6
--- /dev/null
+++ b/tests/tests/widget/src/android/widget/cts/PointerIconTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget.cts;
+
+import static org.junit.Assert.assertEquals;
+
+import android.app.Activity;
+import android.cts.util.WidgetTestUtils;
+import android.support.test.annotation.UiThreadTest;
+import android.support.test.filters.SmallTest;
+import android.support.test.rule.ActivityTestRule;
+import android.support.test.runner.AndroidJUnit4;
+import android.view.MotionEvent;
+import android.view.PointerIcon;
+import android.view.View;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class PointerIconTest {
+
+ @Rule
+ public final ActivityTestRule<PointerIconCtsActivity> mActivityRule =
+ new ActivityTestRule<>(PointerIconCtsActivity.class);
+
+ private Activity mActivity;
+ private View mTopView;
+ private PointerIcon mHandIcon;
+ private PointerIcon mHelpIcon;
+
+ @Before
+ public void setup() {
+ mActivity = mActivityRule.getActivity();
+ mTopView = mActivity.findViewById(R.id.top);
+ mHandIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HAND);
+ mHelpIcon = PointerIcon.getSystemIcon(mActivity, PointerIcon.TYPE_HELP);
+ }
+
+ private void assertPointerIcon(String message, PointerIcon expectedIcon, View target) {
+ final int[] topPos = mTopView.getLocationOnScreen();
+ final int[] targetPos = target.getLocationOnScreen();
+ final int x = targetPos[0] + target.getWidth() / 2 - topPos[0];
+ final int y = targetPos[1] + target.getHeight() / 2 - topPos[1];
+ final MotionEvent event = MotionEvent.obtain(0, 0, MotionEvent.ACTION_HOVER_MOVE, x, y, 0);
+ assertEquals(message, expectedIcon, mTopView.onResolvePointerIcon(event, 0));
+ }
+
+ private void assertDefaultWidgetPointerIconBehavior(View view) {
+ assertPointerIcon("Default pointer icon", mHandIcon, view);
+
+ view.setEnabled(false);
+ assertPointerIcon("Disabled view has no pointer icon", null, view);
+
+ view.setEnabled(true);
+ assertPointerIcon("Enabled view has default pointer icon", mHandIcon, view);
+
+ view.setPointerIcon(mHelpIcon);
+ assertPointerIcon("Override pointer icon", mHelpIcon, view);
+
+ view.setPointerIcon(null);
+ assertPointerIcon("Revert to default pointer icon", mHandIcon, view);
+ }
+
+ private TabHost.TabSpec createTabSpec(TabHost tabHost, String label, PointerIcon pointerIcon) {
+ final TextView tabIndicator = new TextView(mActivity);
+ tabIndicator.setText(label);
+ tabIndicator.setPointerIcon(pointerIcon);
+ return tabHost.newTabSpec(label)
+ .setIndicator(tabIndicator)
+ .setContent(tag -> new View(mActivity));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testButton() {
+ assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.button));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testImageButton() {
+ assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.image_button));
+ }
+
+ @UiThreadTest
+ @Test
+ public void testSpinnerButton() {
+ assertDefaultWidgetPointerIconBehavior(mActivity.findViewById(R.id.spinner));
+ }
+
+ @Test
+ public void testTabWidget() throws Throwable {
+ final TabHost tabHost = (TabHost) mActivity.findViewById(android.R.id.tabhost);
+
+ WidgetTestUtils.runOnMainAndLayoutSync(
+ mActivityRule,
+ () -> {
+ tabHost.setup();
+ tabHost.addTab(createTabSpec(tabHost, "Tab 0", null));
+ tabHost.addTab(createTabSpec(tabHost, "Tab 1", mHandIcon));
+ tabHost.addTab(createTabSpec(tabHost, "Tab 2", mHelpIcon));
+ },
+ false /* force layout */);
+
+ mActivityRule.runOnUiThread(() -> {
+ final TabWidget tabWidget = tabHost.getTabWidget();
+
+ tabWidget.setEnabled(false);
+ assertPointerIcon("Disabled Tab 0", null, tabWidget.getChildTabViewAt(0));
+ assertPointerIcon("Disabled Tab 1", null, tabWidget.getChildTabViewAt(1));
+ assertPointerIcon("Disabled Tab 2", null, tabWidget.getChildTabViewAt(2));
+
+ tabWidget.setEnabled(true);
+ assertPointerIcon("Tab 0", mHandIcon, tabWidget.getChildTabViewAt(0));
+ assertPointerIcon("Tab 1", mHandIcon, tabWidget.getChildTabViewAt(1));
+ assertPointerIcon("Tab 2", mHelpIcon, tabWidget.getChildTabViewAt(2));
+ });
+ }
+}
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index e4dbe83..074d4fa 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -6273,6 +6273,21 @@
verify(spanDetails.mClickableSpan, never()).onClick(mTextView);
}
+ @Test
+ public void testAutoSizeXY_obtainStyledAttributes() {
+ DisplayMetrics metrics = mActivity.getResources().getDisplayMetrics();
+ TextView autoSizeTextViewXY = (TextView) mActivity.findViewById(R.id.textview_autosize_xy);
+
+ // The size has been set to 50dp in the layout but this being an AUTO_SIZE_TYPE_XY TextView,
+ // the size is considered max size thus the value returned by getSize() in this case should
+ // be lower than the one set (given that there is not much available space and the font size
+ // is very high). In theory the values could be equal for a different TextView
+ // configuration.
+ final float sizeSetInPixels = TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP, 50f, metrics);
+ assertTrue(autoSizeTextViewXY.getTextSize() < sizeSetInPixels);
+ }
+
/**
* Removes all existing views from the layout and adds a basic TextView (for exercising the
* ClickableSpan onClick() behavior) in order to prevent scrolling. Adds a ClickableSpan to the
diff --git a/tools/cts-api-coverage/src/MANIFEST.mf b/tools/cts-api-coverage/src/MANIFEST.mf
index 63d6674..16533b5 100644
--- a/tools/cts-api-coverage/src/MANIFEST.mf
+++ b/tools/cts-api-coverage/src/MANIFEST.mf
@@ -1,3 +1,3 @@
Manifest-Version: 1.0
Main-Class: com.android.cts.apicoverage.CtsApiCoverage
-Class-Path: tradefed-prebuilt.jar
+Class-Path: tradefed.jar
diff --git a/tools/cts-java-scanner-doclet/Android.mk b/tools/cts-java-scanner-doclet/Android.mk
index d647537..dbd760d 100644
--- a/tools/cts-java-scanner-doclet/Android.mk
+++ b/tools/cts-java-scanner-doclet/Android.mk
@@ -22,6 +22,6 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-LOCAL_JAVA_LIBRARIES := junit
+LOCAL_JAVA_LIBRARIES := junit-host
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-media/get_achievable_rates.py b/tools/cts-media/get_achievable_rates.py
index 9dde743..369a982 100755
--- a/tools/cts-media/get_achievable_rates.py
+++ b/tools/cts-media/get_achievable_rates.py
@@ -14,36 +14,9 @@
# limitations under the License.
#
-import argparse, math, re, sys
+import argparse, json, math, re, sys, zipfile
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'])):
@@ -51,43 +24,50 @@
def __str__(self):
return '%dx%d' % (self.width, self.height)
+def nicekey(v):
+ """Returns a nicer sort key for sorting strings.
-class _VideoResultBase(object):
- """Helper methods for results. Not for use by applications.
+ This sorts using lower case, with numbers in numerical order first."""
+ key = []
+ num = False
+ for p in re.split('(\d+)', v.lower()):
+ if num:
+ key.append(('0', int(p)))
+ elif p:
+ key.append((p, 0))
+ num = not num
+ return key + [(v, 0)]
- 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 nice(v):
+ """Returns a nicer representation for objects in debug messages.
- 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
+ Dictionaries are sorted, size is WxH, unicode removed, and floats have 1 digit precision."""
+ if isinstance(v, dict):
+ return 'dict(' + ', '.join(k + '=' + nice(v) for k, v in sorted(v.items(), key=lambda i: nicekey(i[0]))) + ')'
+ if isinstance(v, str):
+ return repr(v)
+ if isinstance(v, int):
+ return str(v)
+ if isinstance(v, Size):
+ return repr(str(v))
+ if isinstance(v, float):
+ return '%.1f' % v
+ if isinstance(v, type(u'')):
+ return repr(str(v))
+ raise ValueError(v)
- 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
+class ResultParser:
+ @staticmethod
+ def _intify(value):
+ """Returns a value converted to int if possible, else the original value."""
+ try:
+ return int(value)
+ except ValueError:
+ return value
def _parseDict(self, value):
"""Parses a MediaFormat from its string representation sans brackets."""
- return dict((k, _intify(v))
+ return dict((k, self._intify(v))
for k, v in re.findall(r'([^ =]+)=([^ [=]+(?:|\[[^\]]+\]))(?:, |$)', value))
def _cleanFormat(self, format):
@@ -110,293 +90,270 @@
if key.endswith('Format'):
self._cleanFormat(value)
else:
- value = _intify(value)
+ value = self._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>.
+def perc(data, p, fn=round):
+ """Returns a percentile value from a sorted array.
- 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
+ Arguments:
+ data: sorted data
+ p: percentile value (0-100)
+ fn: method used for rounding the percentile to an integer index in data
+ """
+ return data[int(fn((len(data) - 1) * p / 100))]
-class VideoEncoderDecoderTestResult(_VideoResultBase):
- """Represents a result from a VideoEncoderDecoderTest performance case."""
+def genXml(data, A=None):
+ yield '<?xml version="1.0" encoding="utf-8" ?>'
+ yield '<!-- Copyright 2016 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
+ from collections import namedtuple
+ Comp = namedtuple('Comp', 'is_decoder google mime name')
+ Result = namedtuple('Result', 'mn mx p95 med geo p5')
+ for comp_, cdata in sorted(data.items()):
+ comp = Comp(*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)
+ for size, sdata in sorted(cdata.items()):
+ data = sorted(sdata)
+ N = len(data)
+ mn, mx = data[0], data[-1]
- def __init__(self, unused_m):
- super(VideoEncoderDecoderTestResult, self).__init__(is_decoder=False)
+ if N < 20 and not A.ignore:
+ raise ValueError("need at least 20 data points for %s size %s; have %s" %
+ (comp.name, size, N))
- # 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.)
+ TO = 2.2 # tolerance with margin
+ T = TO / 1.1 # tolerance without margin
- 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']
+ Final = namedtuple('Final', 'comment c2 var qual')
+ lastFinal = None
+ for RG in (10, 15, 20, 25, 30, 40, 50):
+ P = 50./RG
+ quality = 0
+ p95, med, p5 = perc(data, P, math.floor), perc(data, 50, round), perc(data, 100 - P, math.ceil)
+ geo = math.sqrt(p5 * p95)
+ comment = ''
+ pub_lo, pub_hi = min(int(p95 * T), round(geo)), max(math.ceil(p5 / T), round(geo))
+ if pub_lo > med:
+ if pub_lo > med * 1.1:
+ quality += 0.5
+ comment += ' SLOW'
+ pub_lo = int(med)
+ if N < 2 * RG:
+ comment += ' N=%d' % N
+ quality += 2
+ RGVAR = False
+ if p5 / p95 > T ** 3:
+ quality += 3
+ RGVAR = True
+ if pub_hi > pub_lo * TO:
+ quality += 1
+ if RG == 10:
+ # find best pub_lo and pub_hi
+ for i in range(N / 2):
+ pub_lo_, pub_hi_ = min(int(data[N / 2 - i - 1] * T), round(geo), int(med)), max(math.ceil(data[N / 2 + i] / T), round(geo))
+ if pub_hi_ > pub_lo_ * TO:
+ # ???
+ pub_lo = min(pub_lo, math.ceil(pub_hi_ / TO))
+ break
+ pub_lo, pub_hi = pub_lo_, pub_hi_
+ if mn < pub_lo / T or mx > pub_hi * T or pub_lo <= pub_hi / T:
+ quality += 1
+ comment += ' FLAKY('
+ if round(mn, 1) < pub_lo / T:
+ comment += 'mn=%.1f < ' % mn
+ comment += 'RANGE'
+ if round(mx, 1) > pub_hi * T:
+ comment += ' < mx=%.1f' % mx
+ comment += ')'
+ if False:
+ comment += ' DATA(mn=%1.f p%d=%1.f accept=%1.f-%1.f p50=%1.f p%d=%1.f mx=%1.f)' % (
+ mn, 100-P, p95, pub_lo / T, pub_hi * T, med, P, p5, mx)
+ var = math.sqrt(p5/p95)
+ if p95 < geo / T or p5 > geo * T:
+ if RGVAR:
+ comment += ' RG.VARIANCE:%.1f' % ((p5/p95) ** (1./3))
+ else:
+ comment += ' variance:%.1f' % var
+ comment = comment.replace('RANGE', '%d - %d' % (math.ceil(pub_lo / T), int(pub_hi * T)))
+ c2 = ''
+ if N >= 2 * RG:
+ c2 += ' N=%d' % N
+ if var <= T or p5 / p95 > T ** 3:
+ c2 += ' v%d%%=%.1f' % (round(100 - 2 * P), var)
+ if A and A.dbg:
+ c2 += ' E=%s' % (str(quality))
+ if c2:
+ c2 = ' <!--%s -->' % c2
- 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'])
+ if comment:
+ comment = ' <!-- measured %d%%:%d-%d med:%d%s -->' % (round(100 - 2 * P), int(p95), math.ceil(p5), int(round(med)), comment)
+ if A and A.dbg: yield '<!-- --> %s%s' % (comment, c2)
+ c2 = ' <Limit name="measured-frame-rate-%s" range="%d-%d" />%s' % (size, pub_lo, pub_hi, c2)
+ final = Final(comment, c2, var, quality)
+ if lastFinal and final.var > lastFinal.var * math.sqrt(1.3):
+ if A and A.dbg: yield '<!-- RANGE JUMP -->'
+ break
+ elif not lastFinal or quality <= lastFinal.qual:
+ lastFinal = final
+ if N < 2 * RG or quality >= 4:
+ break
+ comment, c2, var, quality = lastFinal
+
+ if comment:
+ yield comment
+ yield c2
+ yield ' </MediaCodec>'
+ if last_section:
+ yield ' </%s>' % last_section
+ yield '</MediaCodecs>'
-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."""
+class Data:
def __init__(self):
- self._results = [] # namedtuples
- self._device = None
+ self.data = set()
+ self.kind = {}
+ self.devices = set()
+ self.parser = ResultParser()
- VIDEO_ENCODER_DECODER_TEST_REGEX = re.compile(
- 'test(.*)(\d{4})x(\d{4})(Goog|Other)$')
+ def summarize(self, A=None):
+ devs = sorted(self.devices)
+ # device > (not encoder,goog,mime,codec) > size > fps
+ xmlInfo = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
- VIDEO_DECODER_PERF_TEST_REGEX = re.compile(
- 'test(VP[89]|H26[34]|MPEG4|HEVC)(\d+)x(\d+)(.*)$')
+ for mime, encoder, goog in sorted(set(self.kind.values())):
+ for dev, build, codec, size, num, std, avg, p0, p5, p10, p20, p30, p40, p50, p60, p70, p80, p90, p95, p100 in self.data:
+ if self.kind[codec] != (mime, encoder, goog):
+ continue
- TestCaseSpec = namedtuple('TestCaseSpec', 'package path class_ regex result_class')
+ if p95 > 2: # ignore measurements at or below 2fps
+ xmlInfo[dev][(not encoder, goog, mime, codec)][size].append(p95)
+ else:
+ print >> sys.stderr, "warning: p95 value is suspiciously low: %s" % (
+ nice(dict(config=dict(dev=dev, codec=codec, size=str(size), N=num),
+ data=dict(std=std, avg=avg, p0=p0, p5=p5, p10=p10, p20=p20, p30=p30, p40=p40,
+ p50=p50, p60=p60, p70=p70, p80=p80, p90=p90, p95=p95, p100=p100))))
+ for dev, ddata in xmlInfo.items():
+ outFile = '{}.media_codecs_performance.xml'.format(dev)
+ print >> sys.stderr, "generating", outFile
+ with open(outFile, "wt") as out:
+ for l in genXml(ddata, A=A):
+ out.write(l + '\n')
+ print l
+ print >> sys.stderr, "generated", outFile
- 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 parse_fmt(self, fmt):
+ return self.parser._parseDict(fmt)
- def _verifyDeviceInfo(self, device):
- assert self._device in (None, device), "expected %s device" % self._device
- self._device = device
+ def parse_perf(self, a, device, build):
+ def rateFn(i):
+ if i is None:
+ return i
+ elif i == 0:
+ return 1e6
+ return 1000. / i
- def importXml(self, xml):
- self._verifyDeviceInfo(xml.find('DeviceInfo/BuildInfo').get('buildName'))
+ points = ('avg', 'min', 'p5', 'p10', 'p20', 'p30', 'p40', 'p50', 'p60', 'p70', 'p80', 'p90', 'p95', 'max')
+ a = dict(a)
+ codec = a['codec_name'] + ''
+ mime = a['mime_type']
+ size = Size(a['width'], a['height'])
+ if 'decode_to' in a:
+ fmt = self.parse_fmt(a['output_format'])
+ ofmt = self.parse_fmt(a['input_format'])
+ else:
+ fmt = self.parse_fmt(a['input_format'])
+ ofmt = self.parse_fmt(a['output_format'])
+ size = Size(max(fmt['width'], ofmt['width']), max(fmt['height'], ofmt['height']))
- 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')
+ prefix = 'time_avg_stats_'
+ if prefix + 'stdev' in a and a[prefix + 'avg']:
+ stdev = (a[prefix + 'stdev'] * 1e3 / a[prefix + 'avg'] ** 2)
+ data = ((device, build, codec, size, a[prefix + 'num'], stdev) +
+ tuple(rateFn(a.get(prefix + i)) for i in points))
+ self.data.add(data)
+ self.kind[codec] = (mime, 'decode_to' not in a, codec.lower().startswith('omx.google.'))
+ self.devices.add(data[0])
+ except (KeyError, ZeroDivisionError):
+ print >> sys.stderr, a
+ raise
- 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:
+ def parse_json(self, json, device, build):
+ for test, results in json:
+ if test in ("video_encoder_performance", "video_decoder_performance"):
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 isinstance(results, list) and len(results[0]) and len(results[0][0]) == 2 and len(results[0][0][0]):
+ for result in results:
+ self.parse_perf(result, device, build)
+ else:
+ self.parse_perf(results, device, build)
+ except KeyboardInterrupt:
+ raise
-if __name__ == '__main__':
- Main().run()
+ def parse_result(self, result):
+ device, build = '', ''
+ if not result.endswith('.zip'):
+ print >> sys.stderr, "cannot parse %s" % result
+ return
+ try:
+ with zipfile.ZipFile(result) as zip:
+ resultInfo, testInfos = None, []
+ for info in zip.infolist():
+ if re.search(r'/GenericDeviceInfo.deviceinfo.json$', info.filename):
+ resultInfo = info
+ elif re.search(r'/Cts(Media|Video)TestCases\.reportlog\.json$', info.filename):
+ testInfos.append(info)
+ if resultInfo:
+ try:
+ jsonFile = zip.open(resultInfo)
+ jsonData = json.load(jsonFile, encoding='utf-8')
+ device, build = jsonData['build_device'], jsonData['build_id']
+ except ValueError:
+ print >> sys.stderr, "could not parse %s" % resultInfo.filename
+ for info in testInfos:
+ jsonFile = zip.open(info)
+ try:
+ jsonData = json.load(jsonFile, encoding='utf-8', object_pairs_hook=lambda items: items)
+ except ValueError:
+ print >> sys.stderr, "cannot parse JSON in %s" % info.filename
+ self.parse_json(jsonData, device, build)
+
+ except zipfile.BadZipfile:
+ raise ValueError('bad zipfile')
+
+
+P = argparse.ArgumentParser("gar_v2")
+P.add_argument("--dbg", "-v", action='store_true', help="dump debug info into xml")
+P.add_argument("--ignore", "-I", action='store_true', help="ignore minimum sample count")
+P.add_argument("result_zip", nargs="*")
+A = P.parse_args()
+
+D = Data()
+for res in A.result_zip:
+ D.parse_result(res)
+D.summarize(A=A)
diff --git a/tools/cts-native-scanner/tests/Android.mk b/tools/cts-native-scanner/tests/Android.mk
index 29c5514..562f0b9 100644
--- a/tools/cts-native-scanner/tests/Android.mk
+++ b/tools/cts-native-scanner/tests/Android.mk
@@ -21,7 +21,7 @@
LOCAL_MODULE := cts-native-scanner-tests
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-native-scanner
+LOCAL_JAVA_LIBRARIES := tradefed cts-native-scanner
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-native-scanner/tests/run_unit_tests.sh b/tools/cts-native-scanner/tests/run_unit_tests.sh
index a42e42b..e85fa7a 100755
--- a/tools/cts-native-scanner/tests/run_unit_tests.sh
+++ b/tools/cts-native-scanner/tests/run_unit_tests.sh
@@ -24,7 +24,7 @@
}
JAR_DIR=${ANDROID_HOST_OUT}/framework
-JARS="ddmlib-prebuilt.jar tradefed-prebuilt.jar hosttestlib.jar cts-native-scanner.jar cts-native-scanner-tests.jar"
+JARS="ddmlib-prebuilt.jar tradefed.jar hosttestlib.jar cts-native-scanner.jar cts-native-scanner-tests.jar"
for JAR in $JARS; do
checkFile ${JAR_DIR}/${JAR}
diff --git a/tools/cts-tradefed/etc/cts-tradefed b/tools/cts-tradefed/etc/cts-tradefed
index f09b581..16a9e5f 100755
--- a/tools/cts-tradefed/etc/cts-tradefed
+++ b/tools/cts-tradefed/etc/cts-tradefed
@@ -80,7 +80,7 @@
fi;
JAR_DIR=${CTS_ROOT}/android-cts/tools
-JARS="tradefed-prebuilt
+JARS="tradefed
hosttestlib
compatibility-host-util
compatibility-host-util-tests
diff --git a/tools/cts-tradefed/res/config/cts-presubmit.xml b/tools/cts-tradefed/res/config/cts-presubmit.xml
new file mode 100644
index 0000000..3f721f1
--- /dev/null
+++ b/tools/cts-tradefed/res/config/cts-presubmit.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT 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 presubmit test cases">
+
+ <include name="cts-automated" />
+
+ <option name="plan" value="cts" />
+
+ <!-- Include modules with presubmit test cases. -->
+ <option name="compatibility:include-filter" value="CtsAccountManagerTestCases" />
+
+ <!-- Only run tests with @Presubmit annotation. -->
+ <option name="compatibility:test-arg" value="com.android.compatibility.common.tradefed.testtype.JarHostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.AndroidJUnitTest:include-annotation:android.platform.test.annotations.Presubmit" />
+ <option name="compatibility:test-arg" value="com.android.tradefed.testtype.HostTest:include-annotation:android.platform.test.annotations.Presubmit" />
+
+</configuration>
diff --git a/tools/cts-tradefed/tests/Android.mk b/tools/cts-tradefed/tests/Android.mk
index 280cdfb..2a391c0 100644
--- a/tools/cts-tradefed/tests/Android.mk
+++ b/tools/cts-tradefed/tests/Android.mk
@@ -20,6 +20,8 @@
LOCAL_MODULE := cts-tradefed-tests
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt cts-tradefed
+LOCAL_JAVA_LIBRARIES := tradefed cts-tradefed
+# We ship the Deqp Runner tests with the CTS one to validate them.
+LOCAL_STATIC_JAVA_LIBRARIES := CtsDeqpRunnerTests
-include $(BUILD_HOST_JAVA_LIBRARY)
\ No newline at end of file
+include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/cts-xml-generator/src/Android.mk b/tools/cts-xml-generator/src/Android.mk
index ea81763..9e5e646 100644
--- a/tools/cts-xml-generator/src/Android.mk
+++ b/tools/cts-xml-generator/src/Android.mk
@@ -25,7 +25,7 @@
LOCAL_MODULE := cts-xml-generator
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := tradefed
LOCAL_STATIC_JAVA_LIBRARIES := vogarexpectlib compatibility-host-util
diff --git a/tools/selinux/SELinuxNeverallowTestFrame.py b/tools/selinux/SELinuxNeverallowTestFrame.py
index f1219c1..51ecc2c 100644
--- a/tools/selinux/SELinuxNeverallowTestFrame.py
+++ b/tools/selinux/SELinuxNeverallowTestFrame.py
@@ -18,7 +18,7 @@
package android.cts.security;
-import com.android.cts.migration.MigrationHelper;
+import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
import com.android.tradefed.build.IBuildInfo;
import com.android.tradefed.device.ITestDevice;
import com.android.tradefed.testtype.DeviceTestCase;
@@ -63,7 +63,8 @@
@Override
protected void setUp() throws Exception {
super.setUp();
- sepolicyAnalyze = MigrationHelper.getTestFile(mBuild, "sepolicy-analyze");
+ CompatibilityBuildHelper buildHelper = new CompatibilityBuildHelper(mBuild);
+ sepolicyAnalyze = buildHelper.getTestFile("sepolicy-analyze");
sepolicyAnalyze.setExecutable(true);
/* obtain sepolicy file from running device */
diff --git a/tools/utils/Android.mk b/tools/utils/Android.mk
index 92bc420..6b01e57 100644
--- a/tools/utils/Android.mk
+++ b/tools/utils/Android.mk
@@ -24,7 +24,7 @@
LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
-LOCAL_JAVA_LIBRARIES := junit tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := junit-host tradefed
LOCAL_STATIC_JAVA_LIBRARIES := compatibility-host-util vogarexpectlib
include $(BUILD_HOST_JAVA_LIBRARY)
diff --git a/tools/vm-tests-tf/Android.mk b/tools/vm-tests-tf/Android.mk
index 4a4e7ae..4935b5e 100644
--- a/tools/vm-tests-tf/Android.mk
+++ b/tools/vm-tests-tf/Android.mk
@@ -44,7 +44,7 @@
LOCAL_MODULE_CLASS := JAVA_LIBRARIES
LOCAL_MODULE_TAGS := optional
-LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit jsr305lib
+LOCAL_JAVA_LIBRARIES := dx dasm cfassembler junit-host jsr305lib
LOCAL_CLASSPATH := $(HOST_JDK_TOOLS_JAR)
@@ -70,7 +70,7 @@
include $(BUILD_SYSTEM)/base_rules.mk
-vmteststf_dep_jars := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, cts-tf-dalvik-buildutil.jar dasm.jar dx.jar cfassembler.jar junit.jar)
+vmteststf_dep_jars := $(addprefix $(HOST_OUT_JAVA_LIBRARIES)/, cts-tf-dalvik-buildutil.jar dasm.jar dx.jar cfassembler.jar junit-host.jar)
$(LOCAL_BUILT_MODULE): PRIVATE_JACK_EXTRA_ARGS := $(LOCAL_JACK_EXTRA_ARGS)
@@ -86,8 +86,8 @@
$(LOCAL_BUILT_MODULE): PRIVATE_JACK_VERSION := $(LOCAL_JACK_VERSION)
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
-$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar
-$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed-prebuilt.jar | setup-jack-server
+$(LOCAL_BUILT_MODULE): PRIVATE_DALVIK_SUITE_CLASSPATH := $(oj_jack):$(libart_jack):$(cts-tf-dalvik-lib.jack):$(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar
+$(LOCAL_BUILT_MODULE) : $(vmteststf_dep_jars) $(JACK) $(oj_jack) $(libart_jack) $(HOST_OUT_JAVA_LIBRARIES)/tradefed.jar | setup-jack-server
$(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
diff --git a/tools/vm-tests-tf/targetprep/Android.mk b/tools/vm-tests-tf/targetprep/Android.mk
index 8abde93..a05b658 100644
--- a/tools/vm-tests-tf/targetprep/Android.mk
+++ b/tools/vm-tests-tf/targetprep/Android.mk
@@ -18,7 +18,7 @@
LOCAL_SRC_FILES := $(call all-java-files-under, src)
-LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed-prebuilt
+LOCAL_JAVA_LIBRARIES := compatibility-host-util cts-tradefed tradefed
LOCAL_MODULE_TAGS := optional