Merge "Fix for Visualizer CTS test: Wait for media to start playing" into lmp-mr1-dev
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 563a65e..13d6dc3 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.android.cts.verifier"
android:versionCode="5"
- android:versionName="5.0_r1.93">
+ android:versionName="5.0_r1.94">
<uses-sdk android:minSdkVersion="19" android:targetSdkVersion="21"/>
@@ -242,8 +242,8 @@
<service android:name=".bluetooth.BleScannerService"
android:label="@string/ble_scanner_service_name" />
- <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
- <!-- activity android:name=".bluetooth.BleClientTestActivity"
+ <!-- Uncomment until b/15657182, b/18283088 fixed
+ <activity android:name=".bluetooth.BleClientStartActivity"
android:label="@string/ble_client_test_name"
android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
@@ -254,98 +254,9 @@
<meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
<meta-data android:name="test_required_features"
android:value="android.hardware.bluetooth_le"/>
- </activity -->
-
- <activity android:name=".bluetooth.BleClientConnectActivity"
- android:label="@string/ble_client_connect_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
</activity>
- <activity android:name=".bluetooth.BleDiscoverServiceActivity"
- android:label="@string/ble_discover_service_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleClientCharacteristicActivity"
- android:label="@string/ble_client_characteristic_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleNotifyCharacteristicActivity"
- android:label="@string/ble_notify_characteristic_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleClientDescriptorActivity"
- android:label="@string/ble_client_descriptor_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleReliableWriteActivity"
- android:label="@string/ble_reliable_write_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleReadRssiActivity"
- android:label="@string/ble_read_rssi_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <activity android:name=".bluetooth.BleClientDisconnectActivity"
- android:label="@string/ble_client_disconnect_name"
- android:configChanges="keyboardHidden|orientation|screenSize">
- <intent-filter>
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.cts.intent.category.MANUAL_TEST" />
- </intent-filter>
- <meta-data android:name="test_category" android:value="@string/bt_le" />
- <meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BleClientTestActivity" />
- </activity>
-
- <!-- TODO: Enable when test quality issues listed in b/18283088 is resolved -->
- <!-- activity android:name=".bluetooth.BleServerStartActivity"
+ <activity android:name=".bluetooth.BleServerStartActivity"
android:label="@string/ble_server_start_name"
android:configChanges="keyboardHidden|orientation|screenSize">
<intent-filter>
@@ -356,7 +267,7 @@
<meta-data android:name="test_parent" android:value="com.android.cts.verifier.bluetooth.BluetoothTestActivity" />
<meta-data android:name="test_required_features"
android:value="android.hardware.bluetooth_le"/>
- </activity -->
+ </activity> -->
<!-- TODO: Enable when test quality issues listed in b/18282549 is resolved -->
<!-- activity android:name=".bluetooth.BleScannerTestActivity"
@@ -1120,6 +1031,8 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.watch" />
</activity>
<activity android:name=".notifications.PackagePriorityVerifierActivity"
@@ -1129,6 +1042,8 @@
<category android:name="android.cts.intent.category.MANUAL_TEST" />
</intent-filter>
<meta-data android:name="test_category" android:value="@string/test_category_notifications" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.hardware.type.watch" />
</activity>
<service android:name=".notifications.MockListener"
@@ -1235,6 +1150,8 @@
<meta-data android:name="test_category" android:value="@string/test_category_other" />
<meta-data android:name="test_required_features"
android:value="android.software.app_widgets" />
+ <meta-data android:name="test_excluded_features"
+ android:value="android.software.leanback" />
</activity>
<activity android:name=".deskclock.DeskClockTestsActivity"
diff --git a/apps/CtsVerifier/res/layout/ble_client_connect.xml b/apps/CtsVerifier/res/layout/ble_client_connect.xml
deleted file mode 100644
index 30b4edb..0000000
--- a/apps/CtsVerifier/res/layout/ble_client_connect.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dip"
- >
-
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- >
- <Button android:id="@+id/ble_scan_start"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ble_scan_start"/>
- <Button android:id="@+id/ble_scan_stop"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ble_scan_stop"/>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"
- />
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_client_read_write.xml b/apps/CtsVerifier/res/layout/ble_client_read_write.xml
deleted file mode 100644
index a263916..0000000
--- a/apps/CtsVerifier/res/layout/ble_client_read_write.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dip"
- >
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- >
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <EditText android:id="@+id/write_text"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:text="@string/ble_test_text"
- android:hint="@string/ble_write_hint"
- android:padding="10dip"
- />
- <Button android:id="@+id/ble_write"
- android:layout_height="wrap_content"
- android:layout_width="wrap_content"
- android:text="@string/ble_write"
- />
- </LinearLayout>
-
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <TextView android:id="@+id/read_text"
- android:layout_width="0dp"
- android:layout_weight="1"
- android:layout_height="wrap_content"
- android:hint="@string/ble_read_hint"
- android:padding="10dip"
- android:textSize="18sp"
- />
- <Button android:id="@+id/ble_read"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/ble_read"
- />
- </LinearLayout>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"
- />
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_client_test.xml b/apps/CtsVerifier/res/layout/ble_client_start.xml
similarity index 79%
rename from apps/CtsVerifier/res/layout/ble_client_test.xml
rename to apps/CtsVerifier/res/layout/ble_client_start.xml
index 660abd5..c377ca1 100644
--- a/apps/CtsVerifier/res/layout/ble_client_test.xml
+++ b/apps/CtsVerifier/res/layout/ble_client_start.xml
@@ -19,15 +19,17 @@
android:orientation="vertical"
android:padding="10dip"
>
- <ListView android:id="@+id/ble_client_tests"
- android:layout_height="fill_parent"
+ <include android:id="@+id/pass_fail_buttons"
android:layout_width="match_parent"
- android:padding="10dip"
- />
-
- <include android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
layout="@layout/pass_fail_buttons"
/>
-</RelativeLayout>
\ No newline at end of file
+ <ListView android:id="@+id/ble_server_tests"
+ android:layout_height="wrap_content"
+ android:layout_width="match_parent"
+ android:layout_above="@id/pass_fail_buttons"
+ android:layout_alignParentTop="true"
+ android:padding="10dip"
+ />
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_notify_characteristic.xml b/apps/CtsVerifier/res/layout/ble_notify_characteristic.xml
deleted file mode 100644
index 786918a..0000000
--- a/apps/CtsVerifier/res/layout/ble_notify_characteristic.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dip"
- >
- <RelativeLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- >
- <Button android:id="@+id/ble_notify"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:text="@string/ble_begin_notification"
- android:padding="10dip"
- />
- <TextView android:id="@+id/ble_notify_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/ble_notify"
- android:textSize="20sp"
- android:padding="10dip"
- />
- </RelativeLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"
- />
-</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/ble_read_rssi.xml b/apps/CtsVerifier/res/layout/ble_read_rssi.xml
deleted file mode 100644
index 8aa3193..0000000
--- a/apps/CtsVerifier/res/layout/ble_read_rssi.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dip"
- >
- <RelativeLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- >
- <Button android:id="@+id/ble_read_rssi"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:text="@string/ble_read_rssi"
- android:padding="10dip"
- />
- <TextView android:id="@+id/ble_rssi_text"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_below="@id/ble_read_rssi"
- android:textSize="20sp"
- android:padding="10dip"
- />
- </RelativeLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"
- />
-</RelativeLayout>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/layout/ble_reliable_write.xml b/apps/CtsVerifier/res/layout/ble_reliable_write.xml
deleted file mode 100644
index 05b1812..0000000
--- a/apps/CtsVerifier/res/layout/ble_reliable_write.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2013 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- android:padding="10dip"
- >
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_centerInParent="true"
- >
- <EditText android:id="@+id/write_text"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:text="@string/ble_test_text"
- android:hint="@string/ble_write_hint"
- android:padding="5dip"
- />
- <LinearLayout android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- >
- <Button android:id="@+id/ble_begin"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/ble_begin_write"
- />
- <Button android:id="@+id/ble_write"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/ble_write"
- />
- <Button android:id="@+id/ble_execute"
- android:layout_width="0dp"
- android:layout_height="wrap_content"
- android:layout_weight="1"
- android:text="@string/ble_execute_write"
- />
- </LinearLayout>
- </LinearLayout>
-
- <include android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- layout="@layout/pass_fail_buttons"
- />
-</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_server_start.xml b/apps/CtsVerifier/res/layout/ble_server_start.xml
index 9ce714d..c377ca1 100644
--- a/apps/CtsVerifier/res/layout/ble_server_start.xml
+++ b/apps/CtsVerifier/res/layout/ble_server_start.xml
@@ -19,7 +19,7 @@
android:orientation="vertical"
android:padding="10dip"
>
- <include android:id="@+id/pass_fail_buttons"
+ <include android:id="@+id/pass_fail_buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
@@ -32,4 +32,4 @@
android:layout_alignParentTop="true"
android:padding="10dip"
/>
-</RelativeLayout>
\ No newline at end of file
+</RelativeLayout>
diff --git a/apps/CtsVerifier/res/layout/ble_server_start_item.xml b/apps/CtsVerifier/res/layout/ble_test_item.xml
similarity index 100%
rename from apps/CtsVerifier/res/layout/ble_server_start_item.xml
rename to apps/CtsVerifier/res/layout/ble_test_item.xml
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index e8cc499..b1ee418 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -188,14 +188,16 @@
<!-- BLE client side strings -->
<string name="ble_client_service_name">Bluetooth LE GATT Client Handler Service</string>
<string name="ble_client_test_name">BLE Client Test</string>
- <string name="ble_client_connect_name">1. BLE Client Connect</string>
- <string name="ble_discover_service_name">2. BLE Discover Service</string>
- <string name="ble_client_characteristic_name">3. BLE Read/Write Characteristic</string>
- <string name="ble_reliable_write_name">4. BLE Reliable Write</string>
- <string name="ble_notify_characteristic_name">5. BLE Notify Characteristic</string>
- <string name="ble_client_descriptor_name">6. BLE Read/Write Descriptor</string>
- <string name="ble_read_rssi_name">7. BLE Read RSSI</string>
- <string name="ble_client_disconnect_name">8. BLE Client Disconnect</string>
+ <string name="ble_client_connect_name">BLE Client Connect</string>
+ <string name="ble_discover_service_name">BLE Discover Service</string>
+ <string name="ble_read_characteristic_name">BLE Read Characteristic</string>
+ <string name="ble_write_characteristic_name">BLE Write Characteristic</string>
+ <string name="ble_reliable_write_name">BLE Reliable Write</string>
+ <string name="ble_notify_characteristic_name">BLE Notify Characteristic</string>
+ <string name="ble_read_descriptor_name">BLE Read Descriptor</string>
+ <string name="ble_write_descriptor_name">BLE Write Descriptor</string>
+ <string name="ble_read_rssi_name">BLE Read RSSI</string>
+ <string name="ble_client_disconnect_name">BLE Client Disconnect</string>
<string name="ble_client_test_info">The BLE test must be done simultaneously on two devices. This device is the client. All tests listed here must be done in order.</string>
<string name="ble_client_send_connect_info">Type in the Bluetooth address of the remote device to connect to, and verify that the devices are connected.</string>
<string name="ble_discover_service_info">Verify that the service is discovered when you press the "Discover Service" button.</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientCharacteristicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientCharacteristicActivity.java
deleted file mode 100644
index 1e1941f..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientCharacteristicActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-public class BleClientCharacteristicActivity extends BleReadWriteActivity {
- public BleClientCharacteristicActivity() {
- super(BleReadWriteActivity.CHARACTERISTIC);
- }
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
deleted file mode 100755
index 4e1c268..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientConnectActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-public class BleClientConnectActivity extends PassFailButtons.Activity {
-
- private EditText mEditText;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_client_connect);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.ble_client_connect_name,
- R.string.ble_client_send_connect_info, -1);
- getPassButton().setEnabled(false);
-
- ((Button) findViewById(R.id.ble_scan_start)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleClientConnectActivity.this,
- BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_SCAN_START);
- startService(intent);
- }
- });
-
- ((Button) findViewById(R.id.ble_scan_stop)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleClientConnectActivity.this,
- BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_SCAN_STOP);
- startService(intent);
- }
- });
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED);
- registerReceiver(onBroadcast, filter);
- }
-
- @Override
- protected void onDestroy(){
- super.onDestroy();
- unregisterReceiver(onBroadcast);
- }
-
- private void showMessage(String msg) {
- Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
- }
-
- private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- showMessage("Bluetooth LE connected");
- getPassButton().setEnabled(true);
- }
- };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDescriptorActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDescriptorActivity.java
deleted file mode 100644
index ab2229a..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDescriptorActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-public class BleClientDescriptorActivity extends BleReadWriteActivity {
- public BleClientDescriptorActivity() {
- super(BleReadWriteActivity.DESCRIPTOR);
- }
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDisconnectActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDisconnectActivity.java
deleted file mode 100644
index 083d327..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientDisconnectActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-public class BleClientDisconnectActivity extends BleButtonActivity {
- public BleClientDisconnectActivity() {
- super(BleButtonActivity.DISCONNECT);
- }
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
index 6765362..10f862d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -96,6 +96,8 @@
"com.android.cts.verifier.bluetooth.EXTRA_DESCRIPTOR_VALUE";
public static final String EXTRA_RSSI_VALUE =
"com.android.cts.verifier.bluetooth.EXTRA_RSSI_VALUE";
+ public static final String EXTRA_ERROR_MESSAGE =
+ "com.android.cts.verifier.bluetooth.EXTRA_ERROR_MESSAGE";
private static final UUID SERVICE_UUID =
UUID.fromString("00009999-0000-1000-8000-00805f9b34fb");
@@ -106,13 +108,15 @@
private static final UUID DESCRIPTOR_UUID =
UUID.fromString("00009996-0000-1000-8000-00805f9b34fb");
+ private static final String WRITE_VALUE = "TEST";
+
private BluetoothManager mBluetoothManager;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothDevice mDevice;
private BluetoothGatt mBluetoothGatt;
+ private BluetoothLeScanner mScanner;
private Handler mHandler;
private Context mContext;
- private BluetoothLeScanner mScanner;
@Override
public void onCreate() {
@@ -120,14 +124,14 @@
mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = mBluetoothManager.getAdapter();
+ mScanner = mBluetoothAdapter.getBluetoothLeScanner();
mHandler = new Handler();
mContext = this;
- mScanner = mBluetoothAdapter.getBluetoothLeScanner();
+ startScan();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
- if (intent != null) handleIntent(intent);
return START_NOT_STICKY;
}
@@ -141,68 +145,10 @@
super.onDestroy();
mBluetoothGatt.disconnect();
mBluetoothGatt.close();
+ mBluetoothGatt = null;
stopScan();
}
- private void handleIntent(Intent intent) {
- int command = intent.getIntExtra(EXTRA_COMMAND, -1);
- String address = intent.getStringExtra(BluetoothDevice.EXTRA_DEVICE); // sometimes null
- String writeValue = intent.getStringExtra(EXTRA_WRITE_VALUE); // sometimes null
- boolean enable = intent.getBooleanExtra(EXTRA_BOOL, false);
- BluetoothGattService service;
- BluetoothGattCharacteristic characteristic;
- BluetoothGattDescriptor descriptor;
-
- switch (command) {
- case COMMAND_CONNECT:
- mDevice = mBluetoothAdapter.getRemoteDevice(address);
- mBluetoothGatt = mDevice.connectGatt(this, false, mGattCallbacks);
- break;
- case COMMAND_DISCONNECT:
- if (mBluetoothGatt != null) mBluetoothGatt.disconnect();
- break;
- case COMMAND_DISCOVER_SERVICE:
- if (mBluetoothGatt != null) mBluetoothGatt.discoverServices();
- break;
- case COMMAND_READ_RSSI:
- if (mBluetoothGatt != null) mBluetoothGatt.readRemoteRssi();
- break;
- case COMMAND_WRITE_CHARACTERISTIC:
- writeCharacteristic(writeValue);
- break;
- case COMMAND_READ_CHARACTERISTIC:
- readCharacteristic();
- break;
- case COMMAND_WRITE_DESCRIPTOR:
- writeDescriptor(writeValue);
- break;
- case COMMAND_READ_DESCRIPTOR:
- readDescriptor();
- break;
- case COMMAND_SET_NOTIFICATION:
- setNotification(enable);
- break;
- case COMMAND_BEGIN_WRITE:
- if (mBluetoothGatt != null) mBluetoothGatt.beginReliableWrite();
- break;
- case COMMAND_EXECUTE_WRITE:
- if (mBluetoothGatt != null) mBluetoothGatt.executeReliableWrite();
- break;
- case COMMAND_ABORT_RELIABLE:
- if (mBluetoothGatt != null) mBluetoothGatt.abortReliableWrite(mDevice);
- break;
- case COMMAND_SCAN_START:
- startScan();
- break;
- case COMMAND_SCAN_STOP:
- stopScan();
- break;
- default:
- showMessage("Unrecognized command: " + command);
- break;
- }
- }
-
private void writeCharacteristic(String writeValue) {
BluetoothGattCharacteristic characteristic = getCharacteristic(CHARACTERISTIC_UUID);
if (characteristic == null) return;
@@ -233,55 +179,69 @@
mBluetoothGatt.setCharacteristicNotification(characteristic, enable);
}
+ private void notifyError(String message) {
+ showMessage(message);
+ }
+
private void notifyConnected() {
+ showMessage("BLE connected");
Intent intent = new Intent(BLE_BLUETOOTH_CONNECTED);
sendBroadcast(intent);
}
private void notifyDisconnected() {
+ showMessage("BLE disconnected");
Intent intent = new Intent(BLE_BLUETOOTH_DISCONNECTED);
sendBroadcast(intent);
}
private void notifyServicesDiscovered() {
+ showMessage("Service discovered");
Intent intent = new Intent(BLE_SERVICES_DISCOVERED);
sendBroadcast(intent);
}
private void notifyCharacteristicRead(String value) {
+ showMessage("Characteristic read: " + value);
Intent intent = new Intent(BLE_CHARACTERISTIC_READ);
intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value);
sendBroadcast(intent);
}
- private void notifyCharacteristicWrite() {
+ private void notifyCharacteristicWrite(String value) {
+ showMessage("Characteristic write: " + value);
Intent intent = new Intent(BLE_CHARACTERISTIC_WRITE);
sendBroadcast(intent);
}
private void notifyCharacteristicChanged(String value) {
+ showMessage("Characteristic changed: " + value);
Intent intent = new Intent(BLE_CHARACTERISTIC_CHANGED);
intent.putExtra(EXTRA_CHARACTERISTIC_VALUE, value);
sendBroadcast(intent);
}
private void notifyDescriptorRead(String value) {
+ showMessage("Descriptor read: " + value);
Intent intent = new Intent(BLE_DESCRIPTOR_READ);
intent.putExtra(EXTRA_DESCRIPTOR_VALUE, value);
sendBroadcast(intent);
}
- private void notifyDescriptorWrite() {
+ private void notifyDescriptorWrite(String value) {
+ showMessage("Descriptor write: " + value);
Intent intent = new Intent(BLE_DESCRIPTOR_WRITE);
sendBroadcast(intent);
}
private void notifyReliableWriteCompleted() {
+ showMessage("Reliable write compelte");
Intent intent = new Intent(BLE_RELIABLE_WRITE_COMPLETED);
sendBroadcast(intent);
}
private void notifyReadRemoteRssi(int rssi) {
+ showMessage("Remote rssi read: " + rssi);
Intent intent = new Intent(BLE_READ_REMOTE_RSSI);
intent.putExtra(EXTRA_RSSI_VALUE, rssi);
sendBroadcast(intent);
@@ -330,88 +290,159 @@
});
}
+ private void sleep(int millis) {
+ try {
+ Thread.sleep(millis);
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Error in thread sleep", e);
+ }
+ }
+
+ private void reliableWrite() {
+ mBluetoothGatt.beginReliableWrite();
+ sleep(1000);
+ writeCharacteristic(WRITE_VALUE);
+ sleep(1000);
+ if (!mBluetoothGatt.executeReliableWrite()) {
+ Log.w(TAG, "reliable write failed");
+ }
+ sleep(1000);
+ mBluetoothGatt.abortReliableWrite();
+ }
+
private final BluetoothGattCallback mGattCallbacks = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (DEBUG) Log.d(TAG, "onConnectionStateChange");
if (status == BluetoothGatt.GATT_SUCCESS) {
- if (newState == BluetoothProfile.STATE_CONNECTED) notifyConnected();
- else if (status == BluetoothProfile.STATE_DISCONNECTED) {
+ if (newState == BluetoothProfile.STATE_CONNECTED) {
+ notifyConnected();
+ stopScan();
+ sleep(1000);
+ mBluetoothGatt.discoverServices();
+ } else if (status == BluetoothProfile.STATE_DISCONNECTED) {
notifyDisconnected();
- showMessage("Bluetooth LE disconnected");
}
+ } else {
+ showMessage("Failed to connect");
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
+ if (DEBUG) Log.d(TAG, "onServiceDiscovered");
if ((status == BluetoothGatt.GATT_SUCCESS) &&
(mBluetoothGatt.getService(SERVICE_UUID) != null)) {
notifyServicesDiscovered();
- }
- }
-
- @Override
- public void onCharacteristicRead(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic, int status) {
- if ((status == BluetoothGatt.GATT_SUCCESS) &&
- (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) {
- notifyCharacteristicRead(characteristic.getStringValue(0));
+ sleep(1000);
+ writeCharacteristic(WRITE_VALUE);
}
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
+ String value = characteristic.getStringValue(0);
if (DEBUG) Log.d(TAG, "onCharacteristicWrite: characteristic.val="
- + characteristic.getStringValue(0) + " status=" + status);
+ + value + " status=" + status);
BluetoothGattCharacteristic mCharacteristic = getCharacteristic(CHARACTERISTIC_UUID);
if ((status == BluetoothGatt.GATT_SUCCESS) &&
- (characteristic.getStringValue(0).equals(mCharacteristic.getStringValue(0)))) {
- notifyCharacteristicWrite();
+ (value.equals(mCharacteristic.getStringValue(0)))) {
+ notifyCharacteristicWrite(value);
+ sleep(1000);
+ readCharacteristic();
+ } else {
+ notifyError("Failed to write characteristic: " + value);
}
}
@Override
- public void onCharacteristicChanged(BluetoothGatt gatt,
- BluetoothGattCharacteristic characteristic) {
- if (characteristic.getUuid().equals(UPDATE_CHARACTERISTIC_UUID))
- notifyCharacteristicChanged(characteristic.getStringValue(0));
- }
-
- @Override
- public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
- int status) {
+ public void onCharacteristicRead(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic, int status) {
+ if (DEBUG) Log.d(TAG, "onCharacteristicRead");
if ((status == BluetoothGatt.GATT_SUCCESS) &&
- (descriptor.getUuid().equals(DESCRIPTOR_UUID))) {
- notifyDescriptorRead(new String(descriptor.getValue()));
+ (characteristic.getUuid().equals(CHARACTERISTIC_UUID))) {
+ notifyCharacteristicRead(characteristic.getStringValue(0));
+ sleep(1000);
+ writeDescriptor(WRITE_VALUE);
+ } else {
+ notifyError("Failed to read characteristic");
}
}
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
int status) {
+ if (DEBUG) Log.d(TAG, "onDescriptorWrite");
if ((status == BluetoothGatt.GATT_SUCCESS) &&
(descriptor.getUuid().equals(DESCRIPTOR_UUID))) {
- notifyDescriptorWrite();
+ notifyDescriptorWrite(new String(descriptor.getValue()));
+ sleep(1000);
+ readDescriptor();
+ } else {
+ notifyError("Failed to write descriptor");
+ }
+ }
+
+ @Override
+ public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor,
+ int status) {
+ if (DEBUG) Log.d(TAG, "onDescriptorRead");
+ if ((status == BluetoothGatt.GATT_SUCCESS) &&
+ (descriptor.getUuid() != null) &&
+ (descriptor.getUuid().equals(DESCRIPTOR_UUID))) {
+ notifyDescriptorRead(new String(descriptor.getValue()));
+ sleep(1000);
+ setNotification(true);
+ } else {
+ notifyError("Failed to read descriptor");
+ }
+ }
+
+ @Override
+ public void onCharacteristicChanged(BluetoothGatt gatt,
+ BluetoothGattCharacteristic characteristic) {
+ if (DEBUG) Log.d(TAG, "onCharacteristicChanged");
+ if ((characteristic.getUuid() != null) &&
+ (characteristic.getUuid().equals(UPDATE_CHARACTERISTIC_UUID))) {
+ notifyCharacteristicChanged(characteristic.getStringValue(0));
+ setNotification(false);
+ sleep(1000);
+ mBluetoothGatt.readRemoteRssi();
}
}
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
- if (status == BluetoothGatt.GATT_SUCCESS) notifyReliableWriteCompleted();
+ if (DEBUG) Log.d(TAG, "onReliableWriteComplete: " + status);
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ notifyReliableWriteCompleted();
+ } else {
+ notifyError("Failed to complete reliable write: " + status);
+ }
+ sleep(1000);
+ mBluetoothGatt.disconnect();
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
- if (status == BluetoothGatt.GATT_SUCCESS) notifyReadRemoteRssi(rssi);
+ if (DEBUG) Log.d(TAG, "onReadRemoteRssi");
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ notifyReadRemoteRssi(rssi);
+ } else {
+ notifyError("Failed to read remote rssi");
+ }
+ sleep(1000);
+ reliableWrite();
}
};
private final ScanCallback mScanCallback = new ScanCallback() {
@Override
public void onScanResult(int callbackType, ScanResult result) {
- mBluetoothGatt = result.getDevice().connectGatt(mContext, false, mGattCallbacks);
+ if (mBluetoothGatt == null) {
+ mBluetoothGatt = result.getDevice().connectGatt(mContext, false, mGattCallbacks);
+ }
}
};
@@ -420,7 +451,7 @@
List<ScanFilter> filter = Arrays.asList(new ScanFilter.Builder().setServiceUuid(
new ParcelUuid(BleServerService.ADV_SERVICE_UUID)).build());
ScanSettings setting = new ScanSettings.Builder()
- .setScanMode(ScanSettings.SCAN_MODE_LOW_POWER).build();
+ .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY).build();
mScanner.startScan(filter, setting, mScanCallback);
}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java
new file mode 100644
index 0000000..5a4e327
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientStartActivity.java
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.bluetooth;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.ImageView;
+import android.widget.ListView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+public class BleClientStartActivity extends PassFailButtons.Activity {
+
+ private TestAdapter mTestAdapter;
+ private int mAllPassed;
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.ble_server_start);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.ble_server_start_name,
+ R.string.ble_server_start_info, -1);
+ getPassButton().setEnabled(false);
+
+ mTestAdapter = new TestAdapter(this, setupTestList());
+ ListView listView = (ListView) findViewById(R.id.ble_server_tests);
+ listView.setAdapter(mTestAdapter);
+
+ mAllPassed = 0;
+ startService(new Intent(this, BleClientService.class));
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ IntentFilter filter = new IntentFilter();
+ filter.addAction(BleClientService.BLE_BLUETOOTH_CONNECTED);
+ filter.addAction(BleClientService.BLE_BLUETOOTH_DISCONNECTED);
+ filter.addAction(BleClientService.BLE_SERVICES_DISCOVERED);
+ filter.addAction(BleClientService.BLE_CHARACTERISTIC_READ);
+ filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE);
+ filter.addAction(BleClientService.BLE_CHARACTERISTIC_CHANGED);
+ filter.addAction(BleClientService.BLE_DESCRIPTOR_READ);
+ filter.addAction(BleClientService.BLE_DESCRIPTOR_WRITE);
+ filter.addAction(BleClientService.BLE_RELIABLE_WRITE_COMPLETED);
+ filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
+ registerReceiver(onBroadcast, filter);
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ unregisterReceiver(onBroadcast);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ stopService(new Intent(this, BleClientService.class));
+ }
+
+ private List<Integer> setupTestList() {
+ ArrayList<Integer> testList = new ArrayList<Integer>();
+ testList.add(R.string.ble_client_connect_name);
+ testList.add(R.string.ble_discover_service_name);
+ testList.add(R.string.ble_read_characteristic_name);
+ testList.add(R.string.ble_write_characteristic_name);
+ testList.add(R.string.ble_reliable_write_name);
+ testList.add(R.string.ble_notify_characteristic_name);
+ testList.add(R.string.ble_read_descriptor_name);
+ testList.add(R.string.ble_write_descriptor_name);
+ testList.add(R.string.ble_read_rssi_name);
+ testList.add(R.string.ble_client_disconnect_name);
+ return testList;
+ }
+
+ private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (action == BleClientService.BLE_BLUETOOTH_CONNECTED) {
+ mTestAdapter.setTestPass(0);
+ mAllPassed |= 0x01;
+ } else if (action == BleClientService.BLE_SERVICES_DISCOVERED) {
+ mTestAdapter.setTestPass(1);
+ mAllPassed |= 0x02;
+ } else if (action == BleClientService.BLE_CHARACTERISTIC_READ) {
+ mTestAdapter.setTestPass(2);
+ mAllPassed |= 0x04;
+ } else if (action == BleClientService.BLE_CHARACTERISTIC_WRITE) {
+ mTestAdapter.setTestPass(3);
+ mAllPassed |= 0x08;
+ } else if (action == BleClientService.BLE_RELIABLE_WRITE_COMPLETED) {
+ mTestAdapter.setTestPass(4);
+ mAllPassed |= 0x10;
+ } else if (action == BleClientService.BLE_CHARACTERISTIC_CHANGED) {
+ mTestAdapter.setTestPass(5);
+ mAllPassed |= 0x20;
+ } else if (action == BleClientService.BLE_DESCRIPTOR_READ) {
+ mTestAdapter.setTestPass(6);
+ mAllPassed |= 0x40;
+ } else if (action == BleClientService.BLE_DESCRIPTOR_WRITE) {
+ mTestAdapter.setTestPass(7);
+ mAllPassed |= 0x80;
+ } else if (action == BleClientService.BLE_READ_REMOTE_RSSI) {
+ mTestAdapter.setTestPass(8);
+ mAllPassed |= 0x100;
+ } else if (action == BleClientService.BLE_BLUETOOTH_DISCONNECTED) {
+ mTestAdapter.setTestPass(9);
+ mAllPassed |= 0x200;
+ }
+ mTestAdapter.notifyDataSetChanged();
+ if (mAllPassed == 0x3FF) getPassButton().setEnabled(true);
+ }
+ };
+
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestActivity.java
deleted file mode 100644
index a13d934..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientTestActivity.java
+++ /dev/null
@@ -1,36 +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.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.ManifestTestListAdapter;
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.os.Bundle;
-
-public class BleClientTestActivity extends PassFailButtons.TestListActivity {
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.pass_fail_list);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.ble_client_test_name, R.string.ble_client_test_info, -1);
-
- setTestListAdapter(new ManifestTestListAdapter(this, getClass().getName()));
- }
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleDiscoverServiceActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleDiscoverServiceActivity.java
deleted file mode 100644
index 6896b04..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleDiscoverServiceActivity.java
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-public class BleDiscoverServiceActivity extends BleButtonActivity {
- public BleDiscoverServiceActivity() {
- super(BleButtonActivity.DISCOVER_SERVICE);
- }
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleNotifyCharacteristicActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleNotifyCharacteristicActivity.java
deleted file mode 100644
index e0c79bf..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleNotifyCharacteristicActivity.java
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class BleNotifyCharacteristicActivity extends PassFailButtons.Activity {
-
- private boolean mEnable;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_notify_characteristic);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.ble_notify_characteristic_name,
- R.string.ble_notify_characteristic_info, -1);
-
- mEnable = false;
-
- ((Button) findViewById(R.id.ble_notify)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- mEnable = !mEnable;
- if (mEnable) ((Button) v).setText(getString(R.string.ble_stop_notification));
- else ((Button) v).setText(getString(R.string.ble_begin_notification));
-
- Intent intent = new Intent(BleNotifyCharacteristicActivity.this,
- BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_SET_NOTIFICATION);
- intent.putExtra(BleClientService.EXTRA_BOOL, mEnable);
- startService(intent);
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- IntentFilter filter = new IntentFilter();
- filter.addAction(BleClientService.BLE_CHARACTERISTIC_CHANGED);
- registerReceiver(onBroadcast, filter);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- unregisterReceiver(onBroadcast);
- mEnable = false;
- Intent intent = new Intent(BleNotifyCharacteristicActivity.this,
- BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_SET_NOTIFICATION);
- intent.putExtra(BleClientService.EXTRA_BOOL, mEnable);
- startService(intent);
- }
-
- private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String value = intent.getStringExtra(BleClientService.EXTRA_CHARACTERISTIC_VALUE);
- ((TextView) findViewById(R.id.ble_notify_text)).setText(value);
- }
- };
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadRssiActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadRssiActivity.java
deleted file mode 100644
index 800499c..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadRssiActivity.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
-
-public class BleReadRssiActivity extends PassFailButtons.Activity {
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_read_rssi);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.ble_read_rssi_name,
- R.string.ble_read_rssi_info, -1);
-
- ((Button) findViewById(R.id.ble_read_rssi)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleReadRssiActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_READ_RSSI);
- startService(intent);
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- IntentFilter filter = new IntentFilter();
- filter.addAction(BleClientService.BLE_READ_REMOTE_RSSI);
- registerReceiver(onBroadcast, filter);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- unregisterReceiver(onBroadcast);
- }
-
- private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- int rssi = intent.getIntExtra(BleClientService.EXTRA_RSSI_VALUE, 128);
- ((TextView) findViewById(R.id.ble_rssi_text)).setText(Integer.toString(rssi));
- }
- };
-}
\ No newline at end of file
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java
deleted file mode 100644
index 8041ce0..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReadWriteActivity.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.TextView;
-import android.widget.Toast;
-
-class BleReadWriteActivity extends PassFailButtons.Activity {
-
- static final int CHARACTERISTIC = 0;
- static final int DESCRIPTOR = 1;
-
- private int mWriteCommand;
- private int mReadCommand;
- private String mWriteFilter;
- private String mReadFilter;
- private String mExtraValue;
- private int mName;
- private EditText mEditText;
-
- BleReadWriteActivity(int target) {
- if (target == CHARACTERISTIC) {
- mWriteCommand = BleClientService.COMMAND_WRITE_CHARACTERISTIC;
- mReadCommand = BleClientService.COMMAND_READ_CHARACTERISTIC;
- mWriteFilter = BleClientService.BLE_CHARACTERISTIC_WRITE;
- mReadFilter = BleClientService.BLE_CHARACTERISTIC_READ;
- mExtraValue = BleClientService.EXTRA_CHARACTERISTIC_VALUE;
- mName = R.string.ble_client_characteristic_name;
- } else if (target == DESCRIPTOR) {
- mWriteCommand = BleClientService.COMMAND_WRITE_DESCRIPTOR;
- mReadCommand = BleClientService.COMMAND_READ_DESCRIPTOR;
- mWriteFilter = BleClientService.BLE_DESCRIPTOR_WRITE;
- mReadFilter = BleClientService.BLE_DESCRIPTOR_READ;
- mExtraValue = BleClientService.EXTRA_DESCRIPTOR_VALUE;
- mName = R.string.ble_client_descriptor_name;
- }
- }
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_client_read_write);
- setPassFailButtonClickListeners();
- setInfoResources(mName, R.string.ble_read_write_info, -1);
-
- mEditText = (EditText) findViewById(R.id.write_text);
-
- ((Button) findViewById(R.id.ble_write)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- String writeValue = mEditText.getText().toString();
- Intent intent = new Intent(BleReadWriteActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND, mWriteCommand);
- intent.putExtra(BleClientService.EXTRA_WRITE_VALUE, writeValue);
- startService(intent);
- mEditText.setText("");
- }
- });
-
- ((Button) findViewById(R.id.ble_read)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleReadWriteActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND, mReadCommand);
- startService(intent);
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- IntentFilter filter = new IntentFilter();
- filter.addAction(mReadFilter);
- filter.addAction(mWriteFilter);
- registerReceiver(onBroadcast, filter);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- unregisterReceiver(onBroadcast);
- }
-
- private void showMessage(String msg) {
- Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
- }
-
- private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == mWriteFilter)
- showMessage("Write successful callback");
- else if (action == mReadFilter) {
- String value = intent.getStringExtra(mExtraValue);
- ((TextView) findViewById(R.id.read_text)).setText(value);
- }
- }
- };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java
deleted file mode 100644
index 9b65bb4..0000000
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleReliableWriteActivity.java
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.verifier.bluetooth;
-
-import com.android.cts.verifier.PassFailButtons;
-import com.android.cts.verifier.R;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.OnClickListener;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.Toast;
-
-public class BleReliableWriteActivity extends PassFailButtons.Activity {
-
- EditText mEditText;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.ble_reliable_write);
- setPassFailButtonClickListeners();
- setInfoResources(R.string.ble_reliable_write_name, R.string.ble_reliable_write_info, -1);
- getPassButton().setEnabled(false);
- ((Button) findViewById(R.id.ble_execute)).setEnabled(false);
-
- mEditText = (EditText) findViewById(R.id.write_text);
-
- ((Button) findViewById(R.id.ble_begin)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleReliableWriteActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_BEGIN_WRITE);
- startService(intent);
- }
- });
-
- ((Button) findViewById(R.id.ble_write)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- String writeValue = mEditText.getText().toString();
- Intent intent = new Intent(BleReliableWriteActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_WRITE_CHARACTERISTIC);
- intent.putExtra(BleClientService.EXTRA_WRITE_VALUE, writeValue);
- startService(intent);
- mEditText.setText("");
- }
- });
-
- ((Button) findViewById(R.id.ble_execute)).setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(BleReliableWriteActivity.this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND,
- BleClientService.COMMAND_EXECUTE_WRITE);
- startService(intent);
- }
- });
- }
-
- @Override
- public void onResume() {
- super.onResume();
- IntentFilter filter = new IntentFilter();
- filter.addAction(BleClientService.BLE_CHARACTERISTIC_WRITE);
- filter.addAction(BleClientService.BLE_RELIABLE_WRITE_COMPLETED);
- registerReceiver(onBroadcast, filter);
- }
-
- @Override
- public void onPause() {
- super.onPause();
- unregisterReceiver(onBroadcast);
- Intent intent = new Intent(this, BleClientService.class);
- intent.putExtra(BleClientService.EXTRA_COMMAND, BleClientService.COMMAND_ABORT_RELIABLE);
- startService(intent);
- }
-
- private void showMessage(String msg) {
- Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
- }
-
- private BroadcastReceiver onBroadcast = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (action == BleClientService.BLE_CHARACTERISTIC_WRITE) {
- showMessage("Write value verified.");
- ((Button) findViewById(R.id.ble_execute)).setEnabled(true);
- } else if (action == BleClientService.BLE_RELIABLE_WRITE_COMPLETED) {
- showMessage("Reliable write completed.");
- getPassButton().setEnabled(true);
- }
- }
- };
-}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java
index 631fe36..8f4ed56 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/TestAdapter.java
@@ -80,7 +80,7 @@
if (convertView != null) {
vg = (ViewGroup) convertView;
} else {
- vg = (ViewGroup) inflater.inflate(R.layout.ble_server_start_item, null);
+ vg = (ViewGroup) inflater.inflate(R.layout.ble_test_item, null);
}
Test test = tests.get(position);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
index c0895d7..105e92b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureSummaryActivity.java
@@ -220,6 +220,9 @@
new Feature(PackageManager.FEATURE_SENSOR_RELATIVE_HUMIDITY, false),
new Feature(PackageManager.FEATURE_VERIFIED_BOOT, false),
+ // Features explicitly made optional in L
+ new Feature("PackageManager.FEATURE_LOCATION_NETWORK", false),
+
// New hidden features in L
new Feature("android.hardware.ethernet", false),
new Feature("android.hardware.hdmi.cec", false),
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
index 18d9d43..77de71d 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/ProjectionActivity.java
@@ -150,6 +150,8 @@
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
Log.i(TAG, "onSurfaceTextureSizeChanged " + surface.toString() + "w: " + width + " h: "
+ height);
+ mWidth = width;
+ mHeight = height;
}
@Override
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
index 5dddf5c..46abaaa 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/projection/list/ListPresentation.java
@@ -50,7 +50,7 @@
setContentView(view);
for (int i = 0; i < NUM_ITEMS; ++i) {
- mItemList.add("Item #" + 1 + i);
+ mItemList.add("Item #" + (1 + i));
}
ListView listView = (ListView) view.findViewById(R.id.pla_list);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
index 1ec5dc1..22ff1e5 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/sensors/MagneticFieldMeasurementTestActivity.java
@@ -21,7 +21,6 @@
import android.hardware.Sensor;
import android.hardware.SensorEvent;
-import android.hardware.SensorEventListener2;
import android.hardware.SensorManager;
import android.hardware.cts.helpers.SensorCalibratedUncalibratedVerifier;
import android.hardware.cts.helpers.SensorCtsHelper;
@@ -166,7 +165,11 @@
* A routine to help operators calibrate the magnetometer.
*/
private void calibrateMagnetometer() throws InterruptedException {
- SensorEventListener2 listener = new SensorEventListener2() {
+ TestSensorEnvironment environment = new TestSensorEnvironment(
+ getApplicationContext(),
+ Sensor.TYPE_MAGNETIC_FIELD,
+ SensorManager.SENSOR_DELAY_NORMAL);
+ TestSensorEventListener listener = new TestSensorEventListener(environment) {
@Override
public void onSensorChanged(SensorEvent event) {
clearText();
@@ -184,21 +187,11 @@
// TODO: automate finding out when the magnetometer is calibrated
logger.logInstructions(R.string.snsr_mag_calibration_complete);
}
-
- @Override
- public void onAccuracyChanged(Sensor sensor, int accuracy) {}
-
- @Override
- public void onFlushCompleted(Sensor sensor) {}
};
- TestSensorEnvironment environment = new TestSensorEnvironment(
- getApplicationContext(),
- Sensor.TYPE_MAGNETIC_FIELD,
- SensorManager.SENSOR_DELAY_NORMAL);
TestSensorManager magnetometer = new TestSensorManager(environment);
try {
- magnetometer.registerListener(new TestSensorEventListener(listener));
+ magnetometer.registerListener(listener);
waitForUserToContinue();
} finally {
magnetometer.unregisterListener();
diff --git a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
index 9dc51c9..4d9ef00 100644
--- a/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
+++ b/hostsidetests/appsecurity/src/com/android/cts/appsecurity/AppSecurityTests.java
@@ -181,7 +181,7 @@
true /* reinstall */, options);
assertNotNull("app upgrade with different cert than existing app installed " +
"successfully", installResult);
- assertEquals("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES", installResult);
+ assertEquals("INSTALL_FAILED_UPDATE_INCOMPATIBLE", installResult);
}
finally {
getDevice().uninstallPackage(SIMPLE_APP_PKG);
diff --git a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
index 18ee963..98610a0 100644
--- a/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
+++ b/hostsidetests/appsecurity/test-apps/DocumentClient/src/com/android/cts/documentclient/DocumentsClientTest.java
@@ -82,6 +82,25 @@
return new UiObject(rootsList.childSelector(new UiSelector().text(label)));
}
+ private UiObject findDocument(String label) throws UiObjectNotFoundException {
+ final UiSelector docList = new UiSelector().resourceId(
+ "com.android.documentsui:id/container_directory").childSelector(
+ new UiSelector().resourceId("com.android.documentsui:id/list"));
+
+ // Wait for the first list item to appear
+ assertTrue("First list item",
+ new UiObject(docList.childSelector(new UiSelector())).waitForExists(TIMEOUT));
+
+ // Now scroll around to find our item
+ new UiScrollable(docList).scrollIntoView(new UiSelector().text(label));
+ return new UiObject(docList.childSelector(new UiSelector().text(label)));
+ }
+
+ private UiObject findSaveButton() throws UiObjectNotFoundException {
+ return new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
+ .childSelector(new UiSelector().resourceId("android:id/button1")));
+ }
+
public void testOpenSimple() throws Exception {
if (!supportedHardware()) return;
@@ -108,7 +127,7 @@
findRoot("CtsLocal").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().text("FILE1")).click();
+ findDocument("FILE1").click();
final Result result = mActivity.getResult();
final Uri uri = result.data.getData();
@@ -137,8 +156,7 @@
findRoot("CtsCreate").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
- .childSelector(new UiSelector().resourceId("android:id/button1"))).click();
+ findSaveButton().click();
final Result result = mActivity.getResult();
final Uri uri = result.data.getData();
@@ -164,13 +182,12 @@
// Pick file2, which should be selected since MIME matches, then try
// picking a non-matching MIME, which should leave file2 selected.
mDevice.waitForIdle();
- new UiObject(new UiSelector().text("FILE2")).click();
+ findDocument("FILE2").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().text("FILE1")).click();
+ findDocument("FILE1").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
- .childSelector(new UiSelector().resourceId("android:id/button1"))).click();
+ findSaveButton().click();
final Result result = mActivity.getResult();
final Uri uri = result.data.getData();
@@ -188,10 +205,9 @@
findRoot("CtsCreate").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().text("DIR2")).click();
+ findDocument("DIR2").click();
mDevice.waitForIdle();
- new UiObject(new UiSelector().resourceId("com.android.documentsui:id/container_save")
- .childSelector(new UiSelector().resourceId("android:id/button1"))).click();
+ findSaveButton().click();
final Result result = mActivity.getResult();
final Uri uri = result.data.getData();
diff --git a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
index 5378266..cf16307 100644
--- a/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
+++ b/hostsidetests/appsecurity/test-apps/UsePermissionDiffCert/src/com/android/cts/usespermissiondiffcertapp/AccessPermissionWithDiffSigTest.java
@@ -429,6 +429,7 @@
boolean mHaveResult = false;
boolean mGoodResult = false;
boolean mSucceeded = false;
+ static final int TIMEOUT_MS = 30000;
@Override
public void onReceive(Context context, Intent intent) {
@@ -456,10 +457,10 @@
final long startTime = SystemClock.uptimeMillis();
while (!mHaveResult) {
try {
- wait(5000);
+ wait(TIMEOUT_MS);
} catch (InterruptedException e) {
}
- if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ if (SystemClock.uptimeMillis() >= (startTime + TIMEOUT_MS)) {
throw new RuntimeException("Timeout");
}
}
@@ -477,10 +478,10 @@
final long startTime = SystemClock.uptimeMillis();
while (!mHaveResult) {
try {
- wait(5000);
+ wait(TIMEOUT_MS);
} catch (InterruptedException e) {
}
- if (SystemClock.uptimeMillis() >= (startTime+5000)) {
+ if (SystemClock.uptimeMillis() >= (startTime + TIMEOUT_MS)) {
throw new RuntimeException("Timeout");
}
}
diff --git a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
index 4668faf..94862e7 100644
--- a/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
+++ b/hostsidetests/dumpsys/src/android/dumpsys/cts/DumpsysHostTest.java
@@ -523,7 +523,7 @@
}
private void checkProcess(String[] parts) {
- assertEquals(9, parts.length);
+ assertTrue(parts.length >= 9);
assertNotNull(parts[4]); // process
assertInteger(parts[5]); // userMillis
assertInteger(parts[6]); // systemMillis
@@ -658,7 +658,7 @@
}
private void checkMisc(String[] parts) {
- assertEquals(20, parts.length);
+ assertTrue(parts.length >= 20);
assertInteger(parts[4]); // screenOnTime
assertInteger(parts[5]); // phoneOnTime
assertInteger(parts[6]); // wifiOnTime
diff --git a/hostsidetests/theme/assets/21/hdpi.zip b/hostsidetests/theme/assets/21/hdpi.zip
index 9cc179c..0fa67b7 100644
--- a/hostsidetests/theme/assets/21/hdpi.zip
+++ b/hostsidetests/theme/assets/21/hdpi.zip
Binary files differ
diff --git a/suite/cts/deviceTests/videoperf/Android.mk b/suite/cts/deviceTests/videoperf/Android.mk
index cd82dde..a393683 100644
--- a/suite/cts/deviceTests/videoperf/Android.mk
+++ b/suite/cts/deviceTests/videoperf/Android.mk
@@ -17,8 +17,15 @@
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
+# and when built explicitly put it in the data partition
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestrunner
+# include both the 32 and 64 bit versions
+LOCAL_MULTILIB := both
+
+LOCAL_STATIC_JAVA_LIBRARIES := ctsmediautil ctsdeviceutil ctstestrunner
+
+LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni
LOCAL_SRC_FILES := $(call all-java-files-under, src)
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java
index b7d1d27..6459c86 100644
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java
+++ b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/CodecInfo.java
@@ -66,7 +66,12 @@
break;
}
}
- VideoCapabilities vidCap = cap.getVideoCapabilities();
+
+ if (cap.colorFormats.length == 0) {
+ Log.w(TAG, "no supported color format");
+ return null;
+ }
+
CodecInfo info = new CodecInfo();
for (int color : cap.colorFormats) {
if (color == CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
@@ -77,12 +82,8 @@
}
}
printIntArray("supported colors", cap.colorFormats);
- // either YUV420 planar or semiplanar should be supported
- if (!info.mSupportPlanar && !info.mSupportSemiPlanar) {
- Log.i(TAG, "no supported color format");
- return null;
- }
+ VideoCapabilities vidCap = cap.getVideoCapabilities();
if (mimeType.equals(VIDEO_AVC)) {
info.mFps = vidCap.getSupportedFrameRatesFor(w, h).getUpper().intValue();
info.mBitRate = vidCap.getBitrateRange().getUpper();
diff --git a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
index aacb7a5..bf02d9c 100644
--- a/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
+++ b/suite/cts/deviceTests/videoperf/src/com/android/cts/videoperf/VideoEncoderDecoderTest.java
@@ -16,7 +16,12 @@
package com.android.cts.videoperf;
+import android.graphics.ImageFormat;
import android.graphics.Point;
+import android.media.cts.CodecImage;
+import android.media.cts.CodecUtils;
+import android.media.Image;
+import android.media.Image.Plane;
import android.media.MediaCodec;
import android.media.MediaCodecList;
import android.media.MediaCodecInfo.CodecCapabilities;
@@ -60,12 +65,10 @@
private static final int Y_CLAMP_MIN = 16;
private static final int Y_CLAMP_MAX = 235;
private static final int YUV_PLANE_ADDITIONAL_LENGTH = 200;
- private ByteBuffer mYBuffer;
- private ByteBuffer mUVBuffer;
- // if input raw data is semi-planar
- private boolean mSrcSemiPlanar;
- // if output raw data is semi-planar
- private boolean mDstSemiPlanar;
+ private ByteBuffer mYBuffer, mYDirectBuffer;
+ private ByteBuffer mUVBuffer, mUVDirectBuffer;
+ private int mSrcColorFormat;
+ private int mDstColorFormat;
private int mBufferWidth;
private int mBufferHeight;
private int mVideoWidth;
@@ -95,6 +98,8 @@
mEncodedOutputBuffer = null;
mYBuffer = null;
mUVBuffer = null;
+ mYDirectBuffer = null;
+ mUVDirectBuffer = null;
mRandom = null;
super.tearDown();
}
@@ -124,6 +129,33 @@
doTest(VIDEO_AVC, 1920, 1072, NUMBER_OF_REPEAT);
}
+ private boolean isSrcSemiPlanar() {
+ return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+ }
+
+ private boolean isSrcFlexYUV() {
+ return mSrcColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
+ }
+
+ private boolean isDstSemiPlanar() {
+ return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+ }
+
+ private boolean isDstFlexYUV() {
+ return mDstColorFormat == CodecCapabilities.COLOR_FormatYUV420Flexible;
+ }
+
+ private static int getColorFormat(CodecInfo info) {
+ if (info.mSupportSemiPlanar) {
+ return CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
+ } else if (info.mSupportPlanar) {
+ return CodecCapabilities.COLOR_FormatYUV420Planar;
+ } else {
+ // FlexYUV must be supported
+ return CodecCapabilities.COLOR_FormatYUV420Flexible;
+ }
+ }
+
/**
* Run encoding / decoding test for given mimeType of codec
* @param mimeType like video/avc
@@ -141,8 +173,14 @@
assertNotNull(infoDec);
mVideoWidth = w;
mVideoHeight = h;
- initYUVPlane(w + YUV_PLANE_ADDITIONAL_LENGTH, h + YUV_PLANE_ADDITIONAL_LENGTH,
- infoEnc.mSupportSemiPlanar, infoDec.mSupportSemiPlanar);
+
+ mSrcColorFormat = getColorFormat(infoEnc);
+ mDstColorFormat = getColorFormat(infoDec);
+ Log.i(TAG, "Testing video resolution " + w + "x" + h +
+ ": enc format " + mSrcColorFormat +
+ ", dec format " + mDstColorFormat);
+
+ initYUVPlane(w + YUV_PLANE_ADDITIONAL_LENGTH, h + YUV_PLANE_ADDITIONAL_LENGTH);
double[] encoderFpsResults = new double[numberRepeat];
double[] decoderFpsResults = new double[numberRepeat];
double[] totalFpsResults = new double[numberRepeat];
@@ -154,9 +192,7 @@
format.setInteger(MediaFormat.KEY_BIT_RATE, infoEnc.mBitRate);
format.setInteger(MediaFormat.KEY_WIDTH, w);
format.setInteger(MediaFormat.KEY_HEIGHT, h);
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
- infoEnc.mSupportSemiPlanar ? CodecCapabilities.COLOR_FormatYUV420SemiPlanar :
- CodecCapabilities.COLOR_FormatYUV420Planar);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mSrcColorFormat);
format.setInteger(MediaFormat.KEY_FRAME_RATE, infoEnc.mFps);
mFrameRate = infoEnc.mFps;
format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, KEY_I_FRAME_INTERVAL);
@@ -166,9 +202,7 @@
format.setString(MediaFormat.KEY_MIME, mimeType);
format.setInteger(MediaFormat.KEY_WIDTH, w);
format.setInteger(MediaFormat.KEY_HEIGHT, h);
- format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
- infoDec.mSupportSemiPlanar ? CodecCapabilities.COLOR_FormatYUV420SemiPlanar :
- CodecCapabilities.COLOR_FormatYUV420Planar);
+ format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mDstColorFormat);
double[] decoderResult = runDecoder(VIDEO_AVC, format);
if (decoderResult == null) {
success = false;
@@ -228,7 +262,6 @@
return Double.NaN;
}
codec.start();
- ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
int numBytesSubmitted = 0;
@@ -241,10 +274,24 @@
if (inFramesCount < totalFrames) {
index = codec.dequeueInputBuffer(VIDEO_CODEC_WAIT_TIME_US /* timeoutUs */);
if (index != MediaCodec.INFO_TRY_AGAIN_LATER) {
- int size = queueInputBufferEncoder(
- codec, codecInputBuffers, index, inFramesCount,
- (inFramesCount == (totalFrames - 1)) ?
- MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+ int size;
+ // when encoder only supports flexYUV, use Image only; otherwise,
+ // use ByteBuffer & Image each on half of the frames to test both
+ if (isSrcFlexYUV() || inFramesCount % 2 == 0) {
+ Image image = codec.getInputImage(index);
+ // image should always be available
+ assertTrue(image != null);
+ size = queueInputImageEncoder(
+ codec, image, index, inFramesCount,
+ (inFramesCount == (totalFrames - 1)) ?
+ MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+ } else {
+ ByteBuffer buffer = codec.getInputBuffer(index);
+ size = queueInputBufferEncoder(
+ codec, buffer, index, inFramesCount,
+ (inFramesCount == (totalFrames - 1)) ?
+ MediaCodec.BUFFER_FLAG_END_OF_STREAM : 0);
+ }
inFramesCount++;
numBytesSubmitted += size;
if (VERBOSE) {
@@ -290,8 +337,7 @@
* @return size of enqueued data.
*/
private int queueInputBufferEncoder(
- MediaCodec codec, ByteBuffer[] inputBuffers, int index, int frameCount, int flags) {
- ByteBuffer buffer = inputBuffers[index];
+ MediaCodec codec, ByteBuffer buffer, int index, int frameCount, int flags) {
buffer.clear();
Point origin = getOrigin(frameCount);
@@ -302,7 +348,7 @@
buffer.put(yBuffer, srcOffsetY, mVideoWidth);
srcOffsetY += mBufferWidth;
}
- if (mSrcSemiPlanar) {
+ if (isSrcSemiPlanar()) {
int srcOffsetU = origin.y / 2 * mBufferWidth + origin.x / 2 * 2;
final byte[] uvBuffer = mUVBuffer.array();
for (int i = 0; i < mVideoHeight / 2; i++) {
@@ -313,16 +359,161 @@
int srcOffsetU = origin.y / 2 * mBufferWidth / 2 + origin.x / 2;
int srcOffsetV = srcOffsetU + mBufferWidth / 2 * mBufferHeight / 2;
final byte[] uvBuffer = mUVBuffer.array();
- for (int i = 0; i < mVideoHeight /2; i++) { //U only
+ for (int i = 0; i < mVideoHeight / 2; i++) { //U only
buffer.put(uvBuffer, srcOffsetU, mVideoWidth / 2);
srcOffsetU += mBufferWidth / 2;
}
- for (int i = 0; i < mVideoHeight /2; i++) { //V only
+ for (int i = 0; i < mVideoHeight / 2; i++) { //V only
buffer.put(uvBuffer, srcOffsetV, mVideoWidth / 2);
srcOffsetV += mBufferWidth / 2;
}
}
- int size = mVideoHeight * mVideoWidth * 3 /2;
+ int size = mVideoHeight * mVideoWidth * 3 / 2;
+ long ptsUsec = computePresentationTime(frameCount);
+
+ codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
+ if (VERBOSE && (frameCount == 0)) {
+ printByteArray("Y ", mYBuffer.array(), 0, 20);
+ printByteArray("UV ", mUVBuffer.array(), 0, 20);
+ printByteArray("UV ", mUVBuffer.array(), mBufferWidth * 60, 20);
+ }
+ return size;
+ }
+
+ class YUVImage extends CodecImage {
+ private final int mImageWidth;
+ private final int mImageHeight;
+ private final Plane[] mPlanes;
+
+ YUVImage(
+ Point origin,
+ int imageWidth, int imageHeight,
+ int arrayWidth, int arrayHeight,
+ boolean semiPlanar,
+ ByteBuffer bufferY, ByteBuffer bufferUV) {
+ mImageWidth = imageWidth;
+ mImageHeight = imageHeight;
+ ByteBuffer dupY = bufferY.duplicate();
+ ByteBuffer dupUV = bufferUV.duplicate();
+ mPlanes = new Plane[3];
+
+ int srcOffsetY = origin.x + origin.y * arrayWidth;
+
+ mPlanes[0] = new YUVPlane(
+ mImageWidth, mImageHeight, arrayWidth, 1,
+ dupY, srcOffsetY);
+
+ if (semiPlanar) {
+ int srcOffsetUV = origin.y / 2 * arrayWidth + origin.x / 2 * 2;
+
+ mPlanes[1] = new YUVPlane(
+ mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
+ dupUV, srcOffsetUV);
+ mPlanes[2] = new YUVPlane(
+ mImageWidth / 2, mImageHeight / 2, arrayWidth, 2,
+ dupUV, srcOffsetUV + 1);
+ } else {
+ int srcOffsetU = origin.y / 2 * arrayWidth / 2 + origin.x / 2;
+ int srcOffsetV = srcOffsetU + arrayWidth / 2 * arrayHeight / 2;
+
+ mPlanes[1] = new YUVPlane(
+ mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
+ dupUV, srcOffsetU);
+ mPlanes[2] = new YUVPlane(
+ mImageWidth / 2, mImageHeight / 2, arrayWidth / 2, 1,
+ dupUV, srcOffsetV);
+ }
+ }
+
+ @Override
+ public int getFormat() {
+ return ImageFormat.YUV_420_888;
+ }
+
+ @Override
+ public int getWidth() {
+ return mImageWidth;
+ }
+
+ @Override
+ public int getHeight() {
+ return mImageHeight;
+ }
+
+ @Override
+ public long getTimestamp() {
+ return 0;
+ }
+
+ @Override
+ public Plane[] getPlanes() {
+ return mPlanes;
+ }
+
+ @Override
+ public void close() {
+ mPlanes[0] = null;
+ mPlanes[1] = null;
+ mPlanes[2] = null;
+ }
+
+ class YUVPlane extends CodecImage.Plane {
+ private final int mRowStride;
+ private final int mPixelStride;
+ private final ByteBuffer mByteBuffer;
+
+ YUVPlane(int w, int h, int rowStride, int pixelStride,
+ ByteBuffer buffer, int offset) {
+ mRowStride = rowStride;
+ mPixelStride = pixelStride;
+
+ // only safe to access length bytes starting from buffer[offset]
+ int length = (h - 1) * rowStride + (w - 1) * pixelStride + 1;
+
+ buffer.position(offset);
+ mByteBuffer = buffer.slice();
+ mByteBuffer.limit(length);
+ }
+
+ @Override
+ public int getRowStride() {
+ return mRowStride;
+ }
+
+ @Override
+ public int getPixelStride() {
+ return mPixelStride;
+ }
+
+ @Override
+ public ByteBuffer getBuffer() {
+ return mByteBuffer;
+ }
+ }
+ }
+
+ /**
+ * Fills input image for encoder from YUV buffers.
+ * @return size of enqueued data.
+ */
+ private int queueInputImageEncoder(
+ MediaCodec codec, Image image, int index, int frameCount, int flags) {
+ assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+
+
+ Point origin = getOrigin(frameCount);
+
+ // Y color first
+ CodecImage srcImage = new YUVImage(
+ origin,
+ mVideoWidth, mVideoHeight,
+ mBufferWidth, mBufferHeight,
+ isSrcSemiPlanar(),
+ mYDirectBuffer, mUVDirectBuffer);
+
+ CodecUtils.copyFlexYUVImage(image, srcImage);
+
+ int size = mVideoHeight * mVideoWidth * 3 / 2;
long ptsUsec = computePresentationTime(frameCount);
codec.queueInputBuffer(index, 0 /* offset */, size, ptsUsec /* timeUs */, flags);
@@ -368,7 +559,6 @@
codec.configure(format, null /* surface */, null /* crypto */, 0 /* flags */);
codec.start();
ByteBuffer[] codecInputBuffers = codec.getInputBuffers();
- ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers();
double totalErrorSquared = 0;
@@ -407,22 +597,49 @@
// only do YUV compare on EOS frame if the buffer size is none-zero
if (info.size > 0) {
- ByteBuffer buf = codecOutputBuffers[outputBufIndex];
- if (VERBOSE && (outFrameCount == 0)) {
- printByteBuffer("Y ", buf, 0, 20);
- printByteBuffer("UV ", buf, mVideoWidth * mVideoHeight, 20);
- printByteBuffer("UV ", buf,
- mVideoWidth * mVideoHeight + mVideoWidth * 60, 20);
- }
Point origin = getOrigin(outFrameCount);
- for (int i = 0; i < PIXEL_CHECK_PER_FRAME; i++) {
+ int i;
+
+ // if decoder supports planar or semiplanar, check output with
+ // ByteBuffer & Image each on half of the points
+ int pixelCheckPerFrame = PIXEL_CHECK_PER_FRAME;
+ if (!isDstFlexYUV()) {
+ pixelCheckPerFrame /= 2;
+ ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
+ if (VERBOSE && (outFrameCount == 0)) {
+ printByteBuffer("Y ", buf, 0, 20);
+ printByteBuffer("UV ", buf, mVideoWidth * mVideoHeight, 20);
+ printByteBuffer("UV ", buf,
+ mVideoWidth * mVideoHeight + mVideoWidth * 60, 20);
+ }
+ for (i = 0; i < pixelCheckPerFrame; i++) {
+ int w = mRandom.nextInt(mVideoWidth);
+ int h = mRandom.nextInt(mVideoHeight);
+ getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
+ getPixelValuesFromOutputBuffer(buf, w, h, decoded);
+ if (VERBOSE) {
+ Log.i(TAG, outFrameCount + "-" + i + "- th round: ByteBuffer:"
+ + " expected "
+ + expected.mY + "," + expected.mU + "," + expected.mV
+ + " decoded "
+ + decoded.mY + "," + decoded.mU + "," + decoded.mV);
+ }
+ totalErrorSquared += expected.calcErrorSquared(decoded);
+ }
+ }
+
+ Image image = codec.getOutputImage(outputBufIndex);
+ assertTrue(image != null);
+ for (i = 0; i < pixelCheckPerFrame; i++) {
int w = mRandom.nextInt(mVideoWidth);
int h = mRandom.nextInt(mVideoHeight);
getPixelValuesFromYUVBuffers(origin.x, origin.y, w, h, expected);
- getPixelValuesFromOutputBuffer(buf, w, h, decoded);
+ getPixelValuesFromImage(image, w, h, decoded);
if (VERBOSE) {
- Log.i(TAG, outFrameCount + "-" + i + "- th round expcted " + expected.mY
- + "," + expected.mU + "," + expected.mV + " decoded "
+ Log.i(TAG, outFrameCount + "-" + i + "- th round: FlexYUV:"
+ + " expcted "
+ + expected.mY + "," + expected.mU + "," + expected.mV
+ + " decoded "
+ decoded.mY + "," + decoded.mU + "," + decoded.mV);
}
totalErrorSquared += expected.calcErrorSquared(decoded);
@@ -434,23 +651,17 @@
Log.d(TAG, "saw output EOS.");
sawOutputEOS = true;
}
- } else if (res == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
- codecOutputBuffers = codec.getOutputBuffers();
- Log.d(TAG, "output buffers have changed.");
} else if (res == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat oformat = codec.getOutputFormat();
Log.d(TAG, "output format has changed to " + oformat);
int colorFormat = oformat.getInteger(MediaFormat.KEY_COLOR_FORMAT);
- if (colorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar ) {
- mDstSemiPlanar = true;
- } else if (colorFormat == CodecCapabilities.COLOR_FormatYUV420Planar ) {
- mDstSemiPlanar = false;
+ if (colorFormat == CodecCapabilities.COLOR_FormatYUV420SemiPlanar
+ || colorFormat == CodecCapabilities.COLOR_FormatYUV420Planar) {
+ mDstColorFormat = colorFormat;
} else {
+ mDstColorFormat = CodecCapabilities.COLOR_FormatYUV420Flexible;
Log.w(TAG, "output format changed to unsupported one " +
- Integer.toHexString(colorFormat));
- // give up and return as nothing can be done
- codec.release();
- return null;
+ Integer.toHexString(colorFormat) + ", using FlexYUV");
}
}
}
@@ -491,12 +702,12 @@
* @param semiPlanarEnc
* @param semiPlanarDec
*/
- private void initYUVPlane(int w, int h, boolean semiPlanarEnc, boolean semiPlanarDec) {
+ private void initYUVPlane(int w, int h) {
int bufferSizeY = w * h;
mYBuffer = ByteBuffer.allocate(bufferSizeY);
mUVBuffer = ByteBuffer.allocate(bufferSizeY / 2);
- mSrcSemiPlanar = semiPlanarEnc;
- mDstSemiPlanar = semiPlanarDec;
+ mYDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY);
+ mUVDirectBuffer = ByteBuffer.allocateDirect(bufferSizeY / 2);
mBufferWidth = w;
mBufferHeight = h;
final byte[] yArray = mYBuffer.array();
@@ -506,7 +717,7 @@
yArray[i * w + j] = clampY((i + j) & 0xff);
}
}
- if (semiPlanarEnc) {
+ if (isSrcSemiPlanar()) {
for (int i = 0; i < h/2; i++) {
for (int j = 0; j < w/2; j++) {
uvArray[i * w + 2 * j] = (byte) (i & 0xff);
@@ -522,6 +733,10 @@
}
}
}
+ mYDirectBuffer.put(yArray);
+ mUVDirectBuffer.put(uvArray);
+ mYDirectBuffer.rewind();
+ mUVDirectBuffer.rewind();
}
/**
@@ -556,7 +771,7 @@
private void getPixelValuesFromYUVBuffers(int originX, int originY, int x, int y,
YUVValue result) {
result.mY = mYBuffer.get((originY + y) * mBufferWidth + (originX + x));
- if (mSrcSemiPlanar) {
+ if (isSrcSemiPlanar()) {
int index = (originY + y) / 2 * mBufferWidth + (originX + x) / 2 * 2;
//Log.d(TAG, "YUV " + originX + "," + originY + "," + x + "," + y + "," + index);
result.mU = mUVBuffer.get(index);
@@ -577,7 +792,7 @@
*/
private void getPixelValuesFromOutputBuffer(ByteBuffer buffer, int x, int y, YUVValue result) {
result.mY = buffer.get(y * mVideoWidth + x);
- if (mDstSemiPlanar) {
+ if (isDstSemiPlanar()) {
int index = mVideoWidth * mVideoHeight + y / 2 * mVideoWidth + x / 2 * 2;
//Log.d(TAG, "Decoded " + x + "," + y + "," + index);
result.mU = buffer.get(index);
@@ -590,6 +805,22 @@
}
}
+ private void getPixelValuesFromImage(Image image, int x, int y, YUVValue result) {
+ assertTrue(image.getFormat() == ImageFormat.YUV_420_888);
+
+ Plane[] planes = image.getPlanes();
+ assertTrue(planes.length == 3);
+
+ result.mY = getPixelFromPlane(planes[0], x, y);
+ result.mU = getPixelFromPlane(planes[1], x / 2, y / 2);
+ result.mV = getPixelFromPlane(planes[2], x / 2, y / 2);
+ }
+
+ private byte getPixelFromPlane(Plane plane, int x, int y) {
+ ByteBuffer buf = plane.getBuffer();
+ return buf.get(y * plane.getRowStride() + x * plane.getPixelStride());
+ }
+
/**
* Y cannot have full range. clamp it to prevent invalid value.
*/
diff --git a/tests/expectations/knownfailures.txt b/tests/expectations/knownfailures.txt
index d81ce35..78a0cfe 100644
--- a/tests/expectations/knownfailures.txt
+++ b/tests/expectations/knownfailures.txt
@@ -22,6 +22,23 @@
bug: 17595050
},
{
+ description: "the SSLCertificateSocketFactoryTest often fails because of lack of live internet or short timeout, it should be refactored to do a local server testing",
+ names: [
+ "android.net.cts.SSLCertificateSocketFactoryTest#testCreateSocket",
+ "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_bind",
+ "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_simple",
+ "android.net.cts.SSLCertificateSocketFactoryTest#test_createSocket_wrapping"
+ ],
+ bug: 18682315
+},
+{
+ description: "the test result are too much dependent on live-internet connection, which for some devices might not exist",
+ names: [
+ "android.net.wifi.cts.NsdManagerTest#testAndroidTestCaseSetupProperly"
+ ],
+ bug: 18680089
+},
+{
description: "AudioPolicyBinder tests are not yet robust enough",
names: [
"android.security.cts.AudioPolicyBinderTest"
@@ -362,5 +379,19 @@
"com.android.org.conscrypt.SignatureTest#test_getInstance_OpenSSL_ENGINE"
],
bug: 18030049
+},
+{
+ description: "The new recording test is not yet passing on all devices",
+ names: [
+ "android.hardware.camera2.cts.RecordingTest#testRecordingFramerateLowToHigh"
+ ],
+ bug: 18705837
+},
+{
+ description: "The new image reader test is not yet passing on all devices",
+ names: [
+ "android.hardware.camera2.cts.ImageReaderTest#testAllOutputYUVResolutions"
+ ],
+ bug: 18689511
}
]
diff --git a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index 87f0238..f5e1d48 100644
--- a/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -35,7 +35,7 @@
public class AccessibilityNodeInfoTest extends AndroidTestCase {
/** The number of properties of the {@link AccessibilityNodeInfo} class. */
- private static final int NON_STATIC_FIELD_COUNT = 28;
+ private static final int NON_STATIC_FIELD_COUNT = 30;
@SmallTest
public void testMarshaling() throws Exception {
@@ -54,7 +54,7 @@
AccessibilityNodeInfo receivedInfo = AccessibilityNodeInfo.CREATOR.createFromParcel(parcel);
// make sure all fields properly marshaled
- assertEqualsAccessiblityNodeInfo(sentInfo, receivedInfo);
+ assertEqualsAccessibilityNodeInfo(sentInfo, receivedInfo);
}
/**
@@ -204,7 +204,7 @@
* <code>receviedInfo</code> to verify that the received node info is
* the one that is expected.
*/
- public static void assertEqualsAccessiblityNodeInfo(AccessibilityNodeInfo expectedInfo,
+ public static void assertEqualsAccessibilityNodeInfo(AccessibilityNodeInfo expectedInfo,
AccessibilityNodeInfo receivedInfo) {
Rect expectedBounds = new Rect();
Rect receivedBounds = new Rect();
diff --git a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
index 306428f..0163a58 100644
--- a/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
+++ b/tests/tests/animation/src/android/animation/cts/AnimatorSetTest.java
@@ -174,8 +174,8 @@
}
- public void testClone() {
- AnimatorSet set1 = new AnimatorSet();
+ public void testClone() throws Throwable {
+ final AnimatorSet set1 = new AnimatorSet();
final AnimatorListenerAdapter setListener = new AnimatorListenerAdapter() {};
set1.addListener(setListener);
ObjectAnimator animator1 = new ObjectAnimator();
@@ -198,7 +198,12 @@
AnimateObject target = new AnimateObject();
set1.setTarget(target);
- set1.start();
+ runTestOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ set1.start();
+ }
+ });
assertTrue(set1.isStarted());
animator1.getListeners();
diff --git a/tests/tests/app/src/android/app/cts/ServiceTest.java b/tests/tests/app/src/android/app/cts/ServiceTest.java
index b66f4c8..8ba1816 100644
--- a/tests/tests/app/src/android/app/cts/ServiceTest.java
+++ b/tests/tests/app/src/android/app/cts/ServiceTest.java
@@ -448,4 +448,17 @@
// expected
}
}
+
+ @MediumTest
+ public void testImplicitIntentFailsOnApiLevel21() throws Exception {
+ Intent intent = new Intent(LocalService.SERVICE_LOCAL);
+ EmptyConnection conn = new EmptyConnection();
+ try {
+ mContext.bindService(intent, conn, 0);
+ mContext.unbindService(conn);
+ fail("Implicit intents should be disallowed for apps targeting API 21+");
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
}
diff --git a/tests/tests/content/src/android/content/cts/IntentTest.java b/tests/tests/content/src/android/content/cts/IntentTest.java
index d4fac55..0f9a5cc 100644
--- a/tests/tests/content/src/android/content/cts/IntentTest.java
+++ b/tests/tests/content/src/android/content/cts/IntentTest.java
@@ -45,6 +45,7 @@
import java.io.Serializable;
import java.net.URISyntaxException;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.Set;
public class IntentTest extends AndroidTestCase {
@@ -676,7 +677,7 @@
final String compnent =
"component(" + mContext.getPackageName() + "!" + MockActivity.class.getName() + ")";
- uri = "testdata#action(test)categories(test!test2)type(mtype)launchFlags(1)" + compnent
+ uri = "testdata#action(test)categories(test!test2)type(mtype)launchFlags(5)" + compnent
+ "extras(Stest=testString!btestbyte=1!"
+ "Btestboolean=true!ctestchar=a!dtestdouble=1d!"
+ "itestint=1!ltestlong=1!stestshort=1!ftestfloat=1f)";
@@ -686,7 +687,7 @@
assertEquals(mComponentName, mIntent.getComponent());
assertEquals("test", (String) (mIntent.getCategories().toArray()[0]));
assertEquals("mtype", mIntent.getType());
- assertEquals(1, mIntent.getFlags());
+ assertEquals(4, mIntent.getFlags());
assertEquals("testString", mIntent.getStringExtra("test"));
assertTrue(mIntent.getBooleanExtra("testboolean", false));
final byte b = 1;
@@ -812,10 +813,13 @@
target = Intent.getIntent(uri);
assertEquals(TEST_TYPE, target.getType());
- mIntent.setFlags(1);
+ mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+ | Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION
+ | Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
+ | Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION);
uri = mIntent.toURI();
target = Intent.getIntent(uri);
- assertEquals(1, target.getFlags());
+ assertEquals(Intent.FLAG_ACTIVITY_NEW_DOCUMENT, target.getFlags());
String stringValue = "testString";
mIntent.putExtra(TEST_EXTRA_NAME, stringValue);
@@ -869,8 +873,8 @@
}
public void testToURI() {
- mIntent.setFlags(0);
- assertEquals("#Intent;end", mIntent.toURI());
+ mIntent = new Intent();
+ assertEquals("", mIntent.toURI());
mIntent.setData(TEST_URI);
assertTrue(mIntent.toURI().indexOf(TEST_URI.toString()) != -1);
@@ -937,6 +941,321 @@
return uri.toString();
}
+ static Intent makeSelector(Intent baseIntent, Intent selectorIntent) {
+ baseIntent.setSelector(selectorIntent);
+ return baseIntent;
+ }
+
+ public void testUris() {
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;end",
+ null,
+ new Intent().setAction("android.test.FOO"));
+ checkIntentUri(
+ "intent:#Intent;category=android.test.FOO;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW).addCategory("android.test.FOO"));
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;launchFlags=0x20;end",
+ null,
+ new Intent().setAction("android.test.FOO").setFlags(0x20));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah")));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;component=com.exfoo/com.argh.Bar;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah"))
+ .setComponent(new ComponentName("com.exfoo", "com.argh.Bar")));
+ checkIntentUri(
+ "intent://www.example.com/blah#fragment#Intent;scheme=http;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah#fragment")));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;action=android.test.foo;end",
+ null,
+ new Intent().setAction("android.test.foo")
+ .setData(Uri.parse("http://www.example.com/blah")));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;type=image/foo;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setDataAndType(Uri.parse("mailto:foo"), "image/foo"));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;S.string=text;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("string", "text"));
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;S.string=text;end",
+ null,
+ new Intent().setAction("android.test.FOO").putExtra("string", "text"));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;i.int=1000;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("int", 1000));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;l.long=1000;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("long", (long) 1000));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;B.boolean=true;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("boolean", true));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;f.float=10.4;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("float", 10.4f));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;d.double=10.4;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("mailto:foo"))
+ .putExtra("double", (double) 10.4));
+ checkIntentUri(
+ "intent:#Intent;S.string=text;i.int=1000;l.long=1000;B.boolean=true;f.float=10.4;end",
+ null,
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("string", "text")
+ .putExtra("int", 1000).putExtra("long", (long) 1000)
+ .putExtra("boolean", true).putExtra("float", 10.4f));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;SEL;scheme=foobar;action=android.test.FOO;end",
+ null,
+ makeSelector(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("mailto:foo")),
+ new Intent("android.test.FOO").setData(Uri.parse("foobar:"))));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;SEL;action=android.test.FOO;package=com.myapp;end",
+ null,
+ makeSelector(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("mailto:foo")),
+ new Intent("android.test.FOO").setPackage("com.myapp")));
+ checkIntentUri(
+ "intent:foo#Intent;scheme=mailto;SEL;action=android.test.FOO;component=com.exfoo/com.argh.Bar;end",
+ null,
+ makeSelector(new Intent(Intent.ACTION_VIEW).setData(Uri.parse("mailto:foo")),
+ new Intent("android.test.FOO")
+ .setComponent(new ComponentName("com.exfoo", "com.argh.Bar"))));
+
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;package=com.myapp;end",
+ "android-app://com.myapp#Intent;action=android.test.FOO;end",
+ new Intent().setAction("android.test.FOO").setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;action=android.intent.action.MAIN;package=com.myapp;end",
+ "android-app://com.myapp",
+ new Intent().setAction(Intent.ACTION_MAIN).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;package=com.myapp;end",
+ "android-app://com.myapp#Intent;action=android.intent.action.VIEW;end",
+ new Intent().setAction(Intent.ACTION_VIEW).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;category=android.test.FOO;package=com.myapp;end",
+ "android-app://com.myapp#Intent;action=android.intent.action.VIEW;category=android.test.FOO;end",
+ new Intent().setAction(Intent.ACTION_VIEW).addCategory("android.test.FOO")
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;launchFlags=0x20;package=com.myapp;end",
+ "android-app://com.myapp#Intent;action=android.test.FOO;launchFlags=0x20;end",
+ new Intent().setAction("android.test.FOO").setFlags(0x20)
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;package=com.myapp;end",
+ "android-app://com.myapp/http/www.example.com/blah",
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah"))
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;package=com.myapp;component=com.exfoo/com.argh.Bar;end",
+ "android-app://com.myapp/http/www.example.com/blah#Intent;component=com.exfoo/com.argh.Bar;end",
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah"))
+ .setComponent(new ComponentName("com.exfoo", "com.argh.Bar"))
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent://www.example.com/blah#fragment#Intent;scheme=http;package=com.myapp;end",
+ "android-app://com.myapp/http/www.example.com/blah#fragment",
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah#fragment"))
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent://www.example.com/blah#fragment#Intent;scheme=http;action=android.test.FOO;package=com.myapp;end",
+ "android-app://com.myapp/http/www.example.com/blah#fragment#Intent;action=android.test.FOO;end",
+ new Intent().setAction("android.test.FOO")
+ .setData(Uri.parse("http://www.example.com/blah#fragment"))
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent://www.example.com/blah#Intent;scheme=http;package=com.myapp;end",
+ "android-app://com.myapp/http/www.example.com/blah",
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setData(Uri.parse("http://www.example.com/blah"))
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;type=image/foo;package=com.myapp;end",
+ "android-app://com.myapp/mailto#Intent;type=image/foo;end",
+ new Intent().setAction(Intent.ACTION_VIEW)
+ .setDataAndType(Uri.parse("mailto:"), "image/foo")
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;S.string=text;end",
+ "android-app://com.myapp/mailto#Intent;S.string=text;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("string", "text")
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;action=android.test.FOO;package=com.myapp;S.string=text;end",
+ "android-app://com.myapp#Intent;action=android.test.FOO;S.string=text;end",
+ new Intent().setAction("android.test.FOO").putExtra("string", "text")
+ .setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;i.int=1000;end",
+ "android-app://com.myapp/mailto#Intent;i.int=1000;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("int", 1000)
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;l.long=1000;end",
+ "android-app://com.myapp/mailto#Intent;l.long=1000;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("long", (long) 1000)
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;B.boolean=true;end",
+ "android-app://com.myapp/mailto#Intent;B.boolean=true;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("boolean", true)
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;f.float=10.4;end",
+ "android-app://com.myapp/mailto#Intent;f.float=10.4;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("float", 10.4f)
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;scheme=mailto;package=com.myapp;d.double=10.4;end",
+ "android-app://com.myapp/mailto#Intent;d.double=10.4;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("double", (double) 10.4)
+ .setData(Uri.parse("mailto:")).setPackage("com.myapp"));
+ checkIntentUri(
+ "intent:#Intent;package=com.myapp;S.string=text;i.int=1000;l.long=1000;B.boolean=true;f.float=10.4;end",
+ "android-app://com.myapp#Intent;action=android.intent.action.VIEW;S.string=text;i.int=1000;l.long=1000;B.boolean=true;f.float=10.4;end",
+ new Intent().setAction(Intent.ACTION_VIEW).putExtra("string", "text")
+ .putExtra("int", 1000).putExtra("long", (long) 1000)
+ .putExtra("boolean", true).putExtra("float", 10.4f)
+ .setPackage("com.myapp"));
+ }
+
+ private boolean compareIntents(Intent expected, Intent actual) {
+ if (!Objects.equals(expected.getAction(), actual.getAction())) {
+ return false;
+ }
+ if (!Objects.equals(expected.getData(), actual.getData())) {
+ return false;
+ }
+ if (!Objects.equals(expected.getType(), actual.getType())) {
+ return false;
+ }
+ if (!Objects.equals(expected.getPackage(), actual.getPackage())) {
+ return false;
+ }
+ if (!Objects.equals(expected.getComponent(), actual.getComponent())) {
+ return false;
+ }
+ if (expected.getFlags() != actual.getFlags()) {
+ return false;
+ }
+ Set<String> expectedCat = expected.getCategories();
+ Set<String> actualCat = actual.getCategories();
+ if (expectedCat != actualCat) {
+ if (expectedCat == null || actualCat == null) {
+ return false;
+ }
+ for (String cat : expectedCat) {
+ if (!actual.hasCategory(cat)) {
+ return false;
+ }
+ }
+ for (String cat : actualCat) {
+ if (!expected.hasCategory(cat)) {
+ return false;
+ }
+ }
+ }
+ Bundle extras1 = expected.getExtras();
+ Bundle extras2 = actual.getExtras();
+ if (extras1 != extras2) {
+ if (extras1 == null || extras2 == null) {
+ return false;
+ }
+ for (String key : extras1.keySet()) {
+ if (!Objects.equals(extras1.get(key), extras2.get(key))) {
+ return false;
+ }
+ }
+ for (String key : extras2.keySet()) {
+ if (!Objects.equals(extras1.get(key), extras2.get(key))) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ private void assertEqualsIntent(String msg, Intent expected, Intent actual) {
+ if (!compareIntents(expected, actual)) {
+ failNotEquals(msg, expected, actual);
+ }
+ Intent expectedSel = expected.getSelector();
+ Intent actualSel = actual.getSelector();
+ if (expectedSel != actualSel) {
+ if (expectedSel == null || actualSel == null) {
+ failNotEquals(msg, expected, actual);
+ }
+ if (!compareIntents(expectedSel, actualSel)) {
+ failNotEquals(msg, expected, actual);
+ }
+ }
+ }
+
+ private void checkIntentUri(String intentSchemeUri, String androidAppSchemeUri, Intent intent) {
+ if (intentSchemeUri != null) {
+ try {
+ Intent genIntent = Intent.parseUri(intentSchemeUri, 0);
+ assertEqualsIntent("Implicitly converting " + intentSchemeUri + " to Intent",
+ intent, genIntent);
+ genIntent = Intent.parseUri(intentSchemeUri, Intent.URI_INTENT_SCHEME);
+ assertEqualsIntent("Explicitly converting " + intentSchemeUri + " to Intent",
+ intent, genIntent);
+ } catch (URISyntaxException e) {
+ fail("Failure parsing " + intentSchemeUri + ": " + e);
+ }
+ String genUri = intent.toUri(Intent.URI_INTENT_SCHEME);
+ assertEquals("Converting " + intent + " to intent: uri",
+ intentSchemeUri, genUri);
+ }
+ if (androidAppSchemeUri != null) {
+ try {
+ Intent genIntent = Intent.parseUri(androidAppSchemeUri, 0);
+ assertEqualsIntent("Implicitly converting " + androidAppSchemeUri + " to Intent",
+ intent, genIntent);
+ genIntent = Intent.parseUri(intentSchemeUri, Intent.URI_ANDROID_APP_SCHEME);
+ assertEqualsIntent("Explicitly converting " + androidAppSchemeUri + " to Intent",
+ intent, genIntent);
+ } catch (URISyntaxException e) {
+ fail("Failure parsing " + androidAppSchemeUri + ": " + e);
+ }
+ String genUri = intent.toUri(Intent.URI_ANDROID_APP_SCHEME);
+ assertEquals("Converting " + intent + " to android-app: uri",
+ androidAppSchemeUri, genUri);
+ }
+ }
+
public void testAccessFlags() {
int expected = 1;
mIntent.setFlags(expected);
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
new file mode 100644
index 0000000..fa5b606
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/BurstCaptureTest.java
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.cts;
+
+import static android.hardware.camera2.cts.CameraTestUtils.*;
+
+import android.graphics.ImageFormat;
+import android.hardware.camera2.CameraDevice;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.CaptureResult;
+import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
+import android.hardware.camera2.cts.testcases.Camera2SurfaceViewTestCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
+import android.media.Image;
+import android.util.Log;
+import android.util.Range;
+import android.util.Size;
+
+import java.util.List;
+import java.util.ArrayList;
+
+public class BurstCaptureTest extends Camera2SurfaceViewTestCase {
+ private static final String TAG = "BurstCaptureTest";
+ private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
+ /**
+ * Test BURST_CAPTURE capability with full-AUTO capture.
+ * Also verifies sensor settings operation if READ_SENSOR_SETTINGS is available.
+ */
+ public void testYuvBurst() throws Exception {
+ for (int i = 0; i < mCameraIds.length; i++) {
+ try {
+ String id = mCameraIds[i];
+ Log.i(TAG, "Testing YUV Burst for camera " + id);
+ openDevice(id);
+ if (!mStaticInfo.isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_BURST_CAPTURE)) {
+ Log.i(TAG, "BURST_CAPTURE capability is not supported in camera " + id +
+ ". Skip the test");
+ continue;
+ }
+
+ yuvBurstTestByCamera(id);
+ } finally {
+ closeDevice();
+ closeImageReader();
+ }
+ }
+ }
+
+ public void yuvBurstTestByCamera(String cameraId) throws Exception {
+ // Parameters
+ final int MAX_CONVERGENCE_FRAMES = 150; // 5 sec at 30fps
+ final long MAX_PREVIEW_RESULT_TIMEOUT_MS = 1000;
+ final int BURST_SIZE = 100;
+ final float FRAME_DURATION_MARGIN_FRACTION = 0.1f;
+
+ // Find a good preview size (bound to 1080p)
+ final Size previewSize = mOrderedPreviewSizes.get(0);
+
+ // Get maximum YUV_420_888 size
+ final Size stillSize = getMaxPreviewSize(cameraId, mCameraManager);
+
+ // Find max pipeline depth and sync latency
+ final int maxPipelineDepth = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.REQUEST_PIPELINE_MAX_DEPTH);
+ final int maxSyncLatency = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.SYNC_MAX_LATENCY);
+
+ assertTrue("Cam " + cameraId + ": maxSyncLatency is UNKNOWN;" +
+ " not allowed for BURST_CAPTURE capability",
+ maxSyncLatency >= 0);
+
+ // Find minimum frame duration for full-res YUV_420_888
+ StreamConfigurationMap config = mStaticInfo.getCharacteristics().get(
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
+ final long minStillFrameDuration =
+ config.getOutputMinFrameDuration(ImageFormat.YUV_420_888, stillSize);
+
+ // Find suitable target FPS range - as high as possible
+ Range<Integer>[] fpsRanges = mStaticInfo.getAeAvailableTargetFpsRangesChecked();
+ int minBurstFps = (int) Math.floor(1e9 / minStillFrameDuration);
+ Range<Integer> targetRange = null;
+ for (Range<Integer> candidateRange : fpsRanges) {
+ if (candidateRange.getLower() >= minBurstFps) {
+ if (targetRange == null) {
+ targetRange = candidateRange;
+ } else if (candidateRange.getLower() > targetRange.getLower()) {
+ targetRange = candidateRange;
+ } else if (candidateRange.getUpper() > targetRange.getUpper()) {
+ targetRange = candidateRange;
+ }
+ }
+ }
+ assertTrue(String.format("Cam %s: No target FPS range found with minimum FPS above " +
+ " 1/minFrameDuration (%d fps, duration %d ns) for full-resolution YUV",
+ cameraId, minBurstFps, minStillFrameDuration),
+ targetRange != null);
+
+ Log.i(TAG, String.format("Selected frame rate range %d - %d for YUV burst",
+ targetRange.getLower(), targetRange.getUpper()));
+
+ // Check if READ_SENSOR_SETTINGS is supported
+ final boolean checkSensorSettings = mStaticInfo.isCapabilitySupported(
+ CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_READ_SENSOR_SETTINGS);
+
+ // Configure basic preview and burst settings
+
+ CaptureRequest.Builder previewBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ CaptureRequest.Builder burstBuilder =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+
+ previewBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+ targetRange);
+ burstBuilder.set(CaptureRequest.CONTROL_AE_TARGET_FPS_RANGE,
+ targetRange);
+ burstBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ burstBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+
+ // Create session and start up preview
+
+ SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+ SimpleImageReaderListener imageListener = new SimpleImageReaderListener();
+
+ prepareCaptureAndStartPreview(
+ previewBuilder, burstBuilder,
+ previewSize, stillSize,
+ ImageFormat.YUV_420_888, resultListener,
+ /*maxNumImages*/ 3, imageListener);
+
+ // Create burst
+
+ List<CaptureRequest> burst = new ArrayList<>();
+ for (int i = 0; i < BURST_SIZE; i++) {
+ burst.add(burstBuilder.build());
+ }
+
+ // Converge AE/AWB
+
+ int frameCount = 0;
+ while (true) {
+ CaptureResult result = resultListener.getCaptureResult(MAX_PREVIEW_RESULT_TIMEOUT_MS);
+ int aeState = result.get(CaptureResult.CONTROL_AE_STATE);
+ int awbState = result.get(CaptureResult.CONTROL_AWB_STATE);
+
+ if (DEBUG) {
+ Log.d(TAG, "aeState: " + aeState + ". awbState: " + awbState);
+ }
+
+ if ((aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED ||
+ aeState == CaptureResult.CONTROL_AE_STATE_FLASH_REQUIRED) &&
+ awbState == CaptureResult.CONTROL_AWB_STATE_CONVERGED) {
+ break;
+ }
+ frameCount++;
+ assertTrue(String.format("Cam %s: Can not converge AE and AWB within %d frames",
+ cameraId, MAX_CONVERGENCE_FRAMES),
+ frameCount < MAX_CONVERGENCE_FRAMES);
+ }
+
+ // Lock AF if there's a focuser
+
+ if (mStaticInfo.hasFocuser()) {
+ previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_START);
+ mSession.capture(previewBuilder.build(), resultListener, mHandler);
+ previewBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
+ CaptureRequest.CONTROL_AF_TRIGGER_IDLE);
+
+ frameCount = 0;
+ while (true) {
+ CaptureResult result = resultListener.getCaptureResult(MAX_PREVIEW_RESULT_TIMEOUT_MS);
+ int afState = result.get(CaptureResult.CONTROL_AF_STATE);
+
+ if (DEBUG) {
+ Log.d(TAG, "afState: " + afState);
+ }
+
+ if (afState == CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED ||
+ afState == CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED) {
+ break;
+ }
+ frameCount++;
+ assertTrue(String.format("Cam %s: Cannot lock AF within %d frames", cameraId,
+ MAX_CONVERGENCE_FRAMES),
+ frameCount < MAX_CONVERGENCE_FRAMES);
+ }
+ }
+
+ // Lock AE/AWB
+
+ previewBuilder.set(CaptureRequest.CONTROL_AE_LOCK, true);
+ previewBuilder.set(CaptureRequest.CONTROL_AWB_LOCK, true);
+
+ CaptureRequest lockedRequest = previewBuilder.build();
+ mSession.setRepeatingRequest(lockedRequest, resultListener, mHandler);
+
+ // Wait for first result with locking
+
+ CaptureResult lockedResult =
+ resultListener.getCaptureResultForRequest(lockedRequest, maxPipelineDepth);
+
+ int pipelineDepth = lockedResult.get(CaptureResult.REQUEST_PIPELINE_DEPTH);
+
+ // Then start waiting on results to get the first result that should be synced
+ // up, and also fire the burst as soon as possible
+
+ if (maxSyncLatency == CameraCharacteristics.SYNC_MAX_LATENCY_PER_FRAME_CONTROL) {
+ // The locked result we have is already synchronized so start the burst
+ mSession.captureBurst(burst, resultListener, mHandler);
+ } else {
+ // Need to get a synchronized result, and may need to start burst later to
+ // be synchronized correctly
+
+ boolean burstSent = false;
+
+ // Calculate how many requests we need to still send down to camera before we
+ // know the settings have settled for the burst
+
+ int requestsNeededToSync = maxSyncLatency - pipelineDepth;
+ for (int i = 0; i < maxSyncLatency; i++) {
+ if (!burstSent && requestsNeededToSync <= 0) {
+ mSession.captureBurst(burst, resultListener, mHandler);
+ burstSent = true;
+ }
+ lockedResult = resultListener.getCaptureResult(MAX_PREVIEW_RESULT_TIMEOUT_MS);
+ requestsNeededToSync--;
+ }
+
+ assertTrue("Cam " + cameraId + ": Burst failed to fire!", burstSent);
+ }
+
+ // Read in locked settings if supported
+
+ long burstExposure = 0;
+ long burstFrameDuration = 0;
+ int burstSensitivity = 0;
+ if (checkSensorSettings) {
+ burstExposure = lockedResult.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+ burstFrameDuration = lockedResult.get(CaptureResult.SENSOR_FRAME_DURATION);
+ burstSensitivity = lockedResult.get(CaptureResult.SENSOR_SENSITIVITY);
+
+ assertTrue(String.format("Cam %s: Frame duration %d ns too short compared to " +
+ "exposure time %d ns", cameraId, burstFrameDuration, burstExposure),
+ burstFrameDuration >= burstExposure);
+
+ assertTrue(String.format("Cam %s: Exposure time is not valid: %d",
+ cameraId, burstExposure),
+ burstExposure > 0);
+ assertTrue(String.format("Cam %s: Frame duration is not valid: %d",
+ cameraId, burstFrameDuration),
+ burstFrameDuration > 0);
+ assertTrue(String.format("Cam %s: Sensitivity is not valid: %d",
+ cameraId, burstSensitivity),
+ burstSensitivity > 0);
+ }
+
+ // Process burst images
+ for (int i = 0; i < BURST_SIZE; i++) {
+ Image img = imageListener.getImage(CAPTURE_IMAGE_TIMEOUT_MS);
+
+ img.close();
+ }
+
+ // Process burst results
+ int burstIndex = 0;
+ CaptureResult burstResult =
+ resultListener.getCaptureResultForRequest(burst.get(burstIndex),
+ maxPipelineDepth + 1);
+ long prevTimestamp = -1;
+ final long frameDurationBound = (long)
+ (minStillFrameDuration * (1 + FRAME_DURATION_MARGIN_FRACTION) );
+
+ List<Long> frameDurations = new ArrayList<>();
+
+ while(true) {
+ // Verify the result
+ assertTrue("Cam " + cameraId + ": Result doesn't match expected request",
+ burstResult.getRequest() == burst.get(burstIndex));
+
+ // Verify locked settings
+ if (checkSensorSettings) {
+ long exposure = burstResult.get(CaptureResult.SENSOR_EXPOSURE_TIME);
+ int sensitivity = burstResult.get(CaptureResult.SENSOR_SENSITIVITY);
+ assertTrue("Cam " + cameraId + ": Exposure not locked!",
+ exposure == burstExposure);
+ assertTrue("Cam " + cameraId + ": Sensitivity not locked!",
+ sensitivity == burstSensitivity);
+ }
+
+ // Collect inter-frame durations
+ long timestamp = burstResult.get(CaptureResult.SENSOR_TIMESTAMP);
+ if (prevTimestamp != -1) {
+ long frameDuration = timestamp - prevTimestamp;
+ frameDurations.add(frameDuration);
+ if (DEBUG) {
+ Log.i(TAG, String.format("Frame %03d Duration %.2f ms", burstIndex,
+ frameDuration/1e6));
+ }
+ }
+ prevTimestamp = timestamp;
+
+ // Get next result
+ burstIndex++;
+ if (burstIndex == BURST_SIZE) break;
+ burstResult = resultListener.getCaptureResult(MAX_PREVIEW_RESULT_TIMEOUT_MS);
+ }
+
+ // Verify inter-frame durations
+
+ long meanFrameSum = 0;
+ for (Long duration : frameDurations) {
+ meanFrameSum += duration;
+ }
+ float meanFrameDuration = (float) meanFrameSum / frameDurations.size();
+
+ float stddevSum = 0;
+ for (Long duration : frameDurations) {
+ stddevSum += (duration - meanFrameDuration) * (duration - meanFrameDuration);
+ }
+ float stddevFrameDuration = (float)
+ Math.sqrt(1.f / (frameDurations.size() - 1 ) * stddevSum);
+
+ Log.i(TAG, String.format("Cam %s: Burst frame duration mean: %.1f, stddev: %.1f", cameraId,
+ meanFrameDuration, stddevFrameDuration));
+
+ assertTrue(
+ String.format("Cam %s: Burst frame duration mean %.1f ns is larger than acceptable, " +
+ "expecting below %d ns, allowing below %d", cameraId,
+ meanFrameDuration, minStillFrameDuration, frameDurationBound),
+ meanFrameDuration <= frameDurationBound);
+
+ // Calculate upper 97.5% bound (assuming durations are normally distributed...)
+ float limit95FrameDuration = meanFrameDuration + 2 * stddevFrameDuration;
+
+ // Don't enforce this yet, but warn
+ if (limit95FrameDuration > frameDurationBound) {
+ Log.w(TAG,
+ String.format("Cam %s: Standard deviation is too large compared to limit: " +
+ "mean: %.1f ms, stddev: %.1f ms: 95%% bound: %f ms", cameraId,
+ meanFrameDuration/1e6, stddevFrameDuration/1e6,
+ limit95FrameDuration/1e6));
+ }
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
index 32a6880..27ff6d1 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -513,6 +513,11 @@
mCameraManager.registerAvailabilityCallback(ac, mHandler);
String[] cameras = mCameraManager.getCameraIdList();
+ if (cameras.length == 0) {
+ Log.i(TAG, "No cameras present, skipping test");
+ return;
+ }
+
// Verify we received available for all cameras' initial state in a reasonable amount of time
HashSet<String> expectedAvailableCameras = new HashSet<String>(Arrays.asList(cameras));
while (expectedAvailableCameras.size() > 0) {
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
index 303099a..dd17779 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/CameraTestUtils.java
@@ -18,6 +18,7 @@
import static com.android.ex.camera2.blocking.BlockingStateCallback.*;
+import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.PointF;
@@ -492,6 +493,23 @@
}
}
+ public static void dumpFile(String fileName, Bitmap data) {
+ FileOutputStream outStream;
+ try {
+ Log.v(TAG, "output will be saved as " + fileName);
+ outStream = new FileOutputStream(fileName);
+ } catch (IOException ioe) {
+ throw new RuntimeException("Unable to create debug output file " + fileName, ioe);
+ }
+
+ try {
+ data.compress(Bitmap.CompressFormat.JPEG, /*quality*/90, outStream);
+ outStream.close();
+ } catch (IOException ioe) {
+ throw new RuntimeException("failed writing data to file " + fileName, ioe);
+ }
+ }
+
public static void dumpFile(String fileName, byte[] data) {
FileOutputStream outStream;
try {
@@ -682,6 +700,21 @@
}
/**
+ * Returns true if the given {@code array} contains the given element.
+ *
+ * @param array {@code array} to check for {@code elem}
+ * @param elem {@code elem} to test for
+ * @return {@code true} if the given element is contained
+ */
+ public static boolean contains(int[] array, int elem) {
+ if (array == null) return false;
+ for (int i = 0; i < array.length; i++) {
+ if (elem == array[i]) return true;
+ }
+ return false;
+ }
+
+ /**
* Get object array from byte array.
*
* @param array Input byte array to be converted
@@ -779,6 +812,7 @@
validateJpegData(data, width, height, filePath);
break;
case ImageFormat.YUV_420_888:
+ case ImageFormat.YV12:
validateYuvData(data, width, height, format, image.getTimestamp(), filePath);
break;
case ImageFormat.RAW_SENSOR:
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
index 40db2d22c..9089a8c 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/ImageReaderTest.java
@@ -16,27 +16,39 @@
package android.hardware.camera2.cts;
-import static android.hardware.camera2.cts.CameraTestUtils.*;
-
import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
+import android.graphics.Color;
import android.graphics.ImageFormat;
-import android.hardware.camera2.CameraDevice;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
import android.hardware.camera2.CameraCharacteristics;
+import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
-import android.util.Size;
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
+import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.os.ConditionVariable;
import android.util.Log;
+import android.util.Size;
import android.view.Surface;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
+import static android.hardware.camera2.cts.CameraTestUtils.CAPTURE_RESULT_TIMEOUT_MS;
+import static android.hardware.camera2.cts.CameraTestUtils.SimpleCaptureCallback;
+import static android.hardware.camera2.cts.CameraTestUtils.SimpleImageReaderListener;
+import static android.hardware.camera2.cts.CameraTestUtils.dumpFile;
+import static android.hardware.camera2.cts.CameraTestUtils.getValueNotNull;
+
/**
* <p>Basic test for ImageReader APIs. It uses CameraDevice as producer, camera
* sends the data to the surface provided by imageReader. Below image formats
@@ -50,10 +62,16 @@
public class ImageReaderTest extends Camera2AndroidTestCase {
private static final String TAG = "ImageReaderTest";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
+ private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
// number of frame (for streaming requests) to be verified.
private static final int NUM_FRAME_VERIFIED = 2;
// Max number of images can be accessed simultaneously from ImageReader.
private static final int MAX_NUM_IMAGES = 5;
+ // Max difference allowed between YUV and JPEG patches. This tolerance is intentionally very
+ // generous to avoid false positives due to punch/saturation operations vendors apply to the
+ // JPEG outputs.
+ private static final double IMAGE_DIFFERENCE_TOLERANCE = 30;
private SimpleImageListener mListener;
@@ -194,6 +212,335 @@
}
}
+ /**
+ * Check that the center patches for YUV and JPEG outputs for the same frame match for each YUV
+ * resolution and format supported.
+ */
+ public void testAllOutputYUVResolutions() throws Exception {
+ for (String id : mCameraIds) {
+ try {
+ Log.v(TAG, "Testing all YUV image resolutions for camera " + id);
+ openDevice(id);
+
+ // Skip warmup on FULL mode devices.
+ int warmupCaptureNumber = (mStaticInfo.isHardwareLevelLegacy()) ?
+ MAX_NUM_IMAGES - 1 : 0;
+
+ // NV21 isn't supported by ImageReader.
+ final int[] YUVFormats = new int[] {ImageFormat.YUV_420_888, ImageFormat.YV12};
+
+ CameraCharacteristics.Key<StreamConfigurationMap> key =
+ CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP;
+ StreamConfigurationMap config = mStaticInfo.getValueFromKeyNonNull(key);
+ int[] supportedFormats = config.getOutputFormats();
+ List<Integer> supportedYUVFormats = new ArrayList<>();
+ for (int format : YUVFormats) {
+ if (CameraTestUtils.contains(supportedFormats, format)) {
+ supportedYUVFormats.add(format);
+ }
+ }
+
+ Size[] jpegSizes = mStaticInfo.getAvailableSizesForFormatChecked(ImageFormat.JPEG,
+ StaticMetadata.StreamDirection.Output);
+ assertFalse("JPEG output not supported for camera " + id +
+ ", at least one JPEG output is required.", jpegSizes.length == 0);
+
+ Size maxJpegSize = CameraTestUtils.getMaxSize(jpegSizes);
+
+ for (int format : supportedYUVFormats) {
+ Size[] targetCaptureSizes =
+ mStaticInfo.getAvailableSizesForFormatChecked(format,
+ StaticMetadata.StreamDirection.Output);
+
+ for (Size captureSz : targetCaptureSizes) {
+ if (VERBOSE) {
+ Log.v(TAG, "Testing yuv size " + captureSz + " and jpeg size "
+ + maxJpegSize + " for camera " + mCamera.getId());
+ }
+
+ ImageReader jpegReader = null;
+ ImageReader yuvReader = null;
+ try {
+ // Create YUV image reader
+ SimpleImageReaderListener yuvListener = new SimpleImageReaderListener();
+ yuvReader = createImageReader(captureSz, format, MAX_NUM_IMAGES,
+ yuvListener);
+ Surface yuvSurface = yuvReader.getSurface();
+
+ // Create JPEG image reader
+ SimpleImageReaderListener jpegListener =
+ new SimpleImageReaderListener();
+ jpegReader = createImageReader(maxJpegSize,
+ ImageFormat.JPEG, MAX_NUM_IMAGES, jpegListener);
+ Surface jpegSurface = jpegReader.getSurface();
+
+ // Setup session
+ List<Surface> outputSurfaces = new ArrayList<Surface>();
+ outputSurfaces.add(yuvSurface);
+ outputSurfaces.add(jpegSurface);
+ createSession(outputSurfaces);
+
+ // Warm up camera preview (mainly to give legacy devices time to do 3A).
+ CaptureRequest.Builder warmupRequest =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ warmupRequest.addTarget(yuvSurface);
+ assertNotNull("Fail to get CaptureRequest.Builder", warmupRequest);
+ SimpleCaptureCallback resultListener = new SimpleCaptureCallback();
+
+ for (int i = 0; i < warmupCaptureNumber; i++) {
+ startCapture(warmupRequest.build(), /*repeating*/false,
+ resultListener, mHandler);
+ }
+ for (int i = 0; i < warmupCaptureNumber; i++) {
+ resultListener.getCaptureResult(CAPTURE_WAIT_TIMEOUT_MS);
+ Image image = yuvListener.getImage(CAPTURE_WAIT_TIMEOUT_MS);
+ image.close();
+ }
+
+ // Capture image.
+ CaptureRequest.Builder mainRequest =
+ mCamera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
+ for (Surface s : outputSurfaces) {
+ mainRequest.addTarget(s);
+ }
+
+ startCapture(mainRequest.build(), /*repeating*/false, resultListener,
+ mHandler);
+
+ // Verify capture result and images
+ resultListener.getCaptureResult(CAPTURE_WAIT_TIMEOUT_MS);
+
+ Image yuvImage = yuvListener.getImage(CAPTURE_WAIT_TIMEOUT_MS);
+ Image jpegImage = jpegListener.getImage(CAPTURE_WAIT_TIMEOUT_MS);
+
+ //Validate captured images.
+ CameraTestUtils.validateImage(yuvImage, captureSz.getWidth(),
+ captureSz.getHeight(), format, /*filePath*/null);
+ CameraTestUtils.validateImage(jpegImage, maxJpegSize.getWidth(),
+ maxJpegSize.getHeight(), ImageFormat.JPEG, /*filePath*/null);
+
+ // Compare the image centers.
+ RectF jpegDimens = new RectF(0, 0, jpegImage.getWidth(),
+ jpegImage.getHeight());
+ RectF yuvDimens = new RectF(0, 0, yuvImage.getWidth(),
+ yuvImage.getHeight());
+
+ // Find scale difference between YUV and JPEG output
+ Matrix m = new Matrix();
+ m.setRectToRect(yuvDimens, jpegDimens, Matrix.ScaleToFit.START);
+ RectF scaledYuv = new RectF();
+ m.mapRect(scaledYuv, yuvDimens);
+ float scale = scaledYuv.width() / yuvDimens.width();
+
+ final int PATCH_DIMEN = 40; // pixels in YUV
+
+ // Find matching square patch of pixels in YUV and JPEG output
+ RectF tempPatch = new RectF(0, 0, PATCH_DIMEN, PATCH_DIMEN);
+ tempPatch.offset(yuvDimens.centerX() - tempPatch.centerX(),
+ yuvDimens.centerY() - tempPatch.centerY());
+ Rect yuvPatch = new Rect();
+ tempPatch.roundOut(yuvPatch);
+
+ tempPatch.set(0, 0, PATCH_DIMEN * scale, PATCH_DIMEN * scale);
+ tempPatch.offset(jpegDimens.centerX() - tempPatch.centerX(),
+ jpegDimens.centerY() - tempPatch.centerY());
+ Rect jpegPatch = new Rect();
+ tempPatch.roundOut(jpegPatch);
+
+ // Decode center patches
+ int[] yuvColors = convertPixelYuvToRgba(yuvPatch.width(),
+ yuvPatch.height(), yuvPatch.left, yuvPatch.top, yuvImage);
+ Bitmap yuvBmap = Bitmap.createBitmap(yuvColors, yuvPatch.width(),
+ yuvPatch.height(), Bitmap.Config.ARGB_8888);
+
+ byte[] compressedJpegData = CameraTestUtils.getDataFromImage(jpegImage);
+ BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+ compressedJpegData, /*offset*/0, compressedJpegData.length,
+ /*isShareable*/true);
+ BitmapFactory.Options opt = new BitmapFactory.Options();
+ opt.inPreferredConfig = Bitmap.Config.ARGB_8888;
+ Bitmap fullSizeJpegBmap = decoder.decodeRegion(jpegPatch, opt);
+ Bitmap jpegBmap = Bitmap.createScaledBitmap(fullSizeJpegBmap,
+ yuvPatch.width(), yuvPatch.height(), /*filter*/true);
+
+ // Compare two patches using average of per-pixel differences
+ double difference = findDifferenceMetric(yuvBmap, jpegBmap);
+
+ Log.i(TAG, "Difference for resolution " + captureSz + " is: " +
+ difference);
+ if (difference > IMAGE_DIFFERENCE_TOLERANCE) {
+ // Dump files if running in verbose mode
+ if (DEBUG) {
+ String jpegFileName = DEBUG_FILE_NAME_BASE + "/" + captureSz +
+ "_jpeg.jpg";
+ dumpFile(jpegFileName, jpegBmap);
+ String fullSizeJpegFileName = DEBUG_FILE_NAME_BASE + "/" +
+ captureSz + "_full_jpeg.jpg";
+ dumpFile(fullSizeJpegFileName, compressedJpegData);
+ String yuvFileName = DEBUG_FILE_NAME_BASE + "/" + captureSz +
+ "_yuv.jpg";
+ dumpFile(yuvFileName, yuvBmap);
+ String fullSizeYuvFileName = DEBUG_FILE_NAME_BASE + "/" +
+ captureSz + "_full_yuv.jpg";
+ int[] fullYUVColors = convertPixelYuvToRgba(yuvImage.getWidth(),
+ yuvImage.getHeight(), 0, 0, yuvImage);
+ Bitmap fullYUVBmap = Bitmap.createBitmap(fullYUVColors,
+ yuvImage.getWidth(), yuvImage.getHeight(),
+ Bitmap.Config.ARGB_8888);
+ dumpFile(fullSizeYuvFileName, fullYUVBmap);
+ }
+ fail("Camera " + mCamera.getId() + ": YUV and JPEG image at " +
+ "capture size " + captureSz + " for the same frame are " +
+ "not similar, center patches have difference metric of " +
+ difference);
+ }
+
+ // Stop capture, delete the streams.
+ stopCapture(/*fast*/false);
+ } finally {
+ closeImageReader(jpegReader);
+ jpegReader = null;
+ closeImageReader(yuvReader);
+ yuvReader = null;
+ }
+ }
+ }
+
+ } finally {
+ closeDevice(id);
+ }
+ }
+ }
+
+ /**
+ * Find the difference between two bitmaps using average of per-pixel differences.
+ *
+ * @param a first {@link Bitmap}.
+ * @param b second {@link Bitmap}.
+ * @return the difference.
+ */
+ private static double findDifferenceMetric(Bitmap a, Bitmap b) {
+ if (a.getWidth() != b.getWidth() || a.getHeight() != b.getHeight()) {
+ throw new IllegalArgumentException("Bitmap dimensions for arguments do not match a=" +
+ a.getWidth() + "x" + a.getHeight() + ", b=" + b.getWidth() + "x" +
+ b.getHeight());
+ }
+ // TODO: Optimize this in renderscript to avoid copy.
+ int[] aPixels = new int[a.getHeight() * a.getWidth()];
+ int[] bPixels = new int[aPixels.length];
+ a.getPixels(aPixels, /*offset*/0, /*stride*/a.getWidth(), /*x*/0, /*y*/0, a.getWidth(),
+ a.getHeight());
+ b.getPixels(bPixels, /*offset*/0, /*stride*/b.getWidth(), /*x*/0, /*y*/0, b.getWidth(),
+ b.getHeight());
+ double diff = 0;
+ for (int i = 0; i < aPixels.length; i++) {
+ int aPix = aPixels[i];
+ int bPix = bPixels[i];
+
+ diff += Math.abs(Color.red(aPix) - Color.red(bPix)); // red
+ diff += Math.abs(Color.green(aPix) - Color.green(bPix)); // green
+ diff += Math.abs(Color.blue(aPix) - Color.blue(bPix)); // blue
+ }
+ diff /= (aPixels.length * 3);
+ return diff;
+ }
+
+ /**
+ * Convert a rectangular patch in a YUV image to an ARGB color array.
+ *
+ * @param w width of the patch.
+ * @param h height of the patch.
+ * @param wOffset offset of the left side of the patch.
+ * @param hOffset offset of the top of the patch.
+ * @param yuvImage a YUV image to select a patch from.
+ * @return the image patch converted to RGB as an ARGB color array.
+ */
+ private static int[] convertPixelYuvToRgba(int w, int h, int wOffset, int hOffset,
+ Image yuvImage) {
+ final int CHANNELS = 3; // yuv
+ final float COLOR_RANGE = 255f;
+
+ assertTrue("Invalid argument to convertPixelYuvToRgba",
+ w > 0 && h > 0 && wOffset >= 0 && hOffset >= 0);
+ assertNotNull(yuvImage);
+
+ int imageFormat = yuvImage.getFormat();
+ assertTrue("YUV image must have YUV-type format",
+ imageFormat == ImageFormat.YUV_420_888 || imageFormat == ImageFormat.YV12 ||
+ imageFormat == ImageFormat.NV21);
+
+ int height = yuvImage.getHeight();
+ int width = yuvImage.getWidth();
+
+ Rect imageBounds = new Rect(/*left*/0, /*top*/0, /*right*/width, /*bottom*/height);
+ Rect crop = new Rect(/*left*/wOffset, /*top*/hOffset, /*right*/wOffset + w,
+ /*bottom*/hOffset + h);
+ assertTrue("Output rectangle" + crop + " must lie within image bounds " + imageBounds,
+ imageBounds.contains(crop));
+ Image.Plane[] planes = yuvImage.getPlanes();
+
+ Image.Plane yPlane = planes[0];
+ Image.Plane cbPlane = planes[1];
+ Image.Plane crPlane = planes[2];
+
+ ByteBuffer yBuf = yPlane.getBuffer();
+ int yPixStride = yPlane.getPixelStride();
+ int yRowStride = yPlane.getRowStride();
+ ByteBuffer cbBuf = cbPlane.getBuffer();
+ int cbPixStride = cbPlane.getPixelStride();
+ int cbRowStride = cbPlane.getRowStride();
+ ByteBuffer crBuf = crPlane.getBuffer();
+ int crPixStride = crPlane.getPixelStride();
+ int crRowStride = crPlane.getRowStride();
+
+ int[] output = new int[w * h];
+
+ // TODO: Optimize this with renderscript intrinsics
+ byte[] yRow = new byte[yPixStride * w];
+ byte[] cbRow = new byte[cbPixStride * w / 2];
+ byte[] crRow = new byte[crPixStride * w / 2];
+ yBuf.mark();
+ cbBuf.mark();
+ crBuf.mark();
+ int initialYPos = yBuf.position();
+ int initialCbPos = cbBuf.position();
+ int initialCrPos = crBuf.position();
+ int outputPos = 0;
+ for (int i = hOffset; i < hOffset + h; i++) {
+ yBuf.position(initialYPos + i * yRowStride + wOffset * yPixStride);
+ yBuf.get(yRow);
+ if ((i & 1) == (hOffset & 1)) {
+ cbBuf.position(initialCbPos + (i / 2) * cbRowStride + wOffset * cbPixStride / 2);
+ cbBuf.get(cbRow);
+ crBuf.position(initialCrPos + (i / 2) * crRowStride + wOffset * crPixStride / 2);
+ crBuf.get(crRow);
+ }
+ for (int j = 0, yPix = 0, crPix = 0, cbPix = 0; j < w; j++, yPix += yPixStride) {
+ float y = yRow[yPix] & 0xFF;
+ float cb = cbRow[cbPix] & 0xFF;
+ float cr = crRow[crPix] & 0xFF;
+
+ // convert YUV -> RGB (from JFIF's "Conversion to and from RGB" section)
+ int r = (int) Math.max(0.0f, Math.min(COLOR_RANGE, y + 1.402f * (cr - 128)));
+ int g = (int) Math.max(0.0f,
+ Math.min(COLOR_RANGE, y - 0.34414f * (cb - 128) - 0.71414f * (cr - 128)));
+ int b = (int) Math.max(0.0f, Math.min(COLOR_RANGE, y + 1.772f * (cb - 128)));
+
+ // Convert to ARGB pixel color (use opaque alpha)
+ output[outputPos++] = Color.rgb(r, g, b);
+
+ if ((j & 1) == 1) {
+ crPix += crPixStride;
+ cbPix += cbPixStride;
+ }
+ }
+ }
+ yBuf.rewind();
+ cbBuf.rewind();
+ crBuf.rewind();
+
+ return output;
+ }
/**
* Test capture a given format stream with yuv stream simultaneously.
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
index 386696c..45d6910 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RecordingTest.java
@@ -30,8 +30,8 @@
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaCodecList;
+import android.media.MediaExtractor;
import android.media.MediaFormat;
-import android.media.MediaPlayer;
import android.media.MediaRecorder;
import android.os.Environment;
import android.os.SystemClock;
@@ -66,15 +66,15 @@
private static final int VIDEO_FRAME_RATE = 30;
private final String VIDEO_FILE_PATH = Environment.getExternalStorageDirectory().getPath();
private static final int[] mCamcorderProfileList = {
+ CamcorderProfile.QUALITY_HIGH,
CamcorderProfile.QUALITY_2160P,
CamcorderProfile.QUALITY_1080P,
- CamcorderProfile.QUALITY_480P,
CamcorderProfile.QUALITY_720P,
+ CamcorderProfile.QUALITY_480P,
CamcorderProfile.QUALITY_CIF,
- CamcorderProfile.QUALITY_LOW,
- CamcorderProfile.QUALITY_HIGH,
CamcorderProfile.QUALITY_QCIF,
CamcorderProfile.QUALITY_QVGA,
+ CamcorderProfile.QUALITY_LOW,
};
private static final int MAX_VIDEO_SNAPSHOT_IMAGES = 5;
private static final int BURST_VIDEO_SNAPSHOT_NUM = 3;
@@ -119,7 +119,7 @@
initSupportedVideoSize(mCameraIds[i]);
- basicRecordingTestByCamera();
+ basicRecordingTestByCamera(mCamcorderProfileList);
} finally {
closeDevice();
releaseRecorder();
@@ -222,6 +222,53 @@
}
/**
+ * <p>
+ * Test recording framerate accuracy when switching from low FPS to high FPS.
+ * </p>
+ * <p>
+ * This test first record a video with profile of lowest framerate then record a video with
+ * profile of highest framerate. Make sure that the video framerate are still accurate.
+ * </p>
+ */
+ public void testRecordingFramerateLowToHigh() throws Exception {
+ for (int i = 0; i < mCameraIds.length; i++) {
+ try {
+ Log.i(TAG, "Testing basic recording for camera " + mCameraIds[i]);
+ // Re-use the MediaRecorder object for the same camera device.
+ mMediaRecorder = new MediaRecorder();
+ openDevice(mCameraIds[i]);
+
+ initSupportedVideoSize(mCameraIds[i]);
+
+ int minFpsProfileId = -1, minFps = 1000;
+ int maxFpsProfileId = -1, maxFps = 0;
+ int cameraId = Integer.valueOf(mCamera.getId());
+
+ for (int profileId : mCamcorderProfileList) {
+ if (!CamcorderProfile.hasProfile(cameraId, profileId)) {
+ continue;
+ }
+ CamcorderProfile profile = CamcorderProfile.get(cameraId, profileId);
+ if (profile.videoFrameRate < minFps) {
+ minFpsProfileId = profileId;
+ minFps = profile.videoFrameRate;
+ }
+ if (profile.videoFrameRate > maxFps) {
+ maxFpsProfileId = profileId;
+ maxFps = profile.videoFrameRate;
+ }
+ }
+
+ int camcorderProfileList[] = new int[] {minFpsProfileId, maxFpsProfileId};
+ basicRecordingTestByCamera(camcorderProfileList);
+ } finally {
+ closeDevice();
+ releaseRecorder();
+ }
+ }
+ }
+
+ /**
* Test slow motion recording where capture rate (camera output) is different with
* video (playback) frame rate for each camera if high speed recording is supported
* by both camera and encoder.
@@ -389,8 +436,8 @@
* Test camera recording by using each available CamcorderProfile for a
* given camera. preview size is set to the video size.
*/
- private void basicRecordingTestByCamera() throws Exception {
- for (int profileId : mCamcorderProfileList) {
+ private void basicRecordingTestByCamera(int[] camcorderProfileList) throws Exception {
+ for (int profileId : camcorderProfileList) {
int cameraId = Integer.valueOf(mCamera.getId());
if (!CamcorderProfile.hasProfile(cameraId, profileId) ||
allowedUnsupported(cameraId, profileId)) {
@@ -658,10 +705,11 @@
// Stop recording and preview
stopRecording(/* useMediaRecorder */true);
- int duration = (int) (SystemClock.elapsedRealtime() - startTime);
+ int durationMs = (int) (resultListener.getTotalNumFrames() * 1000.0f /
+ profile.videoFrameRate);
// Validation recorded video
- validateRecording(videoSz, duration);
+ validateRecording(videoSz, durationMs);
if (burstTest) {
for (int i = 0; i < BURST_VIDEO_SNAPSHOT_NUM; i++) {
@@ -854,14 +902,28 @@
File outFile = new File(mOutMediaFileName);
assertTrue("No video is recorded", outFile.exists());
- MediaPlayer mediaPlayer = new MediaPlayer();
+ MediaExtractor extractor = new MediaExtractor();
try {
- mediaPlayer.setDataSource(mOutMediaFileName);
- mediaPlayer.prepare();
- Size videoSz = new Size(mediaPlayer.getVideoWidth(), mediaPlayer.getVideoHeight());
+ extractor.setDataSource(mOutMediaFileName);
+ long durationUs = 0;
+ int width = -1, height = -1;
+ int numTracks = extractor.getTrackCount();
+ final String VIDEO_MIME_TYPE = "video";
+ for (int i = 0; i < numTracks; i++) {
+ MediaFormat format = extractor.getTrackFormat(i);
+ String mime = format.getString(MediaFormat.KEY_MIME);
+ if (mime.contains(VIDEO_MIME_TYPE)) {
+ Log.i(TAG, "video format is: " + format.toString());
+ durationUs = format.getLong(MediaFormat.KEY_DURATION);
+ width = format.getInteger(MediaFormat.KEY_WIDTH);
+ height = format.getInteger(MediaFormat.KEY_HEIGHT);
+ break;
+ }
+ }
+ Size videoSz = new Size(width, height);
assertTrue("Video size doesn't match, expected " + sz.toString() +
" got " + videoSz.toString(), videoSz.equals(sz));
- int duration = mediaPlayer.getDuration();
+ int duration = (int) (durationUs / 1000);
if (VERBOSE) {
Log.v(TAG, String.format("Video duration: recorded %dms, expected %dms",
duration, durationMs));
@@ -870,12 +932,12 @@
// TODO: Don't skip this for video snapshot
if (!mStaticInfo.isHardwareLevelLegacy()) {
assertTrue(String.format(
- "Camera %s: Video duration doesn't match: recorded %dms, expected %dms",
- mCamera.getId(), duration,
- durationMs), Math.abs(duration - durationMs) < DURATION_MARGIN_MS);
+ "Camera %s: Video duration doesn't match: recorded %dms, expected %dms.",
+ mCamera.getId(), duration, durationMs),
+ Math.abs(duration - durationMs) < DURATION_MARGIN_MS);
}
} finally {
- mediaPlayer.release();
+ extractor.release();
if (!DEBUG_DUMP) {
outFile.delete();
}
diff --git a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
index 004c7da..397407b 100644
--- a/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
+++ b/tests/tests/hardware/src/android/hardware/camera2/cts/RobustnessTest.java
@@ -28,7 +28,6 @@
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.cts.CameraTestUtils;
import android.hardware.camera2.cts.helpers.StaticMetadata;
import android.hardware.camera2.cts.testcases.Camera2AndroidTestCase;
import android.media.CamcorderProfile;
@@ -42,6 +41,7 @@
import java.util.ArrayList;
import java.util.List;
+import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.*;
/**
@@ -50,11 +50,14 @@
public class RobustnessTest extends Camera2AndroidTestCase {
private static final String TAG = "RobustnessTest";
- private static final int FAILED_CONFIGURE_TIMEOUT = 5000; //ms
+ private static final int CONFIGURE_TIMEOUT = 5000; //ms
+ private static final int CAPTURE_TIMEOUT = 1000; //ms
/**
- * Test that a {@link CameraCaptureSession} configured with a {@link Surface} with invalid
- * dimensions fails gracefully.
+ * Test that a {@link CameraCaptureSession} can be configured with a {@link Surface} containing
+ * a dimension other than one of the supported output dimensions. The buffers produced into
+ * this surface are expected have the dimensions of the closest possible buffer size in the
+ * available stream configurations for a surface with this format.
*/
public void testBadSurfaceDimensions() throws Exception {
for (String id : mCameraIds) {
@@ -62,9 +65,21 @@
Log.i(TAG, "Testing Camera " + id);
openDevice(id);
- // Setup Surface with unconfigured dimensions.
- SurfaceTexture surfaceTexture = new SurfaceTexture(0);
- Surface surface = new Surface(surfaceTexture);
+ // Find some size not supported by the camera
+ Size weirdSize = new Size(643, 577);
+ int count = 0;
+ while(mOrderedPreviewSizes.contains(weirdSize)) {
+ // Really, they can't all be supported...
+ weirdSize = new Size(weirdSize.getWidth() + 1, weirdSize.getHeight() + 1);
+ count++;
+ assertTrue("Too many exotic YUV_420_888 resolutions supported.", count < 100);
+ }
+
+ // Setup imageReader with invalid dimension
+ ImageReader imageReader = ImageReader.newInstance(weirdSize.getWidth(),
+ weirdSize.getHeight(), ImageFormat.YUV_420_888, 3);
+
+ Surface surface = imageReader.getSurface();
List<Surface> surfaces = new ArrayList<>();
surfaces.add(surface);
@@ -78,13 +93,34 @@
// Check that correct session callback is hit.
CameraCaptureSession.StateCallback sessionListener =
mock(CameraCaptureSession.StateCallback.class);
- mCamera.createCaptureSession(surfaces, sessionListener, mHandler);
- verify(sessionListener, timeout(FAILED_CONFIGURE_TIMEOUT).atLeastOnce()).
- onConfigureFailed(any(CameraCaptureSession.class));
- verify(sessionListener, never()).onConfigured(any(CameraCaptureSession.class));
+ CameraCaptureSession session = CameraTestUtils.configureCameraSession(mCamera,
+ surfaces, sessionListener, mHandler);
+
+ verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
+ onConfigured(any(CameraCaptureSession.class));
+ verify(sessionListener, timeout(CONFIGURE_TIMEOUT).atLeastOnce()).
+ onReady(any(CameraCaptureSession.class));
+ verify(sessionListener, never()).onConfigureFailed(any(CameraCaptureSession.class));
verify(sessionListener, never()).onActive(any(CameraCaptureSession.class));
- verify(sessionListener, never()).onReady(any(CameraCaptureSession.class));
verify(sessionListener, never()).onClosed(any(CameraCaptureSession.class));
+
+ CameraCaptureSession.CaptureCallback captureListener =
+ mock(CameraCaptureSession.CaptureCallback.class);
+ session.capture(request.build(), captureListener, mHandler);
+
+ verify(captureListener, timeout(CAPTURE_TIMEOUT).atLeastOnce()).
+ onCaptureCompleted(any(CameraCaptureSession.class),
+ any(CaptureRequest.class), any(TotalCaptureResult.class));
+ verify(captureListener, never()).onCaptureFailed(any(CameraCaptureSession.class),
+ any(CaptureRequest.class), any(CaptureFailure.class));
+
+ Image image = imageReader.acquireLatestImage();
+ int imageWidth = image.getWidth();
+ int imageHeight = image.getHeight();
+ Size actualSize = new Size(imageWidth, imageHeight);
+
+ assertTrue("Camera does not contain outputted image resolution " + actualSize,
+ mOrderedPreviewSizes.contains(actualSize));
} finally {
closeDevice(id);
}
@@ -327,16 +363,6 @@
}
}
- private final class ImageCloser implements ImageReader.OnImageAvailableListener {
- @Override
- public void onImageAvailable(ImageReader reader) {
- Image image = reader.acquireLatestImage();
- if (image != null) {
- image.close();
- }
- }
- }
-
private void testOutputCombination(String cameraId, int[] config, MaxOutputSizes maxSizes)
throws Exception {
@@ -346,7 +372,7 @@
final int TIMEOUT_FOR_RESULT_MS = 1000;
final int MIN_RESULT_COUNT = 3;
- ImageCloser imageCloser = new ImageCloser();
+ ImageDropperListener imageDropperListener = new ImageDropperListener();
// Set up outputs
List<Object> outputTargets = new ArrayList<>();
List<Surface> outputSurfaces = new ArrayList<>();
@@ -372,7 +398,7 @@
Size targetSize = maxSizes.maxJpegSizes[sizeLimit];
ImageReader target = ImageReader.newInstance(
targetSize.getWidth(), targetSize.getHeight(), JPEG, MIN_RESULT_COUNT);
- target.setOnImageAvailableListener(imageCloser, mHandler);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
outputTargets.add(target);
outputSurfaces.add(target.getSurface());
jpegTargets.add(target);
@@ -382,7 +408,7 @@
Size targetSize = maxSizes.maxYuvSizes[sizeLimit];
ImageReader target = ImageReader.newInstance(
targetSize.getWidth(), targetSize.getHeight(), YUV, MIN_RESULT_COUNT);
- target.setOnImageAvailableListener(imageCloser, mHandler);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
outputTargets.add(target);
outputSurfaces.add(target.getSurface());
yuvTargets.add(target);
@@ -392,7 +418,7 @@
Size targetSize = maxSizes.maxRawSize;
ImageReader target = ImageReader.newInstance(
targetSize.getWidth(), targetSize.getHeight(), RAW, MIN_RESULT_COUNT);
- target.setOnImageAvailableListener(imageCloser, mHandler);
+ target.setOnImageAvailableListener(imageDropperListener, mHandler);
outputTargets.add(target);
outputSurfaces.add(target.getSurface());
rawTargets.add(target);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
index 08d06c6..87c74ee 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTest.java
@@ -327,7 +327,7 @@
HandlerThread handlerThread = new HandlerThread("sensorThread");
handlerThread.start();
Handler handler = new Handler(handlerThread.getLooper());
- TestSensorEventListener listener = new TestSensorEventListener(handler);
+ TestSensorEventListener listener = new TestSensorEventListener(environment, handler);
sensorManager.registerListener(listener);
listener.waitForEvents(1);
diff --git a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
index 6454678..8dba5d6 100644
--- a/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/cts/SensorTestCase.java
@@ -26,7 +26,7 @@
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.SensorTestStateNotSupportedException;
import android.hardware.cts.helpers.TestSensorEnvironment;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -35,13 +35,13 @@
*/
public abstract class SensorTestCase extends AndroidTestCase {
// TODO: consolidate all log tags
- protected final String LOG_TAG = "TestRunner";
+ protected static final String LOG_TAG = "TestRunner";
/**
* By default tests need to run in a {@link TestSensorEnvironment} that assumes each sensor is
* running with a load of several listeners, requesting data at different rates.
*
- * In a better world the component acting as builder of {@link ISensorOperation} would compute
+ * In a better world the component acting as builder of {@link SensorOperation} would compute
* this value based on the tests composed.
*
* Ideally, each {@link Sensor} object would expose this information to clients.
@@ -51,9 +51,9 @@
protected SensorTestCase() {}
@Override
- public void runTest() throws Throwable {
+ public void runBare() throws Throwable {
try {
- super.runTest();
+ super.runBare();
} catch (SensorTestStateNotSupportedException e) {
// the sensor state is not supported in the device, log a warning and skip the test
Log.w(LOG_TAG, e.getMessage());
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
deleted file mode 100644
index 3bedc05..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/CollectingSensorEventListener.java
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers;
-
-import android.hardware.SensorEvent;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-import java.util.concurrent.TimeUnit;
-
-/**
- * A {@link TestSensorEventListener} which collects events to be processed after the test is run.
- * This should only be used for short tests.
- */
-public class CollectingSensorEventListener extends TestSensorEventListener {
- private final ArrayList<TestSensorEvent> mSensorEventsList = new ArrayList<TestSensorEvent>();
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onSensorChanged(SensorEvent event) {
- super.onSensorChanged(event);
- synchronized (mSensorEventsList) {
- mSensorEventsList.add(new TestSensorEvent(event));
- }
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Clears the event queue before starting.
- * </p>
- */
- @Override
- public void waitForEvents(int eventCount) throws InterruptedException {
- clearEvents();
- super.waitForEvents(eventCount);
- }
-
- /**
- * {@inheritDoc}
- * <p>
- * Clears the event queue before starting.
- * </p>
- */
- @Override
- public void waitForEvents(long duration, TimeUnit timeUnit) throws InterruptedException {
- clearEvents();
- super.waitForEvents(duration, timeUnit);
- }
-
- /**
- * Get the {@link TestSensorEvent} array from the event queue.
- */
- public List<TestSensorEvent> getEvents() {
- synchronized (mSensorEventsList) {
- return Collections.unmodifiableList(mSensorEventsList);
- }
- }
-
- /**
- * Clear the event queue.
- */
- public void clearEvents() {
- synchronized (mSensorEventsList) {
- mSensorEventsList.clear();
- }
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
index 0f84ee6..d3dcf37 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorCalibratedUncalibratedVerifier.java
@@ -35,6 +35,8 @@
private final TestSensorManager mCalibratedSensorManager;
private final TestSensorManager mUncalibratedSensorManager;
+ private final TestSensorEventListener mCalibratedTestListener;
+ private final TestSensorEventListener mUncalibratedTestListener;
private final float mThreshold;
public SensorCalibratedUncalibratedVerifier(
@@ -43,6 +45,8 @@
float threshold) {
mCalibratedSensorManager = new TestSensorManager(calibratedEnvironment);
mUncalibratedSensorManager = new TestSensorManager(uncalibratedEnvironment);
+ mCalibratedTestListener = new TestSensorEventListener(calibratedEnvironment);
+ mUncalibratedTestListener = new TestSensorEventListener(uncalibratedEnvironment);
mThreshold = threshold;
}
@@ -50,11 +54,8 @@
* Executes the operation: it collects the data and run verifications on it.
*/
public void execute() throws Throwable {
- CollectingSensorEventListener calibratedTestListener = new CollectingSensorEventListener();
- CollectingSensorEventListener uncalibratedTestListener =
- new CollectingSensorEventListener();
- mCalibratedSensorManager.registerListener(calibratedTestListener);
- mUncalibratedSensorManager.registerListener(uncalibratedTestListener);
+ mCalibratedSensorManager.registerListener(mCalibratedTestListener);
+ mUncalibratedSensorManager.registerListener(mUncalibratedTestListener);
Thread.sleep(TimeUnit.SECONDS.toMillis(10));
@@ -62,8 +63,8 @@
mUncalibratedSensorManager.unregisterListener();
verifyMeasurements(
- calibratedTestListener.getEvents(),
- uncalibratedTestListener.getEvents(),
+ mCalibratedTestListener.getCollectedEvents(),
+ mUncalibratedTestListener.getCollectedEvents(),
mThreshold);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
index 6f98e86..a7ad94a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/SensorStats.java
@@ -17,7 +17,7 @@
package android.hardware.cts.helpers;
import android.hardware.Sensor;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import android.util.Log;
import java.io.BufferedWriter;
@@ -34,7 +34,7 @@
import java.util.Set;
/**
- * Class used to store stats related to {@link ISensorOperation}s. Sensor stats may be linked
+ * Class used to store stats related to {@link SensorOperation}s. Sensor stats may be linked
* together so that they form a tree.
*/
public class SensorStats {
@@ -55,8 +55,8 @@
public static final String STANDARD_DEVIATION_KEY = "standard_deviation";
public static final String MAGNITUDE_KEY = "magnitude";
- private final Map<String, Object> mValues = new HashMap<String, Object>();
- private final Map<String, SensorStats> mSensorStats = new HashMap<String, SensorStats>();
+ private final Map<String, Object> mValues = new HashMap<>();
+ private final Map<String, SensorStats> mSensorStats = new HashMap<>();
/**
* Add a value.
@@ -73,7 +73,7 @@
/**
* Add a nested {@link SensorStats}. This is useful for keeping track of stats in a
- * {@link ISensorOperation} tree.
+ * {@link SensorOperation} tree.
*
* @param key the key
* @param stats the sub {@link SensorStats} object.
@@ -104,13 +104,13 @@
/**
* Flattens the map and all sub {@link SensorStats} objects. Keys will be flattened using
* {@value #DELIMITER}. For example, if a sub {@link SensorStats} is added with key
- * {@code "key1"} containing the key value pair {@code ("key2", "value")}, the flattened map
- * will contain the entry {@code ("key1__key2", "value")}.
+ * {@code "key1"} containing the key value pair {@code \("key2", "value"\)}, the flattened map
+ * will contain the entry {@code \("key1__key2", "value"\)}.
*
* @return a {@link Map} containing all stats from the value and sub {@link SensorStats}.
*/
public synchronized Map<String, Object> flatten() {
- final Map<String, Object> flattenedMap = new HashMap<String, Object>(mValues);
+ final Map<String, Object> flattenedMap = new HashMap<>(mValues);
for (Entry<String, SensorStats> statsEntry : mSensorStats.entrySet()) {
for (Entry<String, Object> valueEntry : statsEntry.getValue().flatten().entrySet()) {
String key = statsEntry.getKey() + DELIMITER + valueEntry.getKey();
@@ -166,7 +166,7 @@
}
private static List<String> getSortedKeys(Map<String, Object> flattenedStats) {
- List<String> keys = new ArrayList<String>(flattenedStats.keySet());
+ List<String> keys = new ArrayList<>(flattenedStats.keySet());
Collections.sort(keys);
return keys;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
index 5be30a4..d59ea7a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEnvironment.java
@@ -19,12 +19,12 @@
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorManager;
-import android.hardware.cts.helpers.sensoroperations.ISensorOperation;
+import android.hardware.cts.helpers.sensoroperations.SensorOperation;
import java.util.concurrent.TimeUnit;
/**
- * A class that encapsulates base environment information for the {@link ISensorOperation}.
+ * A class that encapsulates base environment information for the {@link SensorOperation}.
* The environment is self contained and carries its state around all the sensor test framework.
*/
public class TestSensorEnvironment {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
index ae36e6a..6c313d2 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorEventListener.java
@@ -24,12 +24,13 @@
import android.os.Handler;
import android.os.Looper;
import android.os.SystemClock;
-import android.util.Log;
import java.util.ArrayList;
-import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
/**
* A {@link SensorEventListener2} which performs operations such as waiting for a specific number of
@@ -42,74 +43,35 @@
private static final long EVENT_TIMEOUT_US = TimeUnit.SECONDS.toMicros(5);
private static final long FLUSH_TIMEOUT_US = TimeUnit.SECONDS.toMicros(10);
- private final ArrayList<CountDownLatch> mEventLatches = new ArrayList<CountDownLatch>();
- private final ArrayList<CountDownLatch> mFlushLatches = new ArrayList<CountDownLatch>();
+ private final List<TestSensorEvent> mCollectedEvents = new ArrayList<>();
+ private final List<CountDownLatch> mEventLatches = new ArrayList<>();
+ private final List<CountDownLatch> mFlushLatches = new ArrayList<>();
+ private final AtomicInteger mEventsReceivedOutsideHandler = new AtomicInteger();
- private final SensorEventListener2 mListener;
private final Handler mHandler;
+ private final TestSensorEnvironment mEnvironment;
- private volatile boolean mEventsReceivedInHandler = true;
- private volatile TestSensorEnvironment mEnvironment;
- private volatile boolean mLogEvents;
+ /**
+ * @deprecated Use {@link TestSensorEventListener(TestSensorEnvironment)}.
+ */
+ @Deprecated
+ public TestSensorEventListener() {
+ this(null /* environment */);
+ }
/**
* Construct a {@link TestSensorEventListener}.
*/
- public TestSensorEventListener() {
- this(null /* listener */, null /* handler */);
+ public TestSensorEventListener(TestSensorEnvironment environment) {
+ this(environment, null /* handler */);
}
/**
- * Construct a {@link TestSensorEventListener} with a {@link Handler}.
+ * Construct a {@link TestSensorEventListener}.
*/
- public TestSensorEventListener(Handler handler) {
- this(null /* listener */, handler);
- }
-
- /**
- * Construct a {@link TestSensorEventListener} that wraps a {@link SensorEventListener2}.
- */
- public TestSensorEventListener(SensorEventListener2 listener) {
- this(listener, null /* handler */);
- }
-
- /**
- * Construct a {@link TestSensorEventListener} that wraps a {@link SensorEventListener2}, and it
- * has a {@link Handler}.
- */
- public TestSensorEventListener(SensorEventListener2 listener, Handler handler) {
- if (listener != null) {
- mListener = listener;
- } else {
- // use a Null Object to simplify handling the listener
- mListener = new SensorEventListener2() {
- public void onFlushCompleted(Sensor sensor) {}
- public void onSensorChanged(SensorEvent sensorEvent) {}
- public void onAccuracyChanged(Sensor sensor, int i) {}
- };
- }
- mHandler = handler;
- }
-
- /**
- * @return The handler (if any) associated with the instance.
- */
- public Handler getHandler() {
- return mHandler;
- }
-
- /**
- * Set the sensor, rate, and batch report latency used for the assertions.
- */
- public void setEnvironment(TestSensorEnvironment environment) {
+ public TestSensorEventListener(TestSensorEnvironment environment, Handler handler) {
mEnvironment = environment;
- }
-
- /**
- * Set whether or not to log events
- */
- public void setLogEvents(boolean log) {
- mLogEvents = log;
+ mHandler = handler;
}
/**
@@ -117,15 +79,10 @@
*/
@Override
public void onSensorChanged(SensorEvent event) {
+ long timestampNs = SystemClock.elapsedRealtimeNanos();
checkHandler();
- mListener.onSensorChanged(event);
- if (mLogEvents) {
- Log.v(LOG_TAG, String.format(
- "Sensor %d: sensor_timestamp=%dns, received_timestamp=%dns, values=%s",
- mEnvironment.getSensor().getType(),
- event.timestamp,
- SystemClock.elapsedRealtimeNanos(),
- Arrays.toString(event.values)));
+ synchronized (mCollectedEvents) {
+ mCollectedEvents.add(new TestSensorEvent(event, timestampNs));
}
synchronized (mEventLatches) {
@@ -141,7 +98,6 @@
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
checkHandler();
- mListener.onAccuracyChanged(sensor, accuracy);
}
/**
@@ -150,8 +106,6 @@
@Override
public void onFlushCompleted(Sensor sensor) {
checkHandler();
- mListener.onFlushCompleted(sensor);
-
synchronized (mFlushLatches) {
for (CountDownLatch latch : mFlushLatches) {
latch.countDown();
@@ -160,11 +114,37 @@
}
/**
+ * @return The handler (if any) associated with the instance.
+ */
+ public Handler getHandler() {
+ return mHandler;
+ }
+
+ /**
+ * @return A list of {@link TestSensorEvent}s collected by the listener.
+ */
+ public List<TestSensorEvent> getCollectedEvents() {
+ synchronized (mCollectedEvents){
+ return Collections.unmodifiableList(mCollectedEvents);
+ }
+ }
+
+ /**
+ * Clears the internal list of collected {@link TestSensorEvent}s.
+ */
+ public void clearEvents() {
+ synchronized (mCollectedEvents) {
+ mCollectedEvents.clear();
+ }
+ }
+
+ /**
* Wait for {@link #onFlushCompleted(Sensor)} to be called.
*
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForFlushComplete() throws InterruptedException {
+ clearEvents();
CountDownLatch latch = new CountDownLatch(1);
synchronized (mFlushLatches) {
mFlushLatches.add(latch);
@@ -190,10 +170,12 @@
* @throws AssertionError if there was a timeout after {@link #FLUSH_TIMEOUT_US} µs
*/
public void waitForEvents(int eventCount) throws InterruptedException {
+ clearEvents();
CountDownLatch eventLatch = new CountDownLatch(eventCount);
synchronized (mEventLatches) {
mEventLatches.add(eventLatch);
}
+
try {
long samplingPeriodUs = mEnvironment.getMaximumExpectedSamplingPeriodUs();
// timeout is 2 * event count * expected period + batch timeout + default wait
@@ -235,14 +217,20 @@
* If no events were received this assertion will be evaluated to {@code true}.
*/
public void assertEventsReceivedInHandler() {
- Assert.assertTrue(
- "Events did not arrive in the Looper associated with the given Handler.",
- mEventsReceivedInHandler);
+ int eventsOutsideHandler = mEventsReceivedOutsideHandler.get();
+ String message = String.format(
+ "Events arrived outside the associated Looper. Expected=0, Found=%d",
+ eventsOutsideHandler);
+ Assert.assertEquals(message, 0 /* expected */, eventsOutsideHandler);
}
+ /**
+ * Keeps track of the number of events that arrived in a different {@link Looper} than the one
+ * associated with the {@link TestSensorEventListener}.
+ */
private void checkHandler() {
- if (mHandler != null) {
- mEventsReceivedInHandler &= (mHandler.getLooper() == Looper.myLooper());
+ if (mHandler != null && mHandler.getLooper() != Looper.myLooper()) {
+ mEventsReceivedOutsideHandler.incrementAndGet();
}
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
index a611bfc..fdd851e 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/TestSensorManager.java
@@ -74,15 +74,13 @@
}
mTestSensorEventListener = listener;
- mTestSensorEventListener.setEnvironment(mEnvironment);
-
String message = SensorCtsHelper.formatAssertionMessage("registerListener", mEnvironment);
boolean result = mSensorManager.registerListener(
mTestSensorEventListener,
mEnvironment.getSensor(),
mEnvironment.getRequestedSamplingPeriodUs(),
mEnvironment.getMaxReportLatencyUs(),
- listener.getHandler());
+ mTestSensorEventListener.getHandler());
Assert.assertTrue(message, result);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java b/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
deleted file mode 100644
index 7572dc7..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/ValidatingSensorEventListener.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers;
-
-import android.hardware.SensorEvent;
-import android.hardware.cts.helpers.sensorverification.ISensorVerification;
-import android.os.Handler;
-
-import java.util.ArrayList;
-import java.util.Collection;
-
-/**
- * A {@link TestSensorEventListener} which performs validations on the received events on the fly.
- * This class is useful for long running tests where it is not practical to store all the events to
- * be processed after.
- */
-public class ValidatingSensorEventListener extends TestSensorEventListener {
-
- private final ArrayList<ISensorVerification> mVerifications =
- new ArrayList<ISensorVerification>();
-
- /**
- * Construct a {@link ValidatingSensorEventListener}.
- */
- public ValidatingSensorEventListener(
- Collection<ISensorVerification> verifications,
- Handler handler) {
- super(handler);
- mVerifications.addAll(verifications);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public void onSensorChanged(SensorEvent event) {
- TestSensorEvent testEvent = new TestSensorEvent(event);
- for (ISensorVerification verification : mVerifications) {
- verification.addSensorEvent(testEvent);
- }
- super.onSensorChanged(event);
- }
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
deleted file mode 100644
index 5b969f2..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AbstractSensorOperation.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import android.hardware.cts.helpers.SensorStats;
-
-/**
- * A {@link ISensorOperation} which contains a common implementation for gathering
- * {@link SensorStats}.
- */
-public abstract class AbstractSensorOperation implements ISensorOperation {
-
- private final SensorStats mStats = new SensorStats();
-
- /**
- * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)}
- */
- protected void addSensorStats(String key, SensorStats stats) {
- mStats.addSensorStats(key, stats);
- }
-
- /**
- * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)} that allows an index
- * to be added. This is useful for {@link ISensorOperation}s that have many iterations or child
- * operations. The key added is in the form {@code key + "_" + index} where index may be zero
- * padded.
- */
- protected void addSensorStats(String key, int index, SensorStats stats) {
- addSensorStats(String.format("%s_%03d", key, index), stats);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public SensorStats getStats() {
- return mStats;
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
- public abstract ISensorOperation clone();
-
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
index 88e4954..8848337 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/AlarmOperation.java
@@ -29,7 +29,7 @@
import java.util.concurrent.TimeUnit;
/**
- * An {@link ISensorOperation} which performs another {@link ISensorOperation} and then wakes up
+ * An {@link SensorOperation} which performs another {@link SensorOperation} and then wakes up
* after a specified period of time and waits for the child operation to complete.
* <p>
* This operation can be used to allow the device to go to sleep and wake it up after a specified
@@ -40,11 +40,11 @@
* but wake the device one time at the specified period.
* </p>
*/
-public class AlarmOperation extends AbstractSensorOperation {
+public class AlarmOperation extends SensorOperation {
private static final String ACTION = "AlarmOperationAction";
private static final String WAKE_LOCK_TAG = "AlarmOperationWakeLock";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final Context mContext;
private final long mSleepDuration;
private final TimeUnit mTimeUnit;
@@ -55,13 +55,17 @@
/**
* Constructor for {@link DelaySensorOperation}
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the alarm manager
* @param sleepDuration the amount of time to sleep
* @param timeUnit the unit of the duration
*/
- public AlarmOperation(ISensorOperation operation, Context context, long sleepDuration,
+ public AlarmOperation(
+ SensorOperation operation,
+ Context context,
+ long sleepDuration,
TimeUnit timeUnit) {
+ super(operation.getStats());
mOperation = operation;
mContext = context;
mSleepDuration = sleepDuration;
@@ -120,7 +124,7 @@
*/
private synchronized void acquireWakeLock() {
// Don't acquire wake lock if the operation has already completed.
- if (mCompleted == true || mWakeLock != null) {
+ if (mCompleted || mWakeLock != null) {
return;
}
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
index b4d1f23..3ee08f6 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/DelaySensorOperation.java
@@ -22,22 +22,22 @@
import java.util.concurrent.TimeUnit;
/**
- * An {@link ISensorOperation} which delays for a specified period of time before performing another
- * {@link ISensorOperation}.
+ * An {@link SensorOperation} which delays for a specified period of time before performing another
+ * {@link SensorOperation}.
*/
-public class DelaySensorOperation implements ISensorOperation {
- private final ISensorOperation mOperation;
+public class DelaySensorOperation extends SensorOperation {
+ private final SensorOperation mOperation;
private final long mDelay;
private final TimeUnit mTimeUnit;
/**
* Constructor for {@link DelaySensorOperation}
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param delay the amount of time to delay
* @param timeUnit the unit of the delay
*/
- public DelaySensorOperation(ISensorOperation operation, long delay, TimeUnit timeUnit) {
+ public DelaySensorOperation(SensorOperation operation, long delay, TimeUnit timeUnit) {
if (operation == null || timeUnit == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
index bb64dfa..8cfd351 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/FakeSensorOperation.java
@@ -16,17 +16,17 @@
package android.hardware.cts.helpers.sensoroperations;
-import android.hardware.cts.helpers.SensorStats;
-
import junit.framework.Assert;
+import android.hardware.cts.helpers.SensorStats;
+
import java.util.concurrent.TimeUnit;
/**
- * A fake {@ISensorOperation} that will run for a specified time and then pass or fail. Useful when
- * debugging the framework.
+ * A fake {@link SensorOperation} that will run for a specified time and then pass or fail. Useful
+ * when debugging the framework.
*/
-public class FakeSensorOperation extends AbstractSensorOperation {
+public class FakeSensorOperation extends SensorOperation {
private static final int NANOS_PER_MILLI = 1000000;
private final boolean mFail;
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
deleted file mode 100644
index 62a4e9e..0000000
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ISensorOperation.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.cts.helpers.sensoroperations;
-
-import android.hardware.cts.helpers.SensorStats;
-
-/**
- * Interface used by all sensor operations. This allows for complex operations such as chaining
- * operations together or running operations in parallel.
- * <p>
- * Certain restrictions exist for {@link ISensorOperation}s:
- * <p><ul>
- * <li>{@link #execute()} should only be called once and behavior is undefined for subsequent calls.
- * Once {@link #execute()} is called, the class should not be modified. Generally, there is no
- * synchronization for operations.</li>
- * <li>{@link #getStats()} should only be called after {@link #execute()}. If it is called before,
- * the returned value is undefined.</li>
- * <li>{@link #clone()} may be called any time and should return an operation with the same
- * parameters as the original.</li>
- * </ul>
- */
-public interface ISensorOperation {
-
- /**
- * Executes the sensor operation. This may throw {@link RuntimeException}s such as
- * {@link AssertionError}s.
- *
- * NOTE: the operation is expected to handle interruption by:
- * - cleaning up on {@link InterruptedException}
- * - propagating the exception down the stack
- */
- public void execute() throws InterruptedException;
-
- /**
- * Get the stats for the operation.
- *
- * @return The {@link SensorStats} for the operation.
- */
- public SensorStats getStats();
-
- /**
- * Clones the {@link ISensorOperation}. The implementation should also clone all child
- * operations, so that a cloned operation will run with the exact same parameters as the
- * original. The stats should not be cloned.
- *
- * @return The cloned {@link ISensorOperation}
- */
- public ISensorOperation clone();
-}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
index 5a4466c..e55c6cb 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/ParallelSensorOperation.java
@@ -22,7 +22,6 @@
import android.os.SystemClock;
import java.util.ArrayList;
-import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
@@ -33,14 +32,14 @@
import java.util.concurrent.TimeoutException;
/**
- * A {@link ISensorOperation} that executes a set of children {@link ISensorOperation}s in parallel.
+ * A {@link SensorOperation} that executes a set of children {@link SensorOperation}s in parallel.
* The children are run in parallel but are given an index label in the order they are added. This
- * class can be combined to compose complex {@link ISensorOperation}s.
+ * class can be combined to compose complex {@link SensorOperation}s.
*/
-public class ParallelSensorOperation extends AbstractSensorOperation {
+public class ParallelSensorOperation extends SensorOperation {
public static final String STATS_TAG = "parallel";
- private final List<ISensorOperation> mOperations = new LinkedList<ISensorOperation>();
+ private final ArrayList<SensorOperation> mOperations = new ArrayList<>();
private final Long mTimeout;
private final TimeUnit mTimeUnit;
@@ -65,10 +64,10 @@
}
/**
- * Add a set of {@link ISensorOperation}s.
+ * Add a set of {@link SensorOperation}s.
*/
- public void add(ISensorOperation ... operations) {
- for (ISensorOperation operation : operations) {
+ public void add(SensorOperation ... operations) {
+ for (SensorOperation operation : operations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
@@ -77,7 +76,7 @@
}
/**
- * Executes the {@link ISensorOperation}s in parallel. If an exception occurs one or more
+ * Executes the {@link SensorOperation}s in parallel. If an exception occurs one or more
* operations, the first exception will be thrown once all operations are completed.
*/
@Override
@@ -92,11 +91,11 @@
executor.allowCoreThreadTimeOut(true);
executor.prestartAllCoreThreads();
- ArrayList<Future<ISensorOperation>> futures = new ArrayList<Future<ISensorOperation>>();
- for (final ISensorOperation operation : mOperations) {
- Future<ISensorOperation> future = executor.submit(new Callable<ISensorOperation>() {
+ ArrayList<Future<SensorOperation>> futures = new ArrayList<>();
+ for (final SensorOperation operation : mOperations) {
+ Future<SensorOperation> future = executor.submit(new Callable<SensorOperation>() {
@Override
- public ISensorOperation call() throws Exception {
+ public SensorOperation call() throws Exception {
operation.execute();
return operation;
}
@@ -111,12 +110,12 @@
}
boolean hasAssertionErrors = false;
- ArrayList<Integer> timeoutIndices = new ArrayList<Integer>();
- ArrayList<Throwable> exceptions = new ArrayList<Throwable>();
+ ArrayList<Integer> timeoutIndices = new ArrayList<>();
+ ArrayList<Throwable> exceptions = new ArrayList<>();
for (int i = 0; i < operationsCount; ++i) {
- Future<ISensorOperation> future = futures.get(i);
+ Future<SensorOperation> future = futures.get(i);
try {
- ISensorOperation operation = getFutureResult(future, executionTimeNs);
+ SensorOperation operation = getFutureResult(future, executionTimeNs);
addSensorStats(STATS_TAG, i, operation.getStats());
} catch (ExecutionException e) {
// extract the exception thrown by the worker thread
@@ -151,7 +150,7 @@
@Override
public ParallelSensorOperation clone() {
ParallelSensorOperation operation = new ParallelSensorOperation();
- for (ISensorOperation subOperation : mOperations) {
+ for (SensorOperation subOperation : mOperations) {
operation.add(subOperation.clone());
}
return operation;
@@ -160,7 +159,7 @@
/**
* Helper method that waits for a {@link Future} to complete, and returns its result.
*/
- private ISensorOperation getFutureResult(Future<ISensorOperation> future, Long timeoutNs)
+ private SensorOperation getFutureResult(Future<SensorOperation> future, Long timeoutNs)
throws ExecutionException, TimeoutException, InterruptedException {
if (timeoutNs == null) {
return future.get();
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
index 3d682fe..2e3af36 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/RepeatingSensorOperation.java
@@ -19,22 +19,22 @@
import android.hardware.cts.helpers.SensorStats;
/**
- * A {@link ISensorOperation} that executes a single {@link ISensorOperation} a given number of
- * times. This class can be combined to compose complex {@link ISensorOperation}s.
+ * A {@link SensorOperation} that executes a single {@link SensorOperation} a given number of
+ * times. This class can be combined to compose complex {@link SensorOperation}s.
*/
-public class RepeatingSensorOperation extends AbstractSensorOperation {
+public class RepeatingSensorOperation extends SensorOperation {
public static final String STATS_TAG = "repeating";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final int mIterations;
/**
* Constructor for {@link RepeatingSensorOperation}.
*
- * @param operation the {@link ISensorOperation} to run.
+ * @param operation the {@link SensorOperation} to run.
* @param iterations the number of iterations to run the operation for.
*/
- public RepeatingSensorOperation(ISensorOperation operation, int iterations) {
+ public RepeatingSensorOperation(SensorOperation operation, int iterations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
@@ -44,13 +44,13 @@
}
/**
- * Executes the {@link ISensorOperation}s the given number of times. If an exception occurs
- * in one iterations, it is thrown and all subsequent iterations will not run.
+ * Executes the {@link SensorOperation}s the given number of times. If an exception occurs in
+ * one iterations, it is thrown and all subsequent iterations will not run.
*/
@Override
public void execute() throws InterruptedException {
for(int i = 0; i < mIterations; ++i) {
- ISensorOperation operation = mOperation.clone();
+ SensorOperation operation = mOperation.clone();
try {
operation.execute();
} catch (AssertionError e) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
new file mode 100644
index 0000000..ea16716
--- /dev/null
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperation.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.cts.helpers.sensoroperations;
+
+import android.hardware.cts.helpers.SensorStats;
+
+/**
+ * Base class used by all sensor operations. This allows for complex operations such as chaining
+ * operations together or running operations in parallel.
+ * <p>
+ * Certain restrictions exist for {@link SensorOperation}s:
+ * <p><ul>
+ * <li>{@link #execute()} should only be called once and behavior is undefined for subsequent calls.
+ * Once {@link #execute()} is called, the class should not be modified. Generally, there is no
+ * synchronization for operations.</li>
+ * <li>{@link #getStats()} should only be called after {@link #execute()}. If it is called before,
+ * the returned value is undefined.</li>
+ * <li>{@link #clone()} may be called any time and should return an operation with the same
+ * parameters as the original.</li>
+ * </ul>
+ */
+public abstract class SensorOperation {
+ private final SensorStats mStats;
+
+ protected SensorOperation() {
+ this(new SensorStats());
+ }
+
+ protected SensorOperation(SensorStats stats) {
+ mStats = stats;
+ }
+
+ /**
+ * @return The {@link SensorStats} for the operation.
+ */
+ public SensorStats getStats() {
+ return mStats;
+ }
+
+ /**
+ * Executes the sensor operation.
+ * This may throw {@link RuntimeException}s such as {@link AssertionError}s.
+ *
+ * NOTE: the operation is expected to handle interruption by:
+ * - cleaning up on {@link InterruptedException}
+ * - propagating the exception down the stack
+ */
+ public abstract void execute() throws InterruptedException;
+
+ /**
+ * @return The cloned {@link SensorOperation}.
+ *
+ * NOTE: The implementation should also clone all child operations, so that a cloned operation
+ * will run with the exact same parameters as the original. The stats should not be cloned.
+ */
+ public abstract SensorOperation clone();
+
+ /**
+ * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)}
+ */
+ protected void addSensorStats(String key, SensorStats stats) {
+ getStats().addSensorStats(key, stats);
+ }
+
+ /**
+ * Wrapper around {@link SensorStats#addSensorStats(String, SensorStats)} that allows an index
+ * to be added. This is useful for {@link SensorOperation}s that have many iterations or child
+ * operations. The key added is in the form {@code key + "_" + index} where index may be zero
+ * padded.
+ */
+ protected void addSensorStats(String key, int index, SensorStats stats) {
+ addSensorStats(String.format("%s_%03d", key, index), stats);
+ }
+}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
index bc48725..033f3c5 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SensorOperationTest.java
@@ -24,7 +24,7 @@
import java.util.concurrent.TimeUnit;
/**
- * Tests for the primitive {@link ISensorOperation}s including {@link DelaySensorOperation},
+ * Tests for the primitive {@link SensorOperation}s including {@link DelaySensorOperation},
* {@link ParallelSensorOperation}, {@link RepeatingSensorOperation} and
* {@link SequentialSensorOperation}.
*/
@@ -38,7 +38,7 @@
public void testFakeSensorOperation() throws InterruptedException {
final int opDurationMs = 100;
- ISensorOperation op = new FakeSensorOperation(opDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new FakeSensorOperation(opDurationMs, TimeUnit.MILLISECONDS);
assertFalse(op.getStats().flatten().containsKey("executed"));
long start = System.currentTimeMillis();
@@ -65,12 +65,12 @@
final int subOpDurationMs = 100;
FakeSensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
- ISensorOperation op = new DelaySensorOperation(subOp, opDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new DelaySensorOperation(subOp, opDurationMs, TimeUnit.MILLISECONDS);
long startMs = System.currentTimeMillis();
op.execute();
- long dirationMs = System.currentTimeMillis() - startMs;
- long durationDeltaMs = Math.abs(opDurationMs + subOpDurationMs - dirationMs);
+ long durationMs = System.currentTimeMillis() - startMs;
+ long durationDeltaMs = Math.abs(opDurationMs + subOpDurationMs - durationMs);
assertTrue(durationDeltaMs < TEST_DURATION_THRESHOLD_MS);
}
@@ -83,7 +83,7 @@
ParallelSensorOperation op = new ParallelSensorOperation();
for (int i = 0; i < subOpCount; i++) {
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -124,7 +124,7 @@
ParallelSensorOperation op = new ParallelSensorOperation();
for (int i = 0; i < subOpCount; i++) {
// Trigger failures in the 5th, 55th operations at t=5ms, t=55ms
- ISensorOperation subOp = new FakeSensorOperation(i % 50 == 5, i, TimeUnit.MILLISECONDS);
+ SensorOperation subOp = new FakeSensorOperation(i % 50 == 5, i, TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -164,7 +164,7 @@
ParallelSensorOperation op = new ParallelSensorOperation(1, TimeUnit.SECONDS);
for (int i = 0; i < subOpCount; i++) {
// Trigger timeouts in the 5th, 55th operations (5 seconds vs 1 seconds)
- ISensorOperation subOp = new FakeSensorOperation(i % 50 == 5 ? 5 : 0, TimeUnit.SECONDS);
+ SensorOperation subOp = new FakeSensorOperation(i % 50 == 5 ? 5 : 0, TimeUnit.SECONDS);
op.add(subOp);
}
@@ -196,8 +196,8 @@
final int iterations = 10;
final int subOpDurationMs = 100;
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
- ISensorOperation op = new RepeatingSensorOperation(subOp, iterations);
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs, TimeUnit.MILLISECONDS);
+ SensorOperation op = new RepeatingSensorOperation(subOp, iterations);
Set<String> statsKeys = op.getStats().flatten().keySet();
assertEquals(0, statsKeys.size());
@@ -223,7 +223,7 @@
final int iterations = 100;
final int failCount = 75;
- ISensorOperation subOp = new FakeSensorOperation(0, TimeUnit.MILLISECONDS) {
+ SensorOperation subOp = new FakeSensorOperation(0, TimeUnit.MILLISECONDS) {
private int mExecutedCount = 0;
private SensorStats mFakeStats = new SensorStats();
@@ -249,7 +249,7 @@
return mFakeStats;
}
};
- ISensorOperation op = new RepeatingSensorOperation(subOp, iterations);
+ SensorOperation op = new RepeatingSensorOperation(subOp, iterations);
Set<String> statsKeys = op.getStats().flatten().keySet();
assertEquals(0, statsKeys.size());
@@ -283,7 +283,7 @@
SequentialSensorOperation op = new SequentialSensorOperation();
for (int i = 0; i < subOpCount; i++) {
- ISensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
+ SensorOperation subOp = new FakeSensorOperation(subOpDurationMs,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
@@ -315,7 +315,7 @@
SequentialSensorOperation op = new SequentialSensorOperation();
for (int i = 0; i < subOpCount; i++) {
// Trigger a failure in the 75th operation only
- ISensorOperation subOp = new FakeSensorOperation(i + 1 == failCount, 0,
+ SensorOperation subOp = new FakeSensorOperation(i + 1 == failCount, 0,
TimeUnit.MILLISECONDS);
op.add(subOp);
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
index 2ed0ca6..85d189a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/SequentialSensorOperation.java
@@ -18,24 +18,23 @@
import android.hardware.cts.helpers.SensorStats;
-import java.util.LinkedList;
-import java.util.List;
+import java.util.ArrayList;
/**
- * A {@link ISensorOperation} that executes a set of children {@link ISensorOperation}s in a
+ * A {@link SensorOperation} that executes a set of children {@link SensorOperation}s in a
* sequence. The children are executed in the order they are added. This class can be combined to
- * compose complex {@link ISensorOperation}s.
+ * compose complex {@link SensorOperation}s.
*/
-public class SequentialSensorOperation extends AbstractSensorOperation {
+public class SequentialSensorOperation extends SensorOperation {
public static final String STATS_TAG = "sequential";
- private final List<ISensorOperation> mOperations = new LinkedList<ISensorOperation>();
+ private final ArrayList<SensorOperation> mOperations = new ArrayList<>();
/**
- * Add a set of {@link ISensorOperation}s.
+ * Add a set of {@link SensorOperation}s.
*/
- public void add(ISensorOperation ... operations) {
- for (ISensorOperation operation : operations) {
+ public void add(SensorOperation ... operations) {
+ for (SensorOperation operation : operations) {
if (operation == null) {
throw new IllegalArgumentException("Arguments cannot be null");
}
@@ -44,13 +43,13 @@
}
/**
- * Executes the {@link ISensorOperation}s in the order they were added. If an exception occurs
+ * Executes the {@link SensorOperation}s in the order they were added. If an exception occurs
* in one operation, it is thrown and all subsequent operations will not run.
*/
@Override
public void execute() throws InterruptedException {
for (int i = 0; i < mOperations.size(); i++) {
- ISensorOperation operation = mOperations.get(i);
+ SensorOperation operation = mOperations.get(i);
try {
operation.execute();
} catch (AssertionError e) {
@@ -69,7 +68,7 @@
@Override
public SequentialSensorOperation clone() {
SequentialSensorOperation operation = new SequentialSensorOperation();
- for (ISensorOperation subOperation : mOperations) {
+ for (SensorOperation subOperation : mOperations) {
operation.add(subOperation.clone());
}
return operation;
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
index 6e53dbb..7347fc7 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/TestSensorOperation.java
@@ -21,9 +21,9 @@
import android.hardware.cts.helpers.SensorCtsHelper;
import android.hardware.cts.helpers.SensorStats;
import android.hardware.cts.helpers.TestSensorEnvironment;
+import android.hardware.cts.helpers.TestSensorEvent;
import android.hardware.cts.helpers.TestSensorEventListener;
import android.hardware.cts.helpers.TestSensorManager;
-import android.hardware.cts.helpers.ValidatingSensorEventListener;
import android.hardware.cts.helpers.sensorverification.EventGapVerification;
import android.hardware.cts.helpers.sensorverification.EventOrderingVerification;
import android.hardware.cts.helpers.sensorverification.EventTimestampSynchronizationVerification;
@@ -35,21 +35,20 @@
import android.hardware.cts.helpers.sensorverification.StandardDeviationVerification;
import android.os.Handler;
-import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
import java.util.concurrent.TimeUnit;
/**
- * A {@link ISensorOperation} used to verify that sensor events and sensor values are correct.
+ * A {@link SensorOperation} used to verify that sensor events and sensor values are correct.
* <p>
* Provides methods to set test expectations as well as providing a set of default expectations
* depending on sensor type. When {{@link #execute()} is called, the sensor will collect the
* events and then run all the tests.
* </p>
*/
-public class TestSensorOperation extends AbstractSensorOperation {
- private final Collection<ISensorVerification> mVerifications =
- new HashSet<ISensorVerification>();
+public class TestSensorOperation extends SensorOperation {
+ private final HashSet<ISensorVerification> mVerifications = new HashSet<>();
private final TestSensorManager mSensorManager;
private final TestSensorEnvironment mEnvironment;
@@ -120,17 +119,15 @@
@Override
public void execute() throws InterruptedException {
getStats().addValue("sensor_name", mEnvironment.getSensor().getName());
-
- ValidatingSensorEventListener listener =
- new ValidatingSensorEventListener(mVerifications, mHandler);
- listener.setLogEvents(mLogEvents);
+ TestSensorEventListener listener = new TestSensorEventListener(mEnvironment, mHandler);
mExecutor.execute(mSensorManager, listener);
boolean failed = false;
StringBuilder sb = new StringBuilder();
+ List<TestSensorEvent> collectedEvents = listener.getCollectedEvents();
for (ISensorVerification verification : mVerifications) {
- failed |= evaluateResults(verification, sb);
+ failed |= evaluateResults(collectedEvents, verification, sb);
}
if (failed) {
@@ -156,8 +153,14 @@
/**
* Evaluate the results of a test, aggregate the stats, and build the error message.
*/
- private boolean evaluateResults(ISensorVerification verification, StringBuilder sb) {
+ private boolean evaluateResults(
+ List<TestSensorEvent> events,
+ ISensorVerification verification,
+ StringBuilder sb) {
try {
+ // this is an intermediate state in refactoring, at some point verifications might
+ // become stateless
+ verification.addSensorEvents(events);
verification.verify(mEnvironment, getStats());
} catch (AssertionError e) {
if (sb.length() > 0) {
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
index b500ea7..5f4f5d8 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensoroperations/WakeLockOperation.java
@@ -22,36 +22,36 @@
import android.os.PowerManager.WakeLock;
/**
- * An {@link ISensorOperation} which holds a wakelock while performing another
- * {@link ISensorOperation}.
+ * An {@link SensorOperation} which holds a wake-lock while performing another
+ * {@link SensorOperation}.
*/
-public class WakeLockOperation extends AbstractSensorOperation {
+public class WakeLockOperation extends SensorOperation {
private static final String TAG = "WakeLockOperation";
- private final ISensorOperation mOperation;
+ private final SensorOperation mOperation;
private final Context mContext;
- private final int mWakelockFlags;
+ private final int mWakeLockFlags;
/**
* Constructor for {@link WakeLockOperation}.
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the power manager
- * @param wakelockFlags the flags used when acquiring the wakelock
+ * @param wakeLockFlags the flags used when acquiring the wake-lock
*/
- public WakeLockOperation(ISensorOperation operation, Context context, int wakelockFlags) {
+ public WakeLockOperation(SensorOperation operation, Context context, int wakeLockFlags) {
mOperation = operation;
mContext = context;
- mWakelockFlags = wakelockFlags;
+ mWakeLockFlags = wakeLockFlags;
}
/**
* Constructor for {@link WakeLockOperation}.
*
- * @param operation the child {@link ISensorOperation} to perform after the delay
+ * @param operation the child {@link SensorOperation} to perform after the delay
* @param context the context used to access the power manager
*/
- public WakeLockOperation(ISensorOperation operation, Context context) {
+ public WakeLockOperation(SensorOperation operation, Context context) {
this(operation, context, PowerManager.PARTIAL_WAKE_LOCK);
}
@@ -61,7 +61,7 @@
@Override
public void execute() throws InterruptedException {
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
- WakeLock wakeLock = pm.newWakeLock(mWakelockFlags, TAG);
+ WakeLock wakeLock = pm.newWakeLock(mWakeLockFlags, TAG);
wakeLock.acquire();
try {
@@ -83,7 +83,7 @@
* {@inheritDoc}
*/
@Override
- public ISensorOperation clone() {
- return new WakeLockOperation(mOperation, mContext, mWakelockFlags);
+ public SensorOperation clone() {
+ return new WakeLockOperation(mOperation, mContext, mWakeLockFlags);
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
index acf71bb..1e775e3 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/AbstractSensorVerification.java
@@ -18,6 +18,7 @@
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.Collection;
import java.util.List;
/**
@@ -29,7 +30,7 @@
* {@inheritDoc}
*/
@Override
- public synchronized void addSensorEvents(TestSensorEvent ... events) {
+ public synchronized void addSensorEvents(Collection<TestSensorEvent> events) {
for (TestSensorEvent event : events) {
addSensorEventInternal(event);
}
@@ -39,14 +40,6 @@
* {@inheritDoc}
*/
@Override
- public synchronized void addSensorEvent(TestSensorEvent event) {
- addSensorEventInternal(event);
- }
-
- /**
- * {@inheritDoc}
- */
- @Override
public abstract ISensorVerification clone();
/**
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
index d01e108..6f17e7b 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventGapVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link EventGapVerification}.
*/
@@ -90,11 +93,13 @@
}
}
- private ISensorVerification getVerification(int expected, long ... timestamps) {
- ISensorVerification verification = new EventGapVerification(expected);
+ private static EventGapVerification getVerification(int expected, long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ EventGapVerification verification = new EventGapVerification(expected);
+ verification.addSensorEvents(events);
return verification;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
index 88d5c19..b9848fa 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/EventOrderingVerificationTest.java
@@ -22,6 +22,7 @@
import android.hardware.cts.helpers.TestSensorEvent;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -96,11 +97,13 @@
assertTrue(indices.contains(4));
}
- private EventOrderingVerification getVerification(long ... timestamps) {
- EventOrderingVerification verification = new EventOrderingVerification();
+ private static EventOrderingVerification getVerification(long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ EventOrderingVerification verification = new EventOrderingVerification();
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
index 24349ce..bbf022a 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/FrequencyVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link EventOrderingVerification}.
*/
@@ -73,15 +76,17 @@
return new TestSensorEnvironment(getContext(), Sensor.TYPE_ALL, rateUs);
}
- private ISensorVerification getVerification(
+ private static FrequencyVerification getVerification(
double lowerThreshold,
double upperThreshold,
long ... timestamps) {
- ISensorVerification verification =
- new FrequencyVerification(lowerThreshold, upperThreshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ FrequencyVerification verification =
+ new FrequencyVerification(lowerThreshold, upperThreshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
index 4f7b65a..2027f0f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/ISensorVerification.java
@@ -20,24 +20,25 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.Collection;
+
/**
- * Interface describing the sensor verification. This class was designed for to handle streaming
- * events. The methods {@link #addSensorEvent(TestSensorEvent)} and
- * {@link #addSensorEvents(TestSensorEvent...)} should be called in the order that the events are
- * received. The method {@link #verify(TestSensorEnvironment, SensorStats)} should be called after
- * all events are added.
+ * Interface describing the sensor verification.
+ * This class was designed to handle streaming of events.
+ *
+ * The method {@link #addSensorEvents(Collection)} should be called in the order that the events are
+ * received.
+ *
+ * The method {@link #verify(TestSensorEnvironment, SensorStats)} should be called after all events
+ * are added.
*/
public interface ISensorVerification {
/**
- * Add a single {@link TestSensorEvent} to be evaluated.
+ * Add a list of {@link TestSensorEvent}s to be evaluated.
*/
- public void addSensorEvent(TestSensorEvent event);
-
- /**
- * Add multiple {@link TestSensorEvent}s to be evaluated.
- */
- public void addSensorEvents(TestSensorEvent ... events);
+ // TODO: refactor verifications to be stateless, and pass the list of events in verify()
+ void addSensorEvents(Collection<TestSensorEvent> events);
/**
* Evaluate all added {@link TestSensorEvent}s and update stats.
@@ -45,10 +46,10 @@
* @param stats a {@link SensorStats} object used to keep track of the stats.
* @throws AssertionError if the verification fails.
*/
- public void verify(TestSensorEnvironment environment, SensorStats stats);
+ void verify(TestSensorEnvironment environment, SensorStats stats);
/**
* Clones the {@link ISensorVerification}
*/
- public ISensorVerification clone();
+ ISensorVerification clone();
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
index 0c85b63..50e288c 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/JitterVerificationTest.java
@@ -22,6 +22,8 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
/**
@@ -98,11 +100,13 @@
assertEquals(3.0, jitterValues.get(3));
}
- private JitterVerification getVerification(int threshold, long ... timestamps) {
- JitterVerification verification = new JitterVerification(threshold);
+ private static JitterVerification getVerification(int threshold, long ... timestamps) {
+ Collection<TestSensorEvent> events = new ArrayList<>(timestamps.length);
for (long timestamp : timestamps) {
- verification.addSensorEvent(new TestSensorEvent(null, timestamp, 0, null));
+ events.add(new TestSensorEvent(null, timestamp, 0, null));
}
+ JitterVerification verification = new JitterVerification(threshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
index bb29330..ac873c1 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MagnitudeVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link MagnitudeVerification}.
*/
@@ -63,12 +66,14 @@
assertEquals(magnitude, (Float) stats.getValue(SensorStats.MAGNITUDE_KEY), 0.01);
}
- private MagnitudeVerification getVerification(float expected, float threshold,
+ private static MagnitudeVerification getVerification(float expected, float threshold,
float[] ... values) {
- MagnitudeVerification verification = new MagnitudeVerification(expected, threshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ MagnitudeVerification verification = new MagnitudeVerification(expected, threshold);
+ verification.addSensorEvents(events);
return verification;
}
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
index b07ea50..d7fcf9f 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/MeanVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link MeanVerification}.
*/
@@ -89,12 +92,14 @@
verifyStats(stats, false, new float[]{2.0f, 3.0f, 6.0f});
}
- private MeanVerification getVerification(float[] expected, float[] threshold,
+ private static MeanVerification getVerification(float[] expected, float[] threshold,
float[] ... values) {
- MeanVerification verification = new MeanVerification(expected, threshold);
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ MeanVerification verification = new MeanVerification(expected, threshold);
+ verification.addSensorEvents(events);
return verification;
}
diff --git a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
index 5d958f5..617a438 100644
--- a/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
+++ b/tests/tests/hardware/src/android/hardware/cts/helpers/sensorverification/StandardDeviationVerificationTest.java
@@ -22,6 +22,9 @@
import android.hardware.cts.helpers.TestSensorEnvironment;
import android.hardware.cts.helpers.TestSensorEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+
/**
* Tests for {@link StandardDeviationVerification}.
*/
@@ -79,11 +82,15 @@
}
}
- private StandardDeviationVerification getVerification(float[] threshold, float[] ... values) {
- StandardDeviationVerification verification = new StandardDeviationVerification(threshold);
+ private static StandardDeviationVerification getVerification(
+ float[] threshold,
+ float[] ... values) {
+ Collection<TestSensorEvent> events = new ArrayList<>(values.length);
for (float[] value : values) {
- verification.addSensorEvent(new TestSensorEvent(null, 0, 0, value));
+ events.add(new TestSensorEvent(null, 0, 0, value));
}
+ StandardDeviationVerification verification = new StandardDeviationVerification(threshold);
+ verification.addSensorEvents(events);
return verification;
}
}
diff --git a/tests/tests/media/Android.mk b/tests/tests/media/Android.mk
index 15237a8..77d4bb7f 100644
--- a/tests/tests/media/Android.mk
+++ b/tests/tests/media/Android.mk
@@ -16,6 +16,20 @@
include $(CLEAR_VARS)
+LOCAL_SRC_FILES := \
+ src/android/media/cts/CodecImage.java \
+ src/android/media/cts/CodecUtils.java
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE := ctsmediautil
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
+include $(CLEAR_VARS)
+
# don't include this package in any target
LOCAL_MODULE_TAGS := optional
# and when built explicitly put it in the data partition
@@ -24,7 +38,8 @@
# include both the 32 and 64 bit versions
LOCAL_MULTILIB := both
-LOCAL_STATIC_JAVA_LIBRARIES := ctsdeviceutil ctstestserver ctstestrunner
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ ctsmediautil ctsdeviceutil ctstestserver ctstestrunner
LOCAL_JNI_SHARED_LIBRARIES := libctsmediacodec_jni
diff --git a/tests/tests/media/assets/noiseandchirps.ogg b/tests/tests/media/assets/noiseandchirps.ogg
index 5c67a88..1acb643 100644
--- a/tests/tests/media/assets/noiseandchirps.ogg
+++ b/tests/tests/media/assets/noiseandchirps.ogg
Binary files differ
diff --git a/tests/tests/media/libmediandkjni/Android.mk b/tests/tests/media/libmediandkjni/Android.mk
index 59ff7bb..23f9f5c 100644
--- a/tests/tests/media/libmediandkjni/Android.mk
+++ b/tests/tests/media/libmediandkjni/Android.mk
@@ -24,7 +24,9 @@
native-media-jni.cpp \
codec-utils-jni.cpp
-LOCAL_C_INCLUDES := $(JNI_H_INCLUDE)
+LOCAL_C_INCLUDES := \
+ $(JNI_H_INCLUDE) \
+ system/core/include
LOCAL_C_INCLUDES += $(call include-path-for, mediandk)
diff --git a/tests/tests/media/libmediandkjni/codec-utils-jni.cpp b/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
index f99f1c8..f7a08a1 100644
--- a/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
+++ b/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
@@ -16,8 +16,10 @@
/* Original code copied from NDK Native-media sample code */
-#undef NDEBUG
//#define LOG_NDEBUG 0
+#define TAG "CodecUtilsJNI"
+#include <log/log.h>
+
#include <stdint.h>
#include <sys/types.h>
#include <jni.h>
@@ -27,20 +29,6 @@
typedef ssize_t offs_t;
-// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
-#include <android/log.h>
-#define TAG "CodecUtilsJNI"
-#define __ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
-#if LOG_NDEBUG
-#define ALOGV(...) do { if (0) { __ALOGV(__VA_ARGS__); } } while (0)
-#else
-#define ALOGV(...) __ALOGV(__VA_ARGS__)
-#endif
-#define ALOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
-#define ALOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__)
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
-
struct NativeImage {
struct crop {
int left;
@@ -132,13 +120,13 @@
}
{ // Image
- jclass imageClazz = env->FindClass("android/media/Image");
+ jclass imageClazz = env->FindClass("android/media/cts/CodecImage");
gFields.methodWidth = env->GetMethodID(imageClazz, "getWidth", "()I");
gFields.methodHeight = env->GetMethodID(imageClazz, "getHeight", "()I");
gFields.methodFormat = env->GetMethodID(imageClazz, "getFormat", "()I");
gFields.methodTimestamp = env->GetMethodID(imageClazz, "getTimestamp", "()J");
gFields.methodPlanes = env->GetMethodID(
- imageClazz, "getPlanes", "()[Landroid/media/Image$Plane;");
+ imageClazz, "getPlanes", "()[Landroid/media/cts/CodecImage$Plane;");
gFields.methodCrop = env->GetMethodID(
imageClazz, "getCropRect", "()Landroid/graphics/Rect;");
env->DeleteLocalRef(imageClazz);
@@ -146,7 +134,7 @@
}
{ // Image.Plane
- jclass planeClazz = env->FindClass("android/media/Image$Plane");
+ jclass planeClazz = env->FindClass("android/media/cts/CodecImage$Plane");
gFields.methodBuffer = env->GetMethodID(planeClazz, "getBuffer", "()Ljava/nio/ByteBuffer;");
gFields.methodPixelStride = env->GetMethodID(planeClazz, "getPixelStride", "()I");
gFields.methodRowStride = env->GetMethodID(planeClazz, "getRowStride", "()I");
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 850932f1..9bca242 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -16,7 +16,10 @@
/* Original code copied from NDK Native-media sample code */
-#undef NDEBUG
+//#define LOG_NDEBUG 0
+#define TAG "NativeMedia"
+#include <log/log.h>
+
#include <assert.h>
#include <jni.h>
#include <pthread.h>
@@ -27,13 +30,6 @@
#include <android/native_window_jni.h>
-// for __android_log_print(ANDROID_LOG_INFO, "YourApp", "formatted message");
-#include <android/log.h>
-#define TAG "NativeMedia"
-#define ALOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__)
-#define ALOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
-#define ALOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__)
-
#include "ndk/NdkMediaExtractor.h"
#include "ndk/NdkMediaCodec.h"
#include "ndk/NdkMediaCrypto.h"
diff --git a/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz.webm b/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz.webm
new file mode 100644
index 0000000..c8b9512
--- /dev/null
+++ b/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz.webm
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm b/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm
deleted file mode 100644
index b0cd94d..0000000
--- a/tests/tests/media/res/raw/video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_48000hz.webm b/tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
similarity index 91%
rename from tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_48000hz.webm
rename to tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
index 2e769e6..a5eddd3 100644
--- a/tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_48000hz.webm
+++ b/tests/tests/media/res/raw/video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_44100hz.webm b/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_44100hz.webm
new file mode 100644
index 0000000..d6f0f3b
--- /dev/null
+++ b/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_44100hz.webm
Binary files differ
diff --git a/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_48000hz.webm b/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_48000hz.webm
deleted file mode 100644
index 10a1a5d..0000000
--- a/tests/tests/media/res/raw/video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_48000hz.webm
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
deleted file mode 100644
index 7b663a4..0000000
--- a/tests/tests/media/res/raw/video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_48000hz.webm b/tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
similarity index 76%
rename from tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_48000hz.webm
rename to tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
index b060ca6..15c34b9 100644
--- a/tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_48000hz.webm
+++ b/tests/tests/media/res/raw/video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz.webm
Binary files differ
diff --git a/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4 b/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
new file mode 100644
index 0000000..9277fbd
--- /dev/null
+++ b/tests/tests/media/res/raw/video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz.mp4
Binary files differ
diff --git a/tests/tests/media/res/raw/video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm b/tests/tests/media/res/raw/video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm
index b17c5af..0a33e54 100644
--- a/tests/tests/media/res/raw/video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm
+++ b/tests/tests/media/res/raw/video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
index 3b46360..67473e1 100644
--- a/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
+++ b/tests/tests/media/src/android/media/cts/AdaptivePlaybackTest.java
@@ -90,7 +90,7 @@
MediaFormat.MIMETYPE_VIDEO_VP8,
"OMX.google.vp8.decoder",
R.raw.video_480x360_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz,
- R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz);
+ R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz);
}
public Iterable<Codec> VP9(CodecFactory factory) {
@@ -1310,11 +1310,13 @@
/* test if the explicitly named codec is present on the system */
if (explicitCodecName != null) {
- MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
- if (codec != null) {
- codec.release();
- add(new Codec(explicitCodecName, null, mediaList));
- }
+ try {
+ MediaCodec codec = MediaCodec.createByCodecName(explicitCodecName);
+ if (codec != null) {
+ codec.release();
+ add(new Codec(explicitCodecName, null, mediaList));
+ }
+ } catch (Exception e) {}
}
} catch (Throwable t) {
Log.wtf("Constructor failed", t);
diff --git a/tests/tests/media/src/android/media/cts/CodecImage.java b/tests/tests/media/src/android/media/cts/CodecImage.java
new file mode 100644
index 0000000..60a644a
--- /dev/null
+++ b/tests/tests/media/src/android/media/cts/CodecImage.java
@@ -0,0 +1,210 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media.cts;
+
+import java.nio.ByteBuffer;
+import java.lang.AutoCloseable;
+
+import android.graphics.Rect;
+
+/**
+ * <p>A single complete image buffer to use with a media source such as a
+ * {@link MediaCodec} or a
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.</p>
+ *
+ * <p>This class allows for efficient direct application access to the pixel
+ * data of the CodecImage through one or more
+ * {@link java.nio.ByteBuffer ByteBuffers}. Each buffer is encapsulated in a
+ * {@link Plane} that describes the layout of the pixel data in that plane. Due
+ * to this direct access, and unlike the {@link android.graphics.Bitmap Bitmap} class,
+ * Images are not directly usable as UI resources.</p>
+ *
+ * <p>Since Images are often directly produced or consumed by hardware
+ * components, they are a limited resource shared across the system, and should
+ * be closed as soon as they are no longer needed.</p>
+ *
+ * <p>For example, when using the {@link ImageReader} class to read out Images
+ * from various media sources, not closing old CodecImage objects will prevent the
+ * availability of new Images once
+ * {@link ImageReader#getMaxImages the maximum outstanding image count} is
+ * reached. When this happens, the function acquiring new Images will typically
+ * throw an {@link IllegalStateException}.</p>
+ *
+ * @see ImageReader
+ */
+public abstract class CodecImage implements AutoCloseable {
+ /**
+ * Get the format for this image. This format determines the number of
+ * ByteBuffers needed to represent the image, and the general layout of the
+ * pixel data in each in ByteBuffer.
+ *
+ * <p>
+ * The format is one of the values from
+ * {@link android.graphics.ImageFormat ImageFormat}. The mapping between the
+ * formats and the planes is as follows:
+ * </p>
+ *
+ * <table>
+ * <tr>
+ * <th>Format</th>
+ * <th>Plane count</th>
+ * <th>Layout details</th>
+ * </tr>
+ * <tr>
+ * <td>{@link android.graphics.ImageFormat#JPEG JPEG}</td>
+ * <td>1</td>
+ * <td>Compressed data, so row and pixel strides are 0. To uncompress, use
+ * {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+ * </td>
+ * </tr>
+ * <tr>
+ * <td>{@link android.graphics.ImageFormat#YUV_420_888 YUV_420_888}</td>
+ * <td>3</td>
+ * <td>A luminance plane followed by the Cb and Cr chroma planes.
+ * The chroma planes have half the width and height of the luminance
+ * plane (4:2:0 subsampling). Each pixel sample in each plane has 8 bits.
+ * Each plane has its own row stride and pixel stride.</td>
+ * </tr>
+ * <tr>
+ * <td>{@link android.graphics.ImageFormat#RAW_SENSOR RAW_SENSOR}</td>
+ * <td>1</td>
+ * <td>A single plane of raw sensor image data, with 16 bits per color
+ * sample. The details of the layout need to be queried from the source of
+ * the raw sensor data, such as
+ * {@link android.hardware.camera2.CameraDevice CameraDevice}.
+ * </td>
+ * </tr>
+ * </table>
+ *
+ * @see android.graphics.ImageFormat
+ */
+ public abstract int getFormat();
+
+ /**
+ * The width of the image in pixels. For formats where some color channels
+ * are subsampled, this is the width of the largest-resolution plane.
+ */
+ public abstract int getWidth();
+
+ /**
+ * The height of the image in pixels. For formats where some color channels
+ * are subsampled, this is the height of the largest-resolution plane.
+ */
+ public abstract int getHeight();
+
+ /**
+ * Get the timestamp associated with this frame.
+ * <p>
+ * The timestamp is measured in nanoseconds, and is monotonically
+ * increasing. However, the zero point and whether the timestamp can be
+ * compared against other sources of time or images depend on the source of
+ * this image.
+ * </p>
+ */
+ public abstract long getTimestamp();
+
+ private Rect mCropRect;
+
+ /**
+ * Get the crop rectangle associated with this frame.
+ * <p>
+ * The crop rectangle specifies the region of valid pixels in the image,
+ * using coordinates in the largest-resolution plane.
+ */
+ public Rect getCropRect() {
+ if (mCropRect == null) {
+ return new Rect(0, 0, getWidth(), getHeight());
+ } else {
+ return new Rect(mCropRect); // return a copy
+ }
+ }
+
+ /**
+ * Set the crop rectangle associated with this frame.
+ * <p>
+ * The crop rectangle specifies the region of valid pixels in the image,
+ * using coordinates in the largest-resolution plane.
+ */
+ public void setCropRect(Rect cropRect) {
+ if (cropRect != null) {
+ cropRect = new Rect(cropRect); // make a copy
+ cropRect.intersect(0, 0, getWidth(), getHeight());
+ }
+ mCropRect = cropRect;
+ }
+
+ /**
+ * Get the array of pixel planes for this CodecImage. The number of planes is
+ * determined by the format of the CodecImage.
+ */
+ public abstract Plane[] getPlanes();
+
+ /**
+ * Free up this frame for reuse.
+ * <p>
+ * After calling this method, calling any methods on this {@code CodecImage} will
+ * result in an {@link IllegalStateException}, and attempting to read from
+ * {@link ByteBuffer ByteBuffers} returned by an earlier
+ * {@link Plane#getBuffer} call will have undefined behavior.
+ * </p>
+ */
+ @Override
+ public abstract void close();
+
+ /**
+ * <p>A single color plane of image data.</p>
+ *
+ * <p>The number and meaning of the planes in an CodecImage are determined by the
+ * format of the CodecImage.</p>
+ *
+ * <p>Once the CodecImage has been closed, any access to the the plane's
+ * ByteBuffer will fail.</p>
+ *
+ * @see #getFormat
+ */
+ public static abstract class Plane {
+ /**
+ * <p>The row stride for this color plane, in bytes.</p>
+ *
+ * <p>This is the distance between the start of two consecutive rows of
+ * pixels in the image. The row stride is always greater than 0.</p>
+ */
+ public abstract int getRowStride();
+ /**
+ * <p>The distance between adjacent pixel samples, in bytes.</p>
+ *
+ * <p>This is the distance between two consecutive pixel values in a row
+ * of pixels. It may be larger than the size of a single pixel to
+ * account for interleaved image data or padded formats.
+ * The pixel stride is always greater than 0.</p>
+ */
+ public abstract int getPixelStride();
+ /**
+ * <p>Get a direct {@link java.nio.ByteBuffer ByteBuffer}
+ * containing the frame data.</p>
+ *
+ * <p>In particular, the buffer returned will always have
+ * {@link java.nio.ByteBuffer#isDirect isDirect} return {@code true}, so
+ * the underlying data could be mapped as a pointer in JNI without doing
+ * any copies with {@code GetDirectBufferAddress}.</p>
+ *
+ * @return the byte buffer containing the image data for this plane.
+ */
+ public abstract ByteBuffer getBuffer();
+ }
+
+}
diff --git a/tests/tests/media/src/android/media/cts/CodecUtils.java b/tests/tests/media/src/android/media/cts/CodecUtils.java
index 3c3576f..df6eb4c 100644
--- a/tests/tests/media/src/android/media/cts/CodecUtils.java
+++ b/tests/tests/media/src/android/media/cts/CodecUtils.java
@@ -16,9 +16,12 @@
package android.media.cts;
+import android.media.cts.CodecImage;
import android.media.Image;
import android.util.Log;
+import java.nio.ByteBuffer;
+
public class CodecUtils {
private static final String TAG = "CodecUtils";
@@ -29,7 +32,89 @@
Log.i(TAG, "after loadlibrary");
}
- public native static int getImageChecksum(Image image);
- public native static void copyFlexYUVImage(Image target, Image source);
+ private static class ImageWrapper extends CodecImage {
+ private final Image mImage;
+ private final Plane[] mPlanes;
+
+ private ImageWrapper(Image image) {
+ mImage = image;
+ Image.Plane[] planes = mImage.getPlanes();
+
+ mPlanes = new Plane[planes.length];
+ for (int i = 0; i < planes.length; i++) {
+ mPlanes[i] = new PlaneWrapper(planes[i]);
+ }
+ }
+
+ public static ImageWrapper createFromImage(Image image) {
+ return new ImageWrapper(image);
+ }
+
+ @Override
+ public int getFormat() {
+ return mImage.getFormat();
+ }
+
+ @Override
+ public int getWidth() {
+ return mImage.getWidth();
+ }
+
+ @Override
+ public int getHeight() {
+ return mImage.getHeight();
+ }
+
+ @Override
+ public long getTimestamp() {
+ return mImage.getTimestamp();
+ }
+
+ @Override
+ public Plane[] getPlanes() {
+ return mPlanes;
+ }
+
+ @Override
+ public void close() {
+ mImage.close();
+ }
+
+ private static class PlaneWrapper extends CodecImage.Plane {
+ private final Image.Plane mPlane;
+
+ PlaneWrapper(Image.Plane plane) {
+ mPlane = plane;
+ }
+
+ @Override
+ public int getRowStride() {
+ return mPlane.getRowStride();
+ }
+
+ @Override
+ public int getPixelStride() {
+ return mPlane.getPixelStride();
+ }
+
+ @Override
+ public ByteBuffer getBuffer() {
+ return mPlane.getBuffer();
+ }
+ }
+ }
+
+
+ public native static int getImageChecksum(CodecImage image);
+ public native static void copyFlexYUVImage(CodecImage target, CodecImage source);
+
+ public static void copyFlexYUVImage(Image target, CodecImage source) {
+ copyFlexYUVImage(ImageWrapper.createFromImage(target), source);
+ }
+ public static void copyFlexYUVImage(Image target, Image source) {
+ copyFlexYUVImage(
+ ImageWrapper.createFromImage(target),
+ ImageWrapper.createFromImage(source));
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/DecoderTest.java b/tests/tests/media/src/android/media/cts/DecoderTest.java
index c8f2064..d79baf2 100644
--- a/tests/tests/media/src/android/media/cts/DecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/DecoderTest.java
@@ -942,7 +942,7 @@
}
public void testVP8Decode320x240() throws Exception {
- testDecode(R.raw.video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_48000hz, 249);
+ testDecode(R.raw.video_320x240_webm_vp8_800kbps_30fps_vorbis_stereo_128kbps_44100hz, 249);
}
public void testVP8Decode640x360() throws Exception {
@@ -987,7 +987,7 @@
}
public void testVP8Decode60fps1920x1080() throws Exception {
- testDecode(R.raw.video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_48000hz,
+ testDecode(R.raw.video_1920x1080_webm_vp8_20480kbps_60fps_vorbis_stereo_128kbps_44100hz,
249);
}
@@ -1006,7 +1006,7 @@
}
public void testVP9Decode30fps1280x720() throws Exception {
- testDecode(R.raw.video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_48000hz, 249);
+ testDecode(R.raw.video_1280x720_webm_vp9_4096kbps_30fps_vorbis_stereo_128kbps_44100hz, 249);
}
public void testVP9Decode30fps1920x1080() throws Exception {
@@ -1047,8 +1047,8 @@
testDecode(R.raw.video_1920x1080_mp4_hevc_10240kbps_30fps_aac_stereo_128kbps_44100hz, 299);
}
- public void testHEVCDecode30fps2840x2160() throws Exception {
- testDecode(R.raw.video_2840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz, 299);
+ public void testHEVCDecode30fps3840x2160() throws Exception {
+ testDecode(R.raw.video_3840x2160_mp4_hevc_20480kbps_30fps_aac_stereo_128kbps_44100hz, 299);
}
private void testCodecEarlyEOS(int resid, int eosFrame) throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
index afed27b..9d65a3d 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
@@ -22,7 +22,9 @@
import android.media.MediaCodecInfo.CodecProfileLevel;
import static android.media.MediaCodecInfo.CodecProfileLevel.*;
import static android.media.MediaFormat.MIMETYPE_VIDEO_AVC;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_H263;
import static android.media.MediaFormat.MIMETYPE_VIDEO_HEVC;
+import static android.media.MediaFormat.MIMETYPE_VIDEO_MPEG4;
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaPlayer;
@@ -76,6 +78,39 @@
}
}
+ // Android device implementations with H.263 encoders, MUST support Level 45.
+ public void testH263EncoderProfileAndLevel() throws Exception {
+ if (!MediaUtils.checkEncoder(MIMETYPE_VIDEO_H263)) {
+ return; // skip
+ }
+
+ assertTrue(
+ "H.263 must support Level 45",
+ hasEncoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level45));
+ }
+
+ // Android device implementations with H.263 decoders, MUST support Level 30.
+ public void testH263DecoderProfileAndLevel() throws Exception {
+ if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_H263)) {
+ return; // skip
+ }
+
+ assertTrue(
+ "H.263 must support Level 30",
+ hasDecoder(MIMETYPE_VIDEO_H263, MPEG4ProfileSimple, H263Level30));
+ }
+
+ // Android device implementations with MPEG-4 decoders, MUST support Simple Profile Level 3.
+ public void testMpeg4DecoderProfileAndLevel() throws Exception {
+ if (!MediaUtils.checkDecoder(MIMETYPE_VIDEO_MPEG4)) {
+ return; // skip
+ }
+
+ assertTrue(
+ "MPEG-4 must support Simple Profile Level 3",
+ hasDecoder(MIMETYPE_VIDEO_MPEG4, MPEG4ProfileSimple, MPEG4Level3));
+ }
+
// Android device implementations, when supporting H.265 codec MUST support the Main Profile
// Level 3 Main tier.
// Android Television Devices MUST support the Main Profile Level 4.1 Main tier.
@@ -96,7 +131,7 @@
hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain, HEVCMainTierLevel41));
}
- if (MediaUtils.canDecodeVideo(MIMETYPE_VIDEO_HEVC, 3840, 2160, 30)) {
+ if (isTv() && MediaUtils.canDecodeVideo(MIMETYPE_VIDEO_HEVC, 3840, 2160, 30)) {
assertTrue(
"H.265 must support Main10 Profile Main Tier Level 5 if UHD is supported",
hasDecoder(MIMETYPE_VIDEO_HEVC, HEVCProfileMain10, HEVCMainTierLevel5));
@@ -277,7 +312,18 @@
try {
CodecCapabilities caps = info.getCapabilitiesForType(mime);
for (CodecProfileLevel pl : caps.profileLevels) {
- if (pl.profile == profile && pl.level >= level) {
+ if (pl.profile != profile) {
+ continue;
+ }
+
+ // H.263 levels are not completely ordered:
+ // Level45 support only implies Level10 support
+ if (mime.equalsIgnoreCase(MIMETYPE_VIDEO_H263)) {
+ if (pl.level != level && pl.level == H263Level45 && level > H263Level10) {
+ continue;
+ }
+ }
+ if (pl.level >= level) {
return true;
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
index 4030636..9442d09 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecListTest.java
@@ -50,9 +50,10 @@
mAllCodecs.getCodecInfos();
class CodecType {
- CodecType(String type, boolean isEncoder) {
+ CodecType(String type, boolean isEncoder, MediaFormat sampleFormat) {
mMimeTypeName = type;
mIsEncoder = isEncoder;
+ mSampleFormat = sampleFormat;
}
boolean equals(CodecType codecType) {
@@ -60,10 +61,35 @@
mIsEncoder == codecType.mIsEncoder;
}
- String mMimeTypeName;
- boolean mIsEncoder;
+ boolean canBeFound() {
+ return codecCanBeFound(mIsEncoder, mSampleFormat);
+ }
+
+ @Override
+ public String toString() {
+ return mMimeTypeName + (mIsEncoder ? " encoder" : " decoder") + " for " + mSampleFormat;
+ }
+
+ private String mMimeTypeName;
+ private boolean mIsEncoder;
+ private MediaFormat mSampleFormat;
};
+ class AudioCodec extends CodecType {
+ AudioCodec(String mime, boolean isEncoder, int sampleRate) {
+ super(mime, isEncoder, MediaFormat.createAudioFormat(
+ mime, sampleRate, 1 /* channelCount */));
+ }
+ }
+
+ class VideoCodec extends CodecType {
+ VideoCodec(String mime, boolean isEncoder) {
+ // implicit assumption that QVGA video is always valid
+ super(mime, isEncoder, MediaFormat.createVideoFormat(
+ mime, 176 /* width */, 144 /* height */));
+ }
+ }
+
public static void testMediaCodecXmlFileExist() {
File file = new File(MEDIA_CODEC_XML_FILE);
assertTrue("/etc/media_codecs.xml does not exist", file.exists());
@@ -241,6 +267,9 @@
List<CodecType> requiredList = getRequiredCodecTypes();
List<CodecType> supportedList = getSupportedCodecTypes();
assertTrue(areRequiredCodecTypesSupported(requiredList, supportedList));
+ for (CodecType type : requiredList) {
+ assertTrue("cannot find " + type, type.canBeFound());
+ }
}
private boolean hasCamera() {
@@ -268,80 +297,8 @@
&& !pm.hasSystemFeature(pm.FEATURE_TELEVISION);
}
- // H263 baseline profile must be supported
- public void testIsH263BaselineProfileSupported() {
- if (!hasCamera()) {
- Log.d(TAG, "not required without camera");
- return;
- }
-
- int profile = CodecProfileLevel.H263ProfileBaseline;
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_H263, false, profile));
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_H263, true, profile));
- }
-
- // AVC baseline profile must be supported
- public void testIsAVCBaselineProfileSupported() {
- int profile = CodecProfileLevel.AVCProfileBaseline;
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_AVC, false, profile));
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_AVC, true, profile));
- }
-
- // HEVC main profile must be supported
- public void testIsHEVCMainProfileSupported() {
- int profile = CodecProfileLevel.HEVCProfileMain;
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_HEVC, false, profile));
- }
-
- // MPEG4 simple profile must be supported
- public void testIsM4VSimpleProfileSupported() {
- if (!hasCamera()) {
- Log.d(TAG, "not required without camera");
- return;
- }
-
- int profile = CodecProfileLevel.MPEG4ProfileSimple;
- assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_MPEG4, false, profile));
-
- // FIXME: no support for M4v simple profile video encoder
- // assertTrue(checkProfileSupported(MediaFormat.MIMETYPE_VIDEO_MPEG4, true, profile));
- }
-
- /*
- * Find whether the given codec is supported
- */
- private boolean checkProfileSupported(
- String mime, boolean isEncoder, int profile) {
- return profileIsListed(mime, isEncoder, profile) &&
- codecCanBeFound(mime, isEncoder);
- }
-
- private boolean profileIsListed(
- String mime, boolean isEncoder, int profile) {
-
- for (MediaCodecInfo info : mRegularInfos) {
- if (isEncoder != info.isEncoder()) {
- continue;
- }
-
- for (String type : info.getSupportedTypes()) {
- if (type.equalsIgnoreCase(mime)) {
- CodecCapabilities cap = info.getCapabilitiesForType(type);
- for (CodecProfileLevel pl : cap.profileLevels) {
- if (pl.profile == profile) {
- return true;
- }
- }
- }
- }
- }
- return false;
- }
-
// Find whether the given codec can be found using MediaCodecList.find methods.
- private boolean codecCanBeFound(String mime, boolean isEncoder) {
- // implicit assumption that QVGA video is always valid.
- MediaFormat format = MediaFormat.createVideoFormat(mime, 176, 144);
+ private boolean codecCanBeFound(boolean isEncoder, MediaFormat format) {
String codecName = isEncoder
? mRegularCodecs.findEncoderForFormat(format)
: mRegularCodecs.findDecoderForFormat(format);
@@ -380,7 +337,7 @@
assertTrue("Unexpected number of supported types", types.length > 0);
boolean isEncoder = info.isEncoder();
for (int j = 0; j < types.length; ++j) {
- supportedList.add(new CodecType(types[j], isEncoder));
+ supportedList.add(new CodecType(types[j], isEncoder, null /* sampleFormat */));
}
}
return supportedList;
@@ -393,39 +350,51 @@
private List<CodecType> getRequiredCodecTypes() {
List<CodecType> list = new ArrayList<CodecType>(16);
- // Mandatory audio codecs
+ // Mandatory audio decoders
// flac decoder is not omx-based yet
- // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false)); // flac decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_MPEG, false)); // mp3 decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_VORBIS, false)); // vorbis decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AAC, false)); // aac decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_RAW, false)); // raw/pcm decoder
+ // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false, 8000));
+ // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, false, 48000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_MPEG, false, 8000)); // mp3
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_MPEG, false, 48000)); // mp3
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_VORBIS, false, 8000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_VORBIS, false, 48000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, false, 8000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, false, 48000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_RAW, false, 8000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_RAW, false, 44100));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_OPUS, false, 48000));
+
+ // Mandatory audio encoders (for non-watch devices with camera)
+
if (hasMicrophone() && !isWatch()) {
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AAC, true)); // aac encoder
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, true, 8000));
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AAC, true, 48000));
// flac encoder is not required
- // list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_FLAC, true)); // flac encoder
- }
- if (isHandheld()) {
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_NB, false)); // amrnb decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_NB, true)); // amrnb encoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_WB, false)); // amrwb decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_AUDIO_AMR_WB, true)); // amrwb encoder
+ // list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_FLAC, true)); // encoder
}
- // Mandatory video codecs
+ // Mandatory audio encoders for handheld devices
+ if (isHandheld()) {
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_NB, false, 8000)); // decoder
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_NB, true, 8000)); // encoder
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_WB, false, 16000)); // decoder
+ list.add(new AudioCodec(MediaFormat.MIMETYPE_AUDIO_AMR_WB, true, 16000)); // encoder
+ }
+
+ // Mandatory video codecs (for non-watch devices)
if (!isWatch()) {
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_AVC, false)); // avc decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_AVC, true)); // avc encoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP8, false)); // vp8 decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP8, true)); // vp8 encoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_VP9, false)); // vp9 decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_H263, false)); // h263 decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_AVC, false)); // avc decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_AVC, true)); // avc encoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, false)); // vp8 decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP8, true)); // vp8 encoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_VP9, false)); // vp9 decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_HEVC, false)); // hevc decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_MPEG4, false)); // m4v decoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, false)); // h263 decoder
if (hasCamera()) {
- list.add(new CodecType(MediaFormat.MIMETYPE_VIDEO_H263, true)); // h263 encoder
+ list.add(new VideoCodec(MediaFormat.MIMETYPE_VIDEO_H263, true)); // h263 encoder
}
}
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
index 1ff5048..0aff8ed 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaCodecTest.java
@@ -19,6 +19,7 @@
import com.android.cts.media.R;
import android.content.res.AssetFileDescriptor;
+import android.cts.util.MediaUtils;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
@@ -80,27 +81,28 @@
* methods when called in incorrect operational states.
*/
public void testException() throws Exception {
- String mimeType = MediaFormat.MIMETYPE_AUDIO_AMR_WB;
- if (!supportsCodec(mimeType, false)) {
- Log.i(TAG, "No decoder found for mimeType= " + mimeType);
- return;
- }
+ boolean tested = false;
+ // audio decoder (MP3 should be present on all Android devices)
+ MediaFormat format = MediaFormat.createAudioFormat(
+ MediaFormat.MIMETYPE_AUDIO_MPEG, 44100 /* sampleRate */, 2 /* channelCount */);
+ tested = verifyException(format, false /* isEncoder */) || tested;
- MediaFormat[] formatList = new MediaFormat[2];
+ // audio encoder (AMR-WB may not be present on some Android devices)
+ format = MediaFormat.createAudioFormat(
+ MediaFormat.MIMETYPE_AUDIO_AMR_WB, 16000 /* sampleRate */, 1 /* channelCount */);
+ format.setInteger(MediaFormat.KEY_BIT_RATE, 19850);
+ tested = verifyException(format, true /* isEncoder */) || tested;
- // use audio format
- formatList[0] = new MediaFormat();
- formatList[0].setString(MediaFormat.KEY_MIME, mimeType);
- formatList[0].setInteger(MediaFormat.KEY_SAMPLE_RATE, 16000);
- formatList[0].setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
- formatList[0].setInteger(MediaFormat.KEY_BIT_RATE, 19850);
+ // video decoder (H.264/AVC may not be present on some Android devices)
+ format = createMediaFormat();
+ tested = verifyException(format, false /* isEncoder */) || tested;
- // use video format
- formatList[1] = createMediaFormat();
+ // video encoder (H.264/AVC may not be present on some Android devices)
+ tested = verifyException(format, true /* isEncoder */) || tested;
- for (MediaFormat format : formatList) {
- verifyIllegalStateException(format, false);
- verifyIllegalStateException(format, true);
+ // signal test is skipped due to no device media codecs.
+ if (!tested) {
+ MediaUtils.skipTest(TAG, "cannot find any compatible device codecs");
}
}
@@ -123,11 +125,17 @@
}
}
- private static void verifyIllegalStateException(MediaFormat format, boolean isEncoder)
+ private static boolean verifyException(MediaFormat format, boolean isEncoder)
throws IOException {
- MediaCodec codec;
+ String mimeType = format.getString(MediaFormat.KEY_MIME);
+ if (!supportsCodec(mimeType, isEncoder)) {
+ Log.i(TAG, "No " + (isEncoder ? "encoder" : "decoder")
+ + " found for mimeType= " + mimeType);
+ return false;
+ }
// create codec (enter Initialized State)
+ MediaCodec codec;
// create improperly
final String methodName = isEncoder ? "createEncoderByType" : "createDecoderByType";
@@ -270,6 +278,7 @@
fail("stop should not return MediaCodec.CodecException on wrong state");
} catch (IllegalStateException e) { // expected
}
+ return true;
}
/**
@@ -1081,4 +1090,4 @@
}
return false;
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
index a498eac..32fbfb5 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerFlakyNetworkTest.java
@@ -109,6 +109,7 @@
String[] supported = getSupportedVideos();
if (supported.length == 0) {
MediaUtils.skipTest("no codec found");
+ return;
}
Random random = new Random(seed);
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index d7bcd78..aed0029 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -91,7 +91,7 @@
testExtractor(R.raw.sinesweepwav);
testExtractor(R.raw.video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz);
- testExtractor(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz);
+ testExtractor(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz);
testExtractor(R.raw.video_1280x720_webm_vp9_309kbps_25fps_vorbis_stereo_128kbps_48000hz);
testExtractor(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz);
testExtractor(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz);
@@ -193,7 +193,7 @@
testDecoder(R.raw.sinesweepwav) +
testDecoder(R.raw.video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz) +
- testDecoder(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz) +
+ testDecoder(R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz) +
testDecoder(R.raw.video_1280x720_webm_vp9_309kbps_25fps_vorbis_stereo_128kbps_48000hz) +
testDecoder(R.raw.video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz) +
testDecoder(R.raw.video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz);
@@ -387,7 +387,7 @@
testVideoPlayback(
R.raw.video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz) +
testVideoPlayback(
- R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_48000hz) +
+ R.raw.video_1280x720_webm_vp8_333kbps_25fps_vorbis_stereo_128kbps_44100hz) +
testVideoPlayback(
R.raw.video_1280x720_webm_vp9_309kbps_25fps_vorbis_stereo_128kbps_48000hz) +
testVideoPlayback(
diff --git a/tests/tests/media/src/android/media/cts/PostProcTestBase.java b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
index b034763..c31693e 100644
--- a/tests/tests/media/src/android/media/cts/PostProcTestBase.java
+++ b/tests/tests/media/src/android/media/cts/PostProcTestBase.java
@@ -16,7 +16,9 @@
package android.media.cts;
+import android.content.Context;
import android.content.pm.PackageManager;
+import android.media.AudioManager;
import android.media.audiofx.AudioEffect;
import android.os.Looper;
import android.test.AndroidTestCase;
@@ -62,4 +64,13 @@
}
return AudioEffect.isEffectTypeAvailable(AudioEffect.EFFECT_TYPE_ENV_REVERB);
}
+
+ protected int getSessionId() {
+ AudioManager am = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
+ assertNotNull("could not get AudioManager", am);
+ int sessionId = am.generateAudioSessionId();
+ assertTrue("Could not generate session id", sessionId>0);
+ return sessionId;
+ }
+
}
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index e6f9656..4b5e0f0 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -164,6 +164,8 @@
protected MediaCodec mDecoder, mEncoder;
private VideoStorage mEncodedStream;
+ protected int mFrameRate = 0;
+ protected int mBitRate = 0;
protected void open(String path) throws IOException {
mExtractor = new MediaExtractor();
@@ -214,14 +216,24 @@
{
int maxWidth = encCaps.getSupportedWidths().getUpper();
int maxHeight = encCaps.getSupportedHeightsFor(maxWidth).getUpper();
- int maxRate =
- encCaps.getSupportedFrameRatesFor(maxWidth, maxHeight).getUpper().intValue();
- outFmt.setInteger(MediaFormat.KEY_FRAME_RATE, Math.min(30, maxRate));
- int bitRate = encCaps.getBitrateRange().clamp(
+ int frameRate = mFrameRate;
+ if (frameRate <= 0) {
+ int maxRate =
+ encCaps.getSupportedFrameRatesFor(maxWidth, maxHeight)
+ .getUpper().intValue();
+ frameRate = Math.min(30, maxRate);
+ }
+ outFmt.setInteger(MediaFormat.KEY_FRAME_RATE, frameRate);
+
+ int bitRate = mBitRate;
+ if (bitRate <= 0) {
+ bitRate = encCaps.getBitrateRange().clamp(
(int)(encCaps.getBitrateRange().getUpper() /
Math.sqrt(maxWidth * maxHeight / width / height)));
- Log.d(TAG, "max rate = " + maxRate + ", bit rate = " + bitRate);
+ }
outFmt.setInteger(MediaFormat.KEY_BIT_RATE, bitRate);
+
+ Log.d(TAG, "frame rate = " + frameRate + ", bit rate = " + bitRate);
}
outFmt.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1);
outFmt.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
@@ -305,6 +317,11 @@
mEncodedStream.playAll(surface);
}
+ public void setFrameAndBitRates(int frameRate, int bitRate) {
+ mFrameRate = frameRate;
+ mBitRate = bitRate;
+ }
+
public abstract boolean processLoop(
String path, String outMime, String videoEncName,
int width, int height, boolean optional);
@@ -879,13 +896,30 @@
return test(width, height, true /* optional */, flexYUV);
}
+ public boolean testDetailed(
+ int width, int height, int frameRate, int bitRate, boolean flexYUV) {
+ return test(width, height, frameRate, bitRate, true /* optional */, flexYUV);
+ }
+
+ public boolean testSupport(int width, int height, int frameRate, int bitRate) {
+ return mCaps.areSizeAndRateSupported(width, height, frameRate) &&
+ mCaps.getBitrateRange().contains(bitRate);
+ }
+
private boolean test(int width, int height, boolean optional, boolean flexYUV) {
+ return test(width, height, 0 /* frameRate */, 0 /* bitRate */, optional, flexYUV);
+ }
+
+ private boolean test(int width, int height, int frameRate, int bitRate,
+ boolean optional, boolean flexYUV) {
Log.i(TAG, "testing " + mMime + " on " + mName + " for " + width + "x" + height
+ (flexYUV ? " flexYUV" : " surface"));
VideoProcessorBase processor =
flexYUV ? new VideoProcessor() : new SurfaceVideoProcessor();
+ processor.setFrameAndBitRates(frameRate, bitRate);
+
// We are using a resource URL as an example
boolean success = processor.processLoop(
SOURCE_URL, mMime, mName, width, height, optional);
@@ -918,6 +952,21 @@
return encoders(mime, false /* goog */);
}
+ private Encoder[] combineArray(Encoder[] a, Encoder[] b) {
+ Encoder[] all = new Encoder[a.length + b.length];
+ System.arraycopy(a, 0, all, 0, a.length);
+ System.arraycopy(b, 0, all, a.length, b.length);
+ return all;
+ }
+
+ private Encoder[] h264() {
+ return combineArray(googH264(), otherH264());
+ }
+
+ private Encoder[] vp8() {
+ return combineArray(googVP8(), otherVP8());
+ }
+
private Encoder[] encoders(String mime, boolean goog) {
MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
ArrayList<Encoder> result = new ArrayList<Encoder>();
@@ -1277,6 +1326,89 @@
public void testOtherVP9Flex1080p() { specific(otherVP9(), 1920, 1080, true /* flex */); }
public void testOtherVP9Surf1080p() { specific(otherVP9(), 1920, 1080, false /* flex */); }
+ // Tests encoder profiles required by CDD.
+ // H264
+ public void testH264LowQualitySDSupport() {
+ support(h264(), 320, 240, 20, 384 * 1000);
+ }
+
+ public void testH264HighQualitySDSupport() {
+ support(h264(), 720, 480, 30, 2 * 1000000);
+ }
+
+ public void testH264FlexQVGA20fps384kbps() {
+ detailed(h264(), 320, 240, 20, 384 * 1000, true /* flex */);
+ }
+
+ public void testH264SurfQVGA20fps384kbps() {
+ detailed(h264(), 320, 240, 20, 384 * 1000, false /* flex */);
+ }
+
+ public void testH264Flex480p30fps2Mbps() {
+ detailed(h264(), 720, 480, 30, 2 * 1000000, true /* flex */);
+ }
+
+ public void testH264Surf480p30fps2Mbps() {
+ detailed(h264(), 720, 480, 30, 2 * 1000000, false /* flex */);
+ }
+
+ public void testH264Flex720p30fps4Mbps() {
+ detailed(h264(), 1280, 720, 30, 4 * 1000000, true /* flex */);
+ }
+
+ public void testH264Surf720p30fps4Mbps() {
+ detailed(h264(), 1280, 720, 30, 4 * 1000000, false /* flex */);
+ }
+
+ public void testH264Flex1080p30fps10Mbps() {
+ detailed(h264(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
+ }
+
+ public void testH264Surf1080p30fps10Mbps() {
+ detailed(h264(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
+ }
+
+ // VP8
+ public void testVP8LowQualitySDSupport() {
+ support(vp8(), 320, 180, 30, 800 * 1000);
+ }
+
+ public void testVP8HighQualitySDSupport() {
+ support(vp8(), 640, 360, 30, 2 * 1000000);
+ }
+
+ public void testVP8Flex180p30fps800kbps() {
+ detailed(vp8(), 320, 180, 30, 800 * 1000, true /* flex */);
+ }
+
+ public void testVP8Surf180p30fps800kbps() {
+ detailed(vp8(), 320, 180, 30, 800 * 1000, false /* flex */);
+ }
+
+ public void testVP8Flex360p30fps2Mbps() {
+ detailed(vp8(), 640, 360, 30, 2 * 1000000, true /* flex */);
+ }
+
+ public void testVP8Surf360p30fps2Mbps() {
+ detailed(vp8(), 640, 360, 30, 2 * 1000000, false /* flex */);
+ }
+
+ public void testVP8Flex720p30fps4Mbps() {
+ detailed(vp8(), 1280, 720, 30, 4 * 1000000, true /* flex */);
+ }
+
+ public void testVP8Surf720p30fps4Mbps() {
+ detailed(vp8(), 1280, 720, 30, 4 * 1000000, false /* flex */);
+ }
+
+ public void testVP8Flex1080p30fps10Mbps() {
+ detailed(vp8(), 1920, 1080, 30, 10 * 1000000, true /* flex */);
+ }
+
+ public void testVP8Surf1080p30fps10Mbps() {
+ detailed(vp8(), 1920, 1080, 30, 10 * 1000000, false /* flex */);
+ }
+
private void minmin(Encoder[] encoders, boolean flexYUV) {
extreme(encoders, 0 /* x */, 0 /* y */, flexYUV, false /* near */);
}
@@ -1357,4 +1489,43 @@
MediaUtils.skipTest("duplicate or unsupported resolution");
}
}
+
+ /* test size, frame rate and bit rate */
+ private void detailed(
+ Encoder[] encoders, int width, int height, int frameRate, int bitRate,
+ boolean flexYUV) {
+ if (encoders.length == 0) {
+ MediaUtils.skipTest("no such encoder present");
+ return;
+ }
+ boolean skipped = true;
+ for (Encoder encoder : encoders) {
+ if (encoder.testSupport(width, height, frameRate, bitRate)) {
+ skipped = false;
+ encoder.testDetailed(width, height, frameRate, bitRate, flexYUV);
+ }
+ }
+ if (skipped) {
+ MediaUtils.skipTest("unsupported resolution and rate");
+ }
+ }
+
+ /* test size and rate are supported */
+ private void support(Encoder[] encoders, int width, int height, int frameRate, int bitRate) {
+ boolean supported = false;
+ if (encoders.length == 0) {
+ MediaUtils.skipTest("no such encoder present");
+ return;
+ }
+ for (Encoder encoder : encoders) {
+ if (encoder.testSupport(width, height, frameRate, bitRate)) {
+ supported = true;
+ break;
+ }
+ }
+ if (!supported) {
+ fail("unsupported format " + width + "x" + height + " " +
+ frameRate + "fps " + bitRate + "bps");
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/VirtualizerTest.java b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
index 51adf1d..ac8eb84 100644
--- a/tests/tests/media/src/android/media/cts/VirtualizerTest.java
+++ b/tests/tests/media/src/android/media/cts/VirtualizerTest.java
@@ -16,14 +16,18 @@
package android.media.cts;
+import android.content.Context;
import android.media.audiofx.AudioEffect;
import android.media.AudioFormat;
-import android.media.AudioManager;
import android.media.audiofx.Virtualizer;
import android.os.Looper;
import android.test.AndroidTestCase;
import android.util.Log;
+import com.android.cts.media.R;
+
+import java.util.Arrays;
+
public class VirtualizerTest extends PostProcTestBase {
private String TAG = "VirtualizerTest";
@@ -288,6 +292,256 @@
}
//-----------------------------------------------------------------
+ // 4 virtualizer capabilities
+ //----------------------------------
+
+ //Test case 4.0: test virtualization format / mode query: at least one of the following
+ // combinations must be supported, otherwise the effect doesn't really qualify as
+ // a virtualizer: AudioFormat.CHANNEL_OUT_STEREO or the quad and 5.1 side/back variants,
+ // in VIRTUALIZATION_MODE_BINAURAL or VIRTUALIZATION_MODE_TRANSAURAL
+ public void test4_0FormatModeQuery() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ boolean isAtLeastOneConfigSupported = false;
+ boolean isConfigSupported = false;
+
+ // testing combinations of input channel mask and virtualization mode
+ for (int m = 0 ; m < VIRTUALIZATION_MODES.length ; m++) {
+ for (int i = 0 ; i < CHANNEL_MASKS.length ; i++) {
+ isConfigSupported = mVirtualizer.canVirtualize(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m]);
+ isAtLeastOneConfigSupported |= isConfigSupported;
+ // optional logging
+ String channelMask = Integer.toHexString(CHANNEL_MASKS[i]).toUpperCase();
+ String nativeChannelMask =
+ Integer.toHexString(CHANNEL_MASKS[i] >> 2).toUpperCase();
+ Log.d(TAG, "content channel mask: 0x" + channelMask + " (native 0x"
+ + nativeChannelMask
+ + ") mode: " + VIRTUALIZATION_MODES[m]
+ + " supported=" + isConfigSupported);
+ }
+ }
+
+ assertTrue("no valid configuration supported", isAtLeastOneConfigSupported);
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 4.1: test that the capabilities reported by Virtualizer.canVirtualize(int,int)
+ // matches those returned by Virtualizer.getSpeakerAngles(int, int, int[])
+ public void test4_1SpeakerAnglesCapaMatchesFormatModeCapa() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ // 3: see size requirement in Virtualizer.getSpeakerAngles(int, int, int[])
+ // 6: for number of channels of 5.1 masks in CHANNEL_MASKS
+ int[] angles = new int[3*6];
+ for (int m = 0 ; m < VIRTUALIZATION_MODES.length ; m++) {
+ for (int i = 0 ; i < CHANNEL_MASKS.length ; i++) {
+ Arrays.fill(angles,AudioFormat.CHANNEL_INVALID);
+ boolean canVirtualize = mVirtualizer.canVirtualize(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m]);
+ boolean canGetAngles = mVirtualizer.getSpeakerAngles(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m], angles);
+ assertTrue("mismatch capability between canVirtualize() and getSpeakerAngles()",
+ canVirtualize == canGetAngles);
+ if(canGetAngles) {
+ //check if the number of angles matched the expected number of channels for
+ //each CHANNEL_MASKS
+ int expectedChannelCount = CHANNEL_MASKS_CHANNEL_COUNT[i];
+ for(int k=0; k<expectedChannelCount; k++) {
+ int speakerIdentification = angles[k*3];
+ assertTrue("found unexpected speaker identification or channel count",
+ speakerIdentification !=AudioFormat.CHANNEL_INVALID );
+ }
+ }
+ }
+ }
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 4.2: test forcing virtualization mode: at least binaural or transaural must be
+ // supported
+ public void test4_2VirtualizationMode() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ mVirtualizer.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mVirtualizer.getEnabled());
+ // testing binaural
+ boolean binauralSupported =
+ mVirtualizer.forceVirtualizationMode(Virtualizer.VIRTUALIZATION_MODE_BINAURAL);
+ // testing transaural
+ boolean transauralSupported = mVirtualizer
+ .forceVirtualizationMode(Virtualizer.VIRTUALIZATION_MODE_TRANSAURAL);
+ // testing at least one supported
+ assertTrue("doesn't support binaural nor transaural",
+ binauralSupported || transauralSupported);
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 4.3: test disabling virtualization maps to VIRTUALIZATION_MODE_OFF
+ public void test4_3DisablingVirtualizationOff() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ mVirtualizer.setEnabled(false);
+ assertFalse("invalid state from getEnabled", mVirtualizer.getEnabled());
+ int virtMode = mVirtualizer.getVirtualizationMode();
+ assertTrue("disabled virtualization isn't reported as OFF",
+ virtMode == Virtualizer.VIRTUALIZATION_MODE_OFF);
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 4.4: test forcing virtualization mode to AUTO
+ public void test4_4VirtualizationModeAuto() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ mVirtualizer.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mVirtualizer.getEnabled());
+ boolean forceRes =
+ mVirtualizer.forceVirtualizationMode(Virtualizer.VIRTUALIZATION_MODE_AUTO);
+ assertTrue("can't set virtualization to AUTO", forceRes);
+
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //Test case 4.5: test for consistent capabilities if virtualizer is enabled or disabled
+ public void test4_5ConsistentCapabilitiesWithEnabledDisabled() throws Exception {
+ if (!isVirtualizerAvailable()) {
+ return;
+ }
+ getVirtualizer(getSessionId());
+ try {
+ // 3: see size requirement in Virtualizer.getSpeakerAngles(int, int, int[])
+ // 6: for number of channels of 5.1 masks in CHANNEL_MASKS
+ int[] angles = new int[3*6];
+ boolean[][] values = new boolean[VIRTUALIZATION_MODES.length][CHANNEL_MASKS.length];
+ mVirtualizer.setEnabled(true);
+ assertTrue("invalid state from getEnabled", mVirtualizer.getEnabled());
+ for (int m = 0 ; m < VIRTUALIZATION_MODES.length ; m++) {
+ for (int i = 0 ; i < CHANNEL_MASKS.length ; i++) {
+ Arrays.fill(angles,AudioFormat.CHANNEL_INVALID);
+ boolean canVirtualize = mVirtualizer.canVirtualize(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m]);
+ boolean canGetAngles = mVirtualizer.getSpeakerAngles(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m], angles);
+ assertTrue("mismatch capability between canVirtualize() and getSpeakerAngles()",
+ canVirtualize == canGetAngles);
+ values[m][i] = canVirtualize;
+ }
+ }
+
+ mVirtualizer.setEnabled(false);
+ assertTrue("invalid state from getEnabled", !mVirtualizer.getEnabled());
+ for (int m = 0 ; m < VIRTUALIZATION_MODES.length ; m++) {
+ for (int i = 0 ; i < CHANNEL_MASKS.length ; i++) {
+ Arrays.fill(angles,AudioFormat.CHANNEL_INVALID);
+ boolean canVirtualize = mVirtualizer.canVirtualize(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m]);
+ boolean canGetAngles = mVirtualizer.getSpeakerAngles(CHANNEL_MASKS[i],
+ VIRTUALIZATION_MODES[m], angles);
+ assertTrue("mismatch capability between canVirtualize() and getSpeakerAngles()",
+ canVirtualize == canGetAngles);
+ assertTrue("mismatch capability between enabled and disabled virtualizer",
+ canVirtualize == values[m][i]);
+ }
+ }
+
+ } catch (IllegalArgumentException e) {
+ fail("bad parameter value");
+ } catch (UnsupportedOperationException e) {
+ fail("command not supported");
+ } catch (IllegalStateException e) {
+ fail("command called in wrong state");
+ } finally {
+ releaseVirtualizer();
+ }
+ }
+
+ //-----------------------------------------------------------------
+ // private data
+ //----------------------------------
+ // channel masks to test at input of virtualizer
+ private static final int[] CHANNEL_MASKS = {
+ AudioFormat.CHANNEL_OUT_STEREO, //2 channels
+ AudioFormat.CHANNEL_OUT_QUAD, //4 channels
+ //AudioFormat.CHANNEL_OUT_QUAD_SIDE (definition is not public)
+ (AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT |
+ AudioFormat.CHANNEL_OUT_SIDE_LEFT | AudioFormat.CHANNEL_OUT_SIDE_RIGHT), //4 channels
+ AudioFormat.CHANNEL_OUT_5POINT1, //6 channels
+ //AudioFormat.CHANNEL_OUT_5POINT1_SIDE (definition is not public)
+ (AudioFormat.CHANNEL_OUT_FRONT_LEFT | AudioFormat.CHANNEL_OUT_FRONT_RIGHT |
+ AudioFormat.CHANNEL_OUT_FRONT_CENTER |
+ AudioFormat.CHANNEL_OUT_LOW_FREQUENCY |
+ AudioFormat.CHANNEL_OUT_SIDE_LEFT | AudioFormat.CHANNEL_OUT_SIDE_RIGHT) //6 channels
+ };
+
+ private static final int[] CHANNEL_MASKS_CHANNEL_COUNT = {
+ 2,
+ 4,
+ 4,
+ 6,
+ 6
+ };
+
+ private static final int[] VIRTUALIZATION_MODES = {
+ Virtualizer.VIRTUALIZATION_MODE_BINAURAL,
+ Virtualizer.VIRTUALIZATION_MODE_TRANSAURAL
+ };
+
+ //-----------------------------------------------------------------
// private methods
//----------------------------------
@@ -362,7 +616,6 @@
mLooper = Looper.myLooper();
mVirtualizer2 = new Virtualizer(0, 0);
- assertNotNull("could not create virtualizer2", mVirtualizer2);
synchronized(mLock) {
if (mControl) {
@@ -436,4 +689,4 @@
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/tests/net/src/android/net/cts/DnsTest.java b/tests/tests/net/src/android/net/cts/DnsTest.java
index 879a962..0377d04 100644
--- a/tests/tests/net/src/android/net/cts/DnsTest.java
+++ b/tests/tests/net/src/android/net/cts/DnsTest.java
@@ -16,6 +16,10 @@
package android.net.cts;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.os.SystemClock;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -34,6 +38,7 @@
private static final boolean DBG = false;
private static final String TAG = "DnsTest";
+ private static final String PROXY_NETWORK_TYPE = "PROXY";
/**
* @return true on success
@@ -71,6 +76,14 @@
// We should have at least one of the addresses to connect!
assertTrue(foundV4 || foundV6);
+ // Skip the rest of the test if the active network for watch is PROXY.
+ // TODO: Check NetworkInfo type in addition to type name once ag/601257 is merged.
+ if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH)
+ && activeNetworkInfoIsProxy()) {
+ Log.i(TAG, "Skipping test because the active network type name is PROXY.");
+ return;
+ }
+
try {
addrs = InetAddress.getAllByName("ipv6.google.com");
} catch (UnknownHostException e) {}
@@ -241,4 +254,15 @@
Log.e(TAG, "bad URL in testDnsPerf: " + e.toString());
}
}
+
+ private boolean activeNetworkInfoIsProxy() {
+ ConnectivityManager cm = (ConnectivityManager)
+ getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo info = cm.getActiveNetworkInfo();
+ if (PROXY_NETWORK_TYPE.equals(info.getTypeName())) {
+ return true;
+ }
+
+ return false;
+ }
}
diff --git a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java b/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
index 49fc59c..e9bfb43 100644
--- a/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
+++ b/tests/tests/net/src/android/net/ipv6/cts/PingTest.java
@@ -130,6 +130,7 @@
// Check the response is an echo reply.
byte[] response = new byte[bytesRead];
+ responseBuffer.flip();
responseBuffer.get(response, 0, bytesRead);
assertEquals((byte) 0x81, response[0]);
diff --git a/tests/tests/os/src/android/os/cts/BuildVersionTest.java b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
index 6069ee6..3002ca3 100644
--- a/tests/tests/os/src/android/os/cts/BuildVersionTest.java
+++ b/tests/tests/os/src/android/os/cts/BuildVersionTest.java
@@ -28,7 +28,8 @@
public class BuildVersionTest extends TestCase {
private static final String LOG_TAG = "BuildVersionTest";
- private static final Set<String> EXPECTED_RELEASES = new HashSet<String>(Arrays.asList("5.0"));
+ private static final Set<String> EXPECTED_RELEASES =
+ new HashSet<String>(Arrays.asList("5.0.1", "5.0.2"));
private static final int EXPECTED_SDK = 21;
private static final String EXPECTED_BUILD_VARIANT = "user";
private static final String EXPECTED_TAG = "release-keys";
diff --git a/tests/tests/provider/src/android/provider/cts/CalendarTest.java b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
index a8f547b..2f5edd0 100644
--- a/tests/tests/provider/src/android/provider/cts/CalendarTest.java
+++ b/tests/tests/provider/src/android/provider/cts/CalendarTest.java
@@ -352,6 +352,7 @@
Events.SYNC_DATA2,
Events.SYNC_DATA3,
Events.SYNC_DATA4,
+ Events.MUTATORS,
};
// @formatter:on
@@ -3275,6 +3276,67 @@
CalendarHelper.deleteCalendarByAccount(mContentResolver, account);
}
+ @MediumTest
+ public void testMutatorSetCorrectly() {
+ String account = "ec_account";
+ String packageName = "com.android.cts.provider";
+ int seed = 0;
+
+ // Clean up just in case
+ CalendarHelper.deleteCalendarByAccount(mContentResolver, account);
+
+ String mutator;
+ Cursor cursor;
+ ContentValues values = new ContentValues();
+ final long calendarId = createAndVerifyCalendar(account, seed++, null);
+
+ // Verify mutator is set to the package, via:
+ // Create:
+ final long eventId = createAndVerifyEvent(account, seed, calendarId, false, null);
+ final Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
+ cursor = mContentResolver.query(uri, new String[] {Events.MUTATORS}, null, null, null);
+ cursor.moveToFirst();
+ mutator = cursor.getString(0);
+ cursor.close();
+ assertEquals(packageName, mutator);
+
+ // Edit:
+ // First clear the mutator column
+ values.clear();
+ values.putNull(Events.MUTATORS);
+ mContentResolver.update(asSyncAdapter(uri, account, CTS_TEST_TYPE), values, null, null);
+ cursor = mContentResolver.query(uri, new String[] {Events.MUTATORS}, null, null, null);
+ cursor.moveToFirst();
+ mutator = cursor.getString(0);
+ cursor.close();
+ assertNull(mutator);
+ // Now edit the event and verify the mutator column
+ values.clear();
+ values.put(Events.TITLE, "New title");
+ mContentResolver.update(uri, values, null, null);
+ cursor = mContentResolver.query(uri, new String[] {Events.MUTATORS}, null, null, null);
+ cursor.moveToFirst();
+ mutator = cursor.getString(0);
+ cursor.close();
+ assertEquals(packageName, mutator);
+
+ // Clean up the event
+ assertEquals(1, EventHelper.deleteEventAsSyncAdapter(mContentResolver, uri, account));
+
+ // Delete:
+ // First create as sync adapter
+ final long eventId2 = createAndVerifyEvent(account, seed, calendarId, true, null);
+ final Uri uri2 = ContentUris.withAppendedId(Events.CONTENT_URI, eventId2);
+ // Now delete the event and verify
+ values.clear();
+ values.put(Events.MUTATORS, packageName);
+ removeAndVerifyEvent(uri2, values, account);
+
+
+ // delete the calendar
+ removeAndVerifyCalendar(account, calendarId);
+ }
+
/**
* Acquires the set of instances that appear between the specified start and end points.
*
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve3x3.java b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve3x3.java
index 1880132..8faeb22 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve3x3.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve3x3.java
@@ -24,11 +24,17 @@
float cf1[] = {0.f, 0.f, 0.f, 0.f, 1.f, 0.f, 0.f, 0.f, 0.f};
float cf2[] = {0.f, -1.f, 0.f, -1.f, 5.f, -1.f, 0.f, -1.f, 0.f};
+ float irCoeff1 = 3.1415927f;
+ float irCoeff2 = -irCoeff1;
+ float cf3[] = {0.f, irCoeff1, 0.f, irCoeff2, 1.f, irCoeff2, 0.f, irCoeff1, 0.f};
+
Element e = makeElement(dt, vecSize);
System.gc();
makeBuffers(w, h, e);
+ mVerify.set_gAllowedIntError(1);
+
ScriptIntrinsicConvolve3x3 si = ScriptIntrinsicConvolve3x3.create(mRS, e);
si.setCoefficients(cf1);
si.setInput(mAllocSrc);
@@ -116,6 +122,44 @@
}
//android.util.Log.e("RSI test", "test convolve U8_" + vecSize + " 2 " + w + ", " + h);
mVerify.invoke_verify(mAllocRef, mAllocDst, mAllocSrc);
+
+ si.setCoefficients(cf3);
+ sr.set_gCoeffs(cf3);
+ si.forEach(mAllocRef, sc);
+ if (dt == Element.DataType.UNSIGNED_8) {
+ switch(vecSize) {
+ case 4:
+ sr.forEach_convolve_U4(mAllocDst, sc);
+ break;
+ case 3:
+ sr.forEach_convolve_U3(mAllocDst, sc);
+ break;
+ case 2:
+ sr.forEach_convolve_U2(mAllocDst, sc);
+ break;
+ case 1:
+ sr.forEach_convolve_U1(mAllocDst, sc);
+ break;
+ }
+ } else {
+ switch(vecSize) {
+ case 4:
+ sr.forEach_convolve_F4(mAllocDst, sc);
+ break;
+ case 3:
+ sr.forEach_convolve_F3(mAllocDst, sc);
+ break;
+ case 2:
+ sr.forEach_convolve_F2(mAllocDst, sc);
+ break;
+ case 1:
+ sr.forEach_convolve_F1(mAllocDst, sc);
+ break;
+ }
+ }
+ //android.util.Log.e("RSI test", "test convolve U8_" + vecSize + " 2 " + w + ", " + h);
+ mVerify.invoke_verify(mAllocRef, mAllocDst, mAllocSrc);
+
mRS.finish();
}
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve5x5.java b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve5x5.java
index ee92651..0753c62 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve5x5.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/IntrinsicConvolve5x5.java
@@ -85,13 +85,24 @@
-1.f, 0.f, 0.f, 0.f, -1.f,
-1.f, -1.f, -1.f, -1.f, -1.f};
+ float irCoeff1 = 3.1415927f;
+ float irCoeff2 = -irCoeff1;
+ float cf3[] = {irCoeff1, -1.f, -1.f, -1.f, irCoeff2,
+ irCoeff1, 0.f, 0.f, 0.f, irCoeff2,
+ irCoeff1, 0.f, 7.f, 0.f, irCoeff2,
+ irCoeff1, 0.f, 0.f, 0.f, irCoeff2,
+ irCoeff1, -1.f, -1.f, -1.f, irCoeff2};
+
Element e = makeElement(dt, vecSize);
makeBuffers(w, h, e);
+ mVerify.set_gAllowedIntError(1);
+
ScriptIntrinsicConvolve5x5 si = ScriptIntrinsicConvolve5x5.create(mRS, e);
ScriptC_intrinsic_convolve5x5 sr = new ScriptC_intrinsic_convolve5x5(mRS);
test5(sr, si, e, cf1, "test convolve", 1, w, h, sc);
test5(sr, si, e, cf2, "test convolve", 2, w, h, sc);
+ test5(sr, si, e, cf3, "test convolve", 3, w, h, sc);
}
public void test_U8_4() {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/intrinsic_convolve5x5.rs b/tests/tests/renderscript/src/android/renderscript/cts/intrinsic_convolve5x5.rs
index 9f9aa2b..966dbdd 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/intrinsic_convolve5x5.rs
+++ b/tests/tests/renderscript/src/android/renderscript/cts/intrinsic_convolve5x5.rs
@@ -66,7 +66,7 @@
+ convert_float4(rsGetElementAt_uchar4(gIn, x3, y4)) * gCoeffs[23]
+ convert_float4(rsGetElementAt_uchar4(gIn, x4, y4)) * gCoeffs[24];
- p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
+ p0 = clamp(p0 + p1 + p2 + p3 + p4 + 0.5f, 0.f, 255.f);
return convert_uchar4(p0);
}
@@ -113,7 +113,7 @@
+ convert_float3(rsGetElementAt_uchar3(gIn, x3, y4)) * gCoeffs[23]
+ convert_float3(rsGetElementAt_uchar3(gIn, x4, y4)) * gCoeffs[24];
- p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
+ p0 = clamp(p0 + p1 + p2 + p3 + p4 + 0.5f, 0.f, 255.f);
return convert_uchar3(p0);
}
@@ -160,7 +160,7 @@
+ convert_float2(rsGetElementAt_uchar2(gIn, x3, y4)) * gCoeffs[23]
+ convert_float2(rsGetElementAt_uchar2(gIn, x4, y4)) * gCoeffs[24];
- p0 = clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
+ p0 = clamp(p0 + p1 + p2 + p3 + p4 + 0.5f, 0.f, 255.f);
return convert_uchar2(p0);
}
@@ -207,7 +207,7 @@
+ (float)(rsGetElementAt_uchar(gIn, x3, y4)) * gCoeffs[23]
+ (float)(rsGetElementAt_uchar(gIn, x4, y4)) * gCoeffs[24];
- return clamp(p0 + p1 + p2 + p3 + p4, 0.f, 255.f);
+ return clamp(p0 + p1 + p2 + p3 + p4 + 0.5f, 0.f, 255.f);
}
float4 __attribute__((kernel)) convolve_F4(uint32_t x, uint32_t y) {
diff --git a/tests/tests/security/src/android/security/cts/CertificateData.java b/tests/tests/security/src/android/security/cts/CertificateData.java
index da098f3..de7c15e 100644
--- a/tests/tests/security/src/android/security/cts/CertificateData.java
+++ b/tests/tests/security/src/android/security/cts/CertificateData.java
@@ -28,9 +28,11 @@
"91:C6:D6:EE:3E:8A:C8:63:84:E5:48:C2:99:29:5C:75:6C:81:7B:81",
"4A:65:D5:F4:1D:EF:39:B8:B8:90:4A:4A:D3:64:81:33:CF:C7:A1:D1",
"16:32:47:8D:89:F9:21:3A:92:00:85:63:F5:A4:A7:D3:12:40:8A:D6",
+ "D1:CB:CA:5D:B2:D5:2A:7F:69:3B:67:4D:E5:F0:5A:1D:0C:95:7D:F0",
"4D:23:78:EC:91:95:39:B5:00:7F:75:8F:03:3B:21:1E:C5:4D:8B:CF",
"E7:B4:F6:9D:61:EC:90:69:DB:7E:90:A7:40:1A:3C:F4:7D:4F:E8:EE",
"DD:E1:D2:A9:01:80:2E:1D:87:5E:84:B3:80:7E:4B:B1:FD:99:41:34",
+ "69:69:56:2E:40:80:F4:24:A1:E7:19:9F:14:BA:F3:EE:58:AB:6A:BB",
"92:5A:8F:8D:2C:6D:04:E0:66:5F:59:6A:FF:22:D8:63:E8:25:6F:3F",
"75:E0:AB:B6:13:85:12:27:1C:04:F8:5F:DD:DE:38:E4:B7:24:2E:FE",
"40:9D:4B:D9:17:B5:5C:27:B6:9B:64:CB:98:22:44:0D:CD:09:B8:89",
@@ -49,6 +51,7 @@
"27:96:BA:E6:3F:18:01:E2:77:26:1B:A0:D7:77:70:02:8F:20:EE:E4",
"AD:7E:1C:28:B0:64:EF:8F:60:03:40:20:14:C3:D0:E3:37:0E:B5:8A",
"8D:17:84:D5:37:F3:03:7D:EC:70:FE:57:8B:51:9A:99:E6:10:D7:B0",
+ "1F:24:C6:30:CD:A4:18:EF:20:69:FF:AD:4F:DD:5F:46:3A:1B:69:AA",
"AE:50:83:ED:7C:F4:5C:BC:8F:61:C6:21:FE:68:5D:79:42:21:15:6E",
"DA:FA:F7:FA:66:84:EC:06:8F:14:50:BD:C7:C2:81:A5:BC:A9:64:57",
"74:F8:A3:C3:EF:E7:B3:90:06:4B:83:90:3C:21:64:60:20:E5:DF:CE",
@@ -56,6 +59,7 @@
"3E:2B:F7:F2:03:1B:96:F3:8C:E6:C4:D8:A8:5D:3E:2D:58:47:6A:0F",
"A3:F1:33:3F:E2:42:BF:CF:C5:D1:4E:8F:39:42:98:40:68:10:D1:A0",
"5F:43:E5:B1:BF:F8:78:8C:AC:1C:C7:CA:4A:9A:C6:22:2B:CC:34:C6",
+ "2B:8F:1B:57:33:0D:BB:A2:D0:7A:6C:51:F7:0E:E9:0D:DA:B9:AD:8E",
"A8:98:5D:3A:65:E5:E5:C4:B2:D7:D6:6D:40:C6:DD:2F:B1:9C:54:36",
"59:22:A1:E1:5A:EA:16:35:21:F8:98:39:6A:46:46:B0:44:1B:0F:A9",
"D4:DE:20:D0:5E:66:FC:53:FE:1A:50:88:2C:78:DB:28:52:CA:E4:74",
@@ -155,6 +159,7 @@
"87:82:C6:C3:04:35:3B:CF:D2:96:92:D2:59:3E:7D:44:D9:34:FF:11",
"59:0D:2D:7D:88:4F:40:2E:61:7E:A5:62:32:17:65:CF:17:D8:94:E9",
"AE:C5:FB:3F:C8:E1:BF:C4:E5:4F:03:07:5A:9A:E8:00:B7:F7:B6:FA",
+ "AF:E5:D2:44:A8:D1:19:42:30:FF:47:9F:E2:F8:97:BB:CD:7A:8C:B4",
"5F:3B:8C:F2:F8:10:B3:7D:78:B4:CE:EC:19:19:C3:73:34:B9:C7:74",
"2A:C8:D5:8B:57:CE:BF:2F:49:AF:F2:FC:76:8F:51:14:62:90:7A:41",
"F1:7F:6F:B6:31:DC:99:E3:A3:C8:7F:FE:1C:F1:81:10:88:D9:60:33",
diff --git a/tests/tests/uirendering/res/layout/blue_padded_layout.xml b/tests/tests/uirendering/res/layout/blue_padded_layout.xml
index 1cd1b21..68c9cd1 100644
--- a/tests/tests/uirendering/res/layout/blue_padded_layout.xml
+++ b/tests/tests/uirendering/res/layout/blue_padded_layout.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/test_root"
android:layout_width="200px"
android:layout_height="200px"
android:clipChildren="false">
diff --git a/tests/tests/uirendering/res/layout/blue_padded_square.xml b/tests/tests/uirendering/res/layout/blue_padded_square.xml
index 0f254d4..71f4b0c 100644
--- a/tests/tests/uirendering/res/layout/blue_padded_square.xml
+++ b/tests/tests/uirendering/res/layout/blue_padded_square.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="100px"
- android:layout_height="100px"
- android:background="@drawable/blue_padded_square"/>
+ android:id="@+id/test_root"
+ android:layout_width="100px"
+ android:layout_height="100px"
+ android:background="@drawable/blue_padded_square"/>
diff --git a/tests/tests/uirendering/res/layout/simple_rect_layout.xml b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
index e64c4e9..b570df8 100644
--- a/tests/tests/uirendering/res/layout/simple_rect_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_rect_layout.xml
@@ -13,11 +13,11 @@
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:id="@+id/test_root"
android:layout_width="match_parent"
- android:layout_height="match_parent">
+ android:layout_height="match_parent"
+ android:orientation="vertical">
<View android:layout_width="100px"
android:layout_height="100px"
diff --git a/tests/tests/uirendering/res/layout/simple_red_layout.xml b/tests/tests/uirendering/res/layout/simple_red_layout.xml
index 1ae3e38..2d2d189 100644
--- a/tests/tests/uirendering/res/layout/simple_red_layout.xml
+++ b/tests/tests/uirendering/res/layout/simple_red_layout.xml
@@ -14,6 +14,7 @@
limitations under the License.
-->
<View xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
+ android:id="@+id/test_root"
+ android:layout_width="180px"
+ android:layout_height="180px"
android:background="#f00" />
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
index 978dc0b..36be5f0f 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapcomparers/ExactComparer.java
@@ -41,9 +41,11 @@
for (int x = 0 ; x < width ; x++) {
int index = indexFromXAndY(x, y, stride, offset);
if (ideal[index] != given[index]) {
- Log.d(TAG, "Failure on position x = " + x + " y = " + y);
- Log.d(TAG, "Expected color : " + Integer.toHexString(ideal[index]) +
- " given color : " + Integer.toHexString(given[index]));
+ if (count < 50) {
+ Log.d(TAG, "Failure on position x = " + x + " y = " + y);
+ Log.d(TAG, "Expected color : " + Integer.toHexString(ideal[index]) +
+ " given color : " + Integer.toHexString(given[index]));
+ }
count++;
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
index ab809f4..0bdcc9b 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/bitmapverifiers/PerPixelBitmapVerifier.java
@@ -38,30 +38,33 @@
public boolean verify(int[] bitmap, int offset, int stride, int width, int height) {
- boolean res = true;
+ int failCount = 0;
int[] differenceMap = new int[bitmap.length];
for (int y = 0 ; y < height ; y++) {
for (int x = 0 ; x < width ; x++) {
int index = indexFromXAndY(x, y, stride, offset);
int expectedColor = getExpectedColor(x, y);
if (!verifyPixel(bitmap[index], expectedColor)) {
- Log.d(TAG, "Expected : " + Integer.toHexString(expectedColor)
- + " received : " + Integer.toHexString(bitmap[index])
- + " at position (" + x + "," + y + ")");
- res = false;
+ if (failCount < 50) {
+ Log.d(TAG, "Expected : " + Integer.toHexString(expectedColor)
+ + " received : " + Integer.toHexString(bitmap[index])
+ + " at position (" + x + "," + y + ")");
+ }
+ failCount++;
differenceMap[index] = FAIL_COLOR;
} else {
differenceMap[index] = PASS_COLOR;
}
}
}
- if (!res) {
+ boolean success = failCount == 0;
+ if (!success) {
mDifferenceBitmap = Bitmap.createBitmap(ActivityTestBase.TEST_WIDTH,
ActivityTestBase.TEST_HEIGHT, Bitmap.Config.ARGB_8888);
mDifferenceBitmap.setPixels(differenceMap, offset, stride, 0, 0,
ActivityTestBase.TEST_WIDTH, ActivityTestBase.TEST_HEIGHT);
}
- return res;
+ return success;
}
protected boolean verifyPixel(int color, int expectedColor) {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
index 0ba0f69..4667ee9 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/LayoutTests.java
@@ -15,32 +15,26 @@
*/
package android.uirendering.cts.testclasses;
+import android.graphics.Color;
+import android.graphics.Rect;
+import android.uirendering.cts.bitmapverifiers.ColorVerifier;
+import android.uirendering.cts.bitmapverifiers.RectVerifier;
import com.android.cts.uirendering.R;
import android.test.suitebuilder.annotation.SmallTest;
-import android.uirendering.cts.bitmapcomparers.BitmapComparer;
-import android.uirendering.cts.bitmapcomparers.ExactComparer;
import android.uirendering.cts.testinfrastructure.ActivityTestBase;
-
-/**
- * Created to see how custom views made with XML and programatic code will work.
- */
public class LayoutTests extends ActivityTestBase {
- private BitmapComparer mBitmapComparer;
-
- public LayoutTests() {
- mBitmapComparer = new ExactComparer();
- }
-
@SmallTest
public void testSimpleRedLayout() {
- createTest().addLayout(R.layout.simple_red_layout, null).runWithComparer(mBitmapComparer);
+ createTest().addLayout(R.layout.simple_red_layout, null, false).runWithVerifier(
+ new ColorVerifier(Color.RED));
}
@SmallTest
public void testSimpleRectLayout() {
- createTest().addLayout(R.layout.simple_rect_layout, null).runWithComparer(mBitmapComparer);
+ createTest().addLayout(R.layout.simple_rect_layout, null, false).runWithVerifier(
+ new RectVerifier(Color.WHITE, Color.BLUE, new Rect(0, 0, 100, 100)));
}
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
index 1acdc20..da2db48 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testclasses/ViewClippingTests.java
@@ -62,7 +62,7 @@
};
// TODO: attempt to reduce
- static final int TOLERANCE = 10;
+ static final int TOLERANCE = 16;
static BitmapVerifier makeClipVerifier(Rect blueBoundsRect) {
return new RectVerifier(Color.WHITE, Color.BLUE, blueBoundsRect, TOLERANCE);
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
index 052b251..386c015 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/ActivityTestBase.java
@@ -38,7 +38,7 @@
*/
public abstract class ActivityTestBase extends
ActivityInstrumentationTestCase2<DrawActivity> {
- public static final String TAG_NAME = "ActivityTestBase";
+ public static final String TAG = "ActivityTestBase";
public static final boolean DEBUG = false;
public static final boolean USE_RS = false;
public static final int TEST_WIDTH = 180;
@@ -97,7 +97,7 @@
for (TestCase testCase : testCases) {
if (!testCase.wasTestRan) {
- Log.w(TAG_NAME, getName() + " not all of the tests were ran");
+ Log.w(TAG, getName() + " not all of the tests ran");
break;
}
}
@@ -115,6 +115,13 @@
getActivity().runOnUiThread(finishRunnable);
}
+ static int[] getBitmapPixels(Bitmap bitmap) {
+ int[] pixels = new int[bitmap.getWidth() * bitmap.getHeight()];
+ bitmap.getPixels(pixels, 0, bitmap.getWidth(),
+ 0, 0, bitmap.getWidth(), bitmap.getHeight());
+ return pixels;
+ }
+
public Bitmap takeScreenshot() {
getInstrumentation().waitForIdleSync();
Bitmap bitmap1 = getInstrumentation().getUiAutomation().takeScreenshot();
@@ -124,7 +131,7 @@
bitmap2 = bitmap1;
bitmap1 = getInstrumentation().getUiAutomation().takeScreenshot();
count++;
- } while (count < MAX_SCREEN_SHOTS && !Arrays.equals(bitmap2.mBuffer, bitmap1.mBuffer));
+ } while (count < MAX_SCREEN_SHOTS && !Arrays.equals(getBitmapPixels(bitmap2), getBitmapPixels(bitmap1)));
return bitmap1;
}
@@ -213,6 +220,11 @@
* every test case is tested against it.
*/
public void runWithComparer(BitmapComparer bitmapComparer) {
+ if (getActivity().getOnWatch()) {
+ Log.d(TAG, getName() + "skipped");
+ return;
+ }
+
if (mTestCases.size() == 0) {
throw new IllegalStateException("Need at least one test to run");
}
@@ -231,6 +243,11 @@
* the verifier given.
*/
public void runWithVerifier(BitmapVerifier bitmapVerifier) {
+ if (getActivity().getOnWatch()) {
+ Log.d(TAG, getName() + "skipped");
+ return;
+ }
+
if (mTestCases.size() == 0) {
throw new IllegalStateException("Need at least one test to run");
}
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
index 4d4a012..166b6ff 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/testinfrastructure/DrawActivity.java
@@ -17,15 +17,16 @@
import android.annotation.Nullable;
import android.app.Activity;
-import android.content.Context;
+import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
-import android.util.AttributeSet;
import android.view.View;
import android.view.ViewTreeObserver;
import android.webkit.WebView;
+import com.android.cts.uirendering.R;
+
/**
* A generic activity that uses a view specified by the user.
*/
@@ -36,16 +37,17 @@
private Handler mHandler;
private View mView;
+ private boolean mOnWatch;
public void onCreate(Bundle bundle){
super.onCreate(bundle);
mHandler = new RenderSpecHandler();
+ int uiMode = getResources().getConfiguration().uiMode;
+ mOnWatch = (uiMode & Configuration.UI_MODE_TYPE_WATCH) == Configuration.UI_MODE_TYPE_WATCH;
}
- @Override
- public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
- mView = parent;
- return super.onCreateView(parent, name, context, attrs);
+ public boolean getOnWatch() {
+ return mOnWatch;
}
public void enqueueRenderSpecAndWait(int layoutId, CanvasClient canvasClient, String webViewUrl,
@@ -85,6 +87,10 @@
switch (message.what) {
case LAYOUT_MSG: {
setContentView(message.arg1);
+ mView = findViewById(R.id.test_root);
+ if (mView == null) {
+ throw new IllegalStateException("test_root failed to inflate");
+ }
} break;
case CANVAS_MSG: {
diff --git a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
index 41e255b..8dd98b0 100644
--- a/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
+++ b/tests/tests/uirendering/src/android/uirendering/cts/util/BitmapDumper.java
@@ -99,9 +99,25 @@
saveFile(className, testName, SINGULAR_FILE_NAME, bitmap);
}
+ private static void logIfBitmapSolidColor(String bitmapName, Bitmap bitmap) {
+ int firstColor = bitmap.getPixel(0, 0);
+ for (int x = 0; x < bitmap.getWidth(); x++) {
+ for (int y = 0; y < bitmap.getHeight(); y++) {
+ if (bitmap.getPixel(x, y) != firstColor) {
+ return;
+ }
+ }
+ }
+
+ Log.w(TAG, String.format("%s entire bitmap color is %x", bitmapName, firstColor));
+ }
+
private static void saveFile(String className, String testName, String fileName, Bitmap bitmap) {
- Log.d(TAG, "Saving file : " + testName + "_" + fileName + " in directory : " + className);
- File file = new File(CAPTURE_SUB_DIRECTORY + className, testName + "_" + fileName);
+ String bitmapName = testName + "_" + fileName;
+ Log.d(TAG, "Saving file : " + bitmapName + " in directory : " + className);
+ logIfBitmapSolidColor(bitmapName, bitmap);
+
+ File file = new File(CAPTURE_SUB_DIRECTORY + className, bitmapName);
FileOutputStream fileStream = null;
try {
fileStream = new FileOutputStream(file);
diff --git a/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java b/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
index fb44334..e8f0cab 100644
--- a/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/URLUtilTest.java
@@ -144,7 +144,7 @@
public void testGuessFileName() {
String url = "ftp://example.url/test";
- assertEquals("test.jpeg", URLUtil.guessFileName(url, null, "image/jpeg"));
+ assertEquals("test.jpg", URLUtil.guessFileName(url, null, "image/jpeg"));
assertEquals("test.bin", URLUtil.guessFileName(url, null, "application/octet-stream"));
}
diff --git a/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java b/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
index 41018a9..9589fec 100644
--- a/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/MockPopupWindowCtsActivity.java
@@ -30,28 +30,10 @@
* Stub activity for testing {@link PopupWindow}
*/
public class MockPopupWindowCtsActivity extends Activity {
- private boolean isFirstRun = true;
-
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Window window = getWindow();
- final View decor = window.getDecorView();
- decor.setOnApplyWindowInsetsListener(new OnApplyWindowInsetsListener() {
- @Override
- public WindowInsets onApplyWindowInsets(View v, WindowInsets insets) {
- if (isFirstRun) {
- if (insets.isRound()) {
- decor.setPadding(decor.getPaddingLeft(), decor.getPaddingTop(),
- decor.getPaddingRight(),
- decor.getPaddingBottom() + insets.getSystemWindowInsetBottom());
- }
- isFirstRun = false;
- setContentView(R.layout.popupwindow);
- }
- return insets.consumeSystemWindowInsets();
- }
- });
+ setContentView(R.layout.popupwindow);
}
}
diff --git a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
index e1742c8..c14bb03 100644
--- a/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
+++ b/tests/tests/widget/src/android/widget/cts/PopupWindowTest.java
@@ -273,18 +273,21 @@
}
public void testShowAtLocation() {
- int[] viewInWindowXY = new int[2];
- int[] viewOnScreenXY = new int[2];
+ int[] popupContentViewInWindowXY = new int[2];
+ int[] popupContentViewOnScreenXY = new int[2];
mPopupWindow = createPopupWindow(createPopupContent());
+ // Do not attach within the decor; we will be measuring location
+ // with regard to screen coordinates.
+ mPopupWindow.setAttachedInDecor(false);
final View upperAnchor = mActivity.findViewById(R.id.anchor_upper);
final int xOff = 10;
final int yOff = 21;
assertFalse(mPopupWindow.isShowing());
- mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
- assertEquals(0, viewInWindowXY[0]);
- assertEquals(0, viewInWindowXY[1]);
+ mPopupWindow.getContentView().getLocationInWindow(popupContentViewInWindowXY);
+ assertEquals(0, popupContentViewInWindowXY[0]);
+ assertEquals(0, popupContentViewInWindowXY[1]);
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
@@ -294,12 +297,12 @@
mInstrumentation.waitForIdleSync();
assertTrue(mPopupWindow.isShowing());
- mPopupWindow.getContentView().getLocationInWindow(viewInWindowXY);
- mPopupWindow.getContentView().getLocationOnScreen(viewOnScreenXY);
- assertTrue(viewInWindowXY[0] >= 0);
- assertTrue(viewInWindowXY[1] >= 0);
- assertEquals(viewInWindowXY[0] + xOff, viewOnScreenXY[0]);
- assertEquals(viewInWindowXY[1] + yOff, viewOnScreenXY[1]);
+ mPopupWindow.getContentView().getLocationInWindow(popupContentViewInWindowXY);
+ mPopupWindow.getContentView().getLocationOnScreen(popupContentViewOnScreenXY);
+ assertTrue(popupContentViewInWindowXY[0] >= 0);
+ assertTrue(popupContentViewInWindowXY[1] >= 0);
+ assertEquals(popupContentViewInWindowXY[0] + xOff, popupContentViewOnScreenXY[0]);
+ assertEquals(popupContentViewInWindowXY[1] + yOff, popupContentViewOnScreenXY[1]);
dismissPopup();
}
@@ -453,6 +456,9 @@
mInstrumentation.runOnMainSync(new Runnable() {
public void run() {
mPopupWindow = createPopupWindow(createPopupContent());
+ // Do not attach within the decor; we will be measuring location
+ // with regard to screen coordinates.
+ mPopupWindow.setAttachedInDecor(false);
}
});
diff --git a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
index c8211f6..5259736 100644
--- a/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TableLayoutTest.java
@@ -404,8 +404,8 @@
// exceptional
try {
tableLayout.addView(null);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
}
}
@@ -445,8 +445,8 @@
try {
tableLayout.addView(null, -1);
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
}
}
@@ -477,8 +477,8 @@
try {
tableLayout.addView(null, new TableLayout.LayoutParams(200, 300));
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
}
try {
@@ -540,8 +540,8 @@
try {
tableLayout.addView(null, -1, new TableLayout.LayoutParams(200, 300));
- fail("Should throw NullPointerException");
- } catch (NullPointerException e) {
+ fail("Should throw IllegalArgumentException");
+ } catch (IllegalArgumentException e) {
}
try {
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
index 1eb4acb..62c268d 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoConstants.java
@@ -68,4 +68,5 @@
public static final String SERIAL_NUMBER = "deviceID";
public static final String STORAGE_DEVICES = "storage_devices";
public static final String MULTI_USER = "multi_user";
+ public static final String ENCRYPTED = "encrypted";
}
diff --git a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
index 19349e5..52ddfe9 100644
--- a/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
+++ b/tools/device-setup/TestDeviceSetup/src/android/tests/getinfo/DeviceInfoInstrument.java
@@ -149,6 +149,9 @@
// Multi-user support
addResult(MULTI_USER, getMultiUserInfo());
+ // Encrypted
+ addResult(ENCRYPTED, getEncrypted());
+
finish(Activity.RESULT_OK, mResults);
}
@@ -394,4 +397,29 @@
return "unknown";
}
+
+ private static String getProperty(String property)
+ throws IOException {
+ Process process = new ProcessBuilder("getprop", property).start();
+ Scanner scanner = null;
+ String line = "";
+ try {
+ scanner = new Scanner(process.getInputStream());
+ line = scanner.nextLine();
+ } finally {
+ if (scanner != null) {
+ scanner.close();
+ }
+ }
+ return line;
+ }
+
+ private int getEncrypted() {
+ try {
+ return "encrypted".equals(getProperty("ro.crypto.state")) ? 1 : 0;
+ } catch (IOException e) {
+ }
+
+ return 0;
+ }
}
diff --git a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
index 42724e5..7e8a19e 100644
--- a/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
+++ b/tools/tradefed-host/src/com/android/cts/tradefed/build/CtsBuildProvider.java
@@ -31,7 +31,7 @@
@Option(name="cts-install-path", description="the path to the cts installation to use")
private String mCtsRootDirPath = System.getProperty("CTS_ROOT");
- public static final String CTS_BUILD_VERSION = "5.0_r1.93";
+ public static final String CTS_BUILD_VERSION = "5.0_r1.94";
/**
* {@inheritDoc}