Merge "Add CTS test for new added functions in BluetoothLeAudioCodecConfig"
diff --git a/Android.bp b/Android.bp
index 0d50878..0598d5d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,33 +1,6 @@
package {
- default_applicable_licenses: ["cts_license"],
-}
-
-// Added automatically by a large-scale-change that took the approach of
-// 'apply every license found to every target'. While this makes sure we respect
-// every license restriction, it may not be entirely correct.
-//
-// e.g. GPL in an MIT project might only apply to the contrib/ directory.
-//
-// Please consider splitting the single license below into multiple licenses,
-// taking care not to lose any license_kind information, and overriding the
-// default license using the 'licenses: [...]' property on targets as needed.
-//
-// For unused files, consider creating a 'fileGroup' with "//visibility:private"
-// to attach the license to, and including a comment whether the files may be
-// used in the current project.
-// See: http://go/android-license-faq
-license {
- name: "cts_license",
- visibility: [":__subpackages__"],
- license_kinds: [
- "SPDX-license-identifier-Apache-2.0",
- "SPDX-license-identifier-BSD",
- "SPDX-license-identifier-CC-BY",
- "SPDX-license-identifier-MIT",
- "SPDX-license-identifier-NCSA",
- "legacy_unencumbered",
- ],
- // large-scale-change unable to identify any license_text files
+ // See: http://go/android-license-faq
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
java_defaults {
diff --git a/apps/CtsVerifier/Android.bp b/apps/CtsVerifier/Android.bp
index a73691d..41eb311 100644
--- a/apps/CtsVerifier/Android.bp
+++ b/apps/CtsVerifier/Android.bp
@@ -16,13 +16,33 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-BSD
- // SPDX-license-identifier-CC-BY
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "cts_apps_CtsVerifier_opencv_license",
+ "Android-Apache-2.0",
+ "cts_apps_CtsVerifier_fatcow_license",
+ ]
+}
+
+license {
+ name: "cts_apps_CtsVerifier_opencv_license",
+ package_name: "opencv",
+ license_kinds: [
+ "SPDX-license-identifier-BSD",
+ ],
+ license_text: [
+ "libs/opencv-android_LICENSE",
+ "res/raw/opencv_library_license",
+ ],
+}
+
+// See: src/com/android/cts/verifier/features/FeatureSummaryActivity.java
+license {
+ name: "cts_apps_CtsVerifier_fatcow_license",
+ package_name: "fatcow icons",
+ license_kinds: [
+ "SPDX-license-identifier-CC-BY-3.0",
+ ],
+ license_text: ["LICENSE_CC_BY"],
}
filegroup {
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index 2f80d79..00a486d 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -1463,6 +1463,27 @@
android:value="multi_display_mode" />
</activity>
+ <activity
+ android:name=".bluetooth.BleAdvertisingSetTestActivity"
+ android:configChanges="keyboardHidden|orientation|screenSize"
+ android:exported="true"
+ android:label="@string/ble_advertising_set_test_name" >
+ <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.BleAdvertiserTestActivity" />
+ <meta-data android:name="display_mode"
+ android:value="multi_display_mode" />
+ </activity>
+
<activity android:name=".biometrics.BiometricTestList"
android:label="@string/biometric_test"
android:exported="true"
diff --git a/apps/CtsVerifier/LICENSE_CC_BY b/apps/CtsVerifier/LICENSE_CC_BY
new file mode 100644
index 0000000..e3feb12
--- /dev/null
+++ b/apps/CtsVerifier/LICENSE_CC_BY
@@ -0,0 +1,348 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta name="generator" content="HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
+<title>Creative Commons Legal Code</title>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3.css" media="screen" />
+<link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3-print.css" media="print" />
+<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3-ie.css" media="screen" /><![endif]-->
+<script type="text/javascript" src="https://creativecommons.org/includes/errata.js">
+</script>
+</head>
+<body>
+<p align="center" id="header"><a href="https://creativecommons.org/">Creative Commons</a></p>
+<div id="deed" class="green">
+<div id="deed-head">
+<div id="cc-logo">
+<img src="https://creativecommons.org/images/deed/cc-logo.jpg" alt="" />
+</div>
+<h1><span>Creative Commons Legal Code</span></h1>
+<div id="deed-license">
+<h2>Attribution 3.0 United States</h2>
+</div>
+</div>
+<div id="deed-main">
+<div id="deed-main-content">
+<img src="https://creativecommons.org/images/international/us.png" alt="" />
+<blockquote>
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES
+NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE
+DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE
+COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
+CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE
+INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES
+RESULTING FROM ITS USE.
+</blockquote>
+<h3><em>License</em></h3>
+<p>THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS
+OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR
+"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER
+APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
+PROHIBITED.</p>
+<p>BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU
+ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.
+TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A
+CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE
+IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.</p>
+<p><strong>1. Definitions</strong></p>
+<ol type="a">
+<li><strong>"Collective Work"</strong> means a work, such
+as a periodical issue, anthology or encyclopedia, in
+which the Work in its entirety in unmodified form, along
+with one or more other contributions, constituting
+separate and independent works in themselves, are
+assembled into a collective whole. A work that
+constitutes a Collective Work will not be considered a
+Derivative Work (as defined below) for the purposes of
+this License.</li>
+<li><strong>"Derivative Work"</strong> means a work based
+upon the Work or upon the Work and other pre-existing
+works, such as a translation, musical arrangement,
+dramatization, fictionalization, motion picture version,
+sound recording, art reproduction, abridgment,
+condensation, or any other form in which the Work may be
+recast, transformed, or adapted, except that a work that
+constitutes a Collective Work will not be considered a
+Derivative Work for the purpose of this License. For the
+avoidance of doubt, where the Work is a musical
+composition or sound recording, the synchronization of
+the Work in timed-relation with a moving image
+("synching") will be considered a Derivative Work for the
+purpose of this License.</li>
+<li><strong>"Licensor"</strong> means the individual,
+individuals, entity or entities that offers the Work
+under the terms of this License.</li>
+<li><strong>"Original Author"</strong> means the
+individual, individuals, entity or entities who created
+the Work.</li>
+<li><strong>"Work"</strong> means the copyrightable work
+of authorship offered under the terms of this
+License.</li>
+<li><strong>"You"</strong> means an individual or entity
+exercising rights under this License who has not
+previously violated the terms of this License with
+respect to the Work, or who has received express
+permission from the Licensor to exercise rights under
+this License despite a previous violation.</li>
+</ol>
+<p><strong>2. Fair Use Rights.</strong> Nothing in this
+license is intended to reduce, limit, or restrict any
+rights arising from fair use, first sale or other
+limitations on the exclusive rights of the copyright owner
+under copyright law or other applicable laws.</p>
+<p><strong>3. License Grant.</strong> Subject to the terms
+and conditions of this License, Licensor hereby grants You
+a worldwide, royalty-free, non-exclusive, perpetual (for
+the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:</p>
+<ol type="a">
+<li>to reproduce the Work, to incorporate the Work into
+one or more Collective Works, and to reproduce the Work
+as incorporated in the Collective Works;</li>
+<li>to create and reproduce Derivative Works provided
+that any such Derivative Work, including any translation
+in any medium, takes reasonable steps to clearly label,
+demarcate or otherwise identify that changes were made to
+the original Work. For example, a translation could be
+marked "The original work was translated from English to
+Spanish," or a modification could indicate "The original
+work has been modified.";;</li>
+<li>to distribute copies or phonorecords of, display
+publicly, perform publicly, and perform publicly by means
+of a digital audio transmission the Work including as
+incorporated in Collective Works;</li>
+<li>to distribute copies or phonorecords of, display
+publicly, perform publicly, and perform publicly by means
+of a digital audio transmission Derivative Works.</li>
+<li>
+<p>For the avoidance of doubt, where the Work is a
+musical composition:</p>
+<ol type="i">
+<li><strong>Performance Royalties Under Blanket
+Licenses</strong>. Licensor waives the exclusive
+right to collect, whether individually or, in the
+event that Licensor is a member of a performance
+rights society (e.g. ASCAP, BMI, SESAC), via that
+society, royalties for the public performance or
+public digital performance (e.g. webcast) of the
+Work.</li>
+<li><strong>Mechanical Rights and Statutory
+Royalties</strong>. Licensor waives the exclusive
+right to collect, whether individually or via a music
+rights agency or designated agent (e.g. Harry Fox
+Agency), royalties for any phonorecord You create
+from the Work ("cover version") and distribute,
+subject to the compulsory license created by 17 USC
+Section 115 of the US Copyright Act (or the
+equivalent in other jurisdictions).</li>
+</ol>
+</li>
+<li><strong>Webcasting Rights and Statutory
+Royalties</strong>. For the avoidance of doubt, where the
+Work is a sound recording, Licensor waives the exclusive
+right to collect, whether individually or via a
+performance-rights society (e.g. SoundExchange),
+royalties for the public digital performance (e.g.
+webcast) of the Work, subject to the compulsory license
+created by 17 USC Section 114 of the US Copyright Act (or
+the equivalent in other jurisdictions).</li>
+</ol>
+<p>The above rights may be exercised in all media and
+formats whether now known or hereafter devised. The above
+rights include the right to make such modifications as are
+technically necessary to exercise the rights in other media
+and formats. All rights not expressly granted by Licensor
+are hereby reserved.</p>
+<p><strong>4. Restrictions.</strong> The license granted in
+Section 3 above is expressly made subject to and limited by
+the following restrictions:</p>
+<ol type="a">
+<li>You may distribute, publicly display, publicly
+perform, or publicly digitally perform the Work only
+under the terms of this License, and You must include a
+copy of, or the Uniform Resource Identifier for, this
+License with every copy or phonorecord of the Work You
+distribute, publicly display, publicly perform, or
+publicly digitally perform. You may not offer or impose
+any terms on the Work that restrict the terms of this
+License or the ability of a recipient of the Work to
+exercise the rights granted to that recipient under the
+terms of the License. You may not sublicense the Work.
+You must keep intact all notices that refer to this
+License and to the disclaimer of warranties. When You
+distribute, publicly display, publicly perform, or
+publicly digitally perform the Work, You may not impose
+any technological measures on the Work that restrict the
+ability of a recipient of the Work from You to exercise
+the rights granted to that recipient under the terms of
+the License. This Section 4(a) applies to the Work as
+incorporated in a Collective Work, but this does not
+require the Collective Work apart from the Work itself to
+be made subject to the terms of this License. If You
+create a Collective Work, upon notice from any Licensor
+You must, to the extent practicable, remove from the
+Collective Work any credit as required by Section 4(b),
+as requested. If You create a Derivative Work, upon
+notice from any Licensor You must, to the extent
+practicable, remove from the Derivative Work any credit
+as required by Section 4(b), as requested.</li>
+<li>If You distribute, publicly display, publicly
+perform, or publicly digitally perform the Work (as
+defined in Section 1 above) or any Derivative Works (as
+defined in Section 1 above) or Collective Works (as
+defined in Section 1 above), You must, unless a request
+has been made pursuant to Section 4(a), keep intact all
+copyright notices for the Work and provide, reasonable to
+the medium or means You are utilizing: (i) the name of
+the Original Author (or pseudonym, if applicable) if
+supplied, and/or (ii) if the Original Author and/or
+Licensor designate another party or parties (e.g. a
+sponsor institute, publishing entity, journal) for
+attribution ("Attribution Parties") in Licensor's
+copyright notice, terms of service or by other reasonable
+means, the name of such party or parties; the title of
+the Work if supplied; to the extent reasonably
+practicable, the Uniform Resource Identifier, if any,
+that Licensor specifies to be associated with the Work,
+unless such URI does not refer to the copyright notice or
+licensing information for the Work; and, consistent with
+Section 3(b) in the case of a Derivative Work, a credit
+identifying the use of the Work in the Derivative Work
+(e.g., "French translation of the Work by Original
+Author," or "Screenplay based on original Work by
+Original Author"). The credit required by this Section
+4(b) may be implemented in any reasonable manner;
+provided, however, that in the case of a Derivative Work
+or Collective Work, at a minimum such credit will appear,
+if a credit for all contributing authors of the
+Derivative Work or Collective Work appears, then as part
+of these credits and in a manner at least as prominent as
+the credits for the other contributing authors. For the
+avoidance of doubt, You may only use the credit required
+by this Section for the purpose of attribution in the
+manner set out above and, by exercising Your rights under
+this License, You may not implicitly or explicitly assert
+or imply any connection with, sponsorship or endorsement
+by the Original Author, Licensor and/or Attribution
+Parties, as appropriate, of You or Your use of the Work,
+without the separate, express prior written permission of
+the Original Author, Licensor and/or Attribution
+Parties.</li>
+</ol>
+<p><strong>5. Representations, Warranties and
+Disclaimer</strong></p>
+<p>UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN
+WRITING, LICENSOR OFFERS THE WORK AS-IS AND ONLY TO THE
+EXTENT OF ANY RIGHTS HELD IN THE LICENSED WORK BY THE
+LICENSOR. THE LICENSOR MAKES NO REPRESENTATIONS OR
+WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS,
+IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
+LIMITATION, WARRANTIES OF TITLE, MARKETABILITY,
+MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
+NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS,
+ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT
+APPLY TO YOU.</p>
+<p><strong>6. Limitation on Liability.</strong> EXCEPT TO
+THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
+LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY
+SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY
+DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
+EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.</p>
+<p><strong>7. Termination</strong></p>
+<ol type="a">
+<li>This License and the rights granted hereunder will
+terminate automatically upon any breach by You of the
+terms of this License. Individuals or entities who have
+received Derivative Works (as defined in Section 1 above)
+or Collective Works (as defined in Section 1 above) from
+You under this License, however, will not have their
+licenses terminated provided such individuals or entities
+remain in full compliance with those licenses. Sections
+1, 2, 5, 6, 7, and 8 will survive any termination of this
+License.</li>
+<li>Subject to the above terms and conditions, the
+license granted here is perpetual (for the duration of
+the applicable copyright in the Work). Notwithstanding
+the above, Licensor reserves the right to release the
+Work under different license terms or to stop
+distributing the Work at any time; provided, however that
+any such election will not serve to withdraw this License
+(or any other license that has been, or is required to
+be, granted under the terms of this License), and this
+License will continue in full force and effect unless
+terminated as stated above.</li>
+</ol>
+ <p><strong>8. Miscellaneous</strong></p>
+<ol type="a">
+<li>Each time You distribute or publicly digitally
+perform the Work (as defined in Section 1 above) or a
+Collective Work (as defined in Section 1 above), the
+Licensor offers to the recipient a license to the Work on
+the same terms and conditions as the license granted to
+You under this License.</li>
+<li>Each time You distribute or publicly digitally
+perform a Derivative Work, Licensor offers to the
+recipient a license to the original Work on the same
+terms and conditions as the license granted to You under
+this License.</li>
+<li>If any provision of this License is invalid or
+unenforceable under applicable law, it shall not affect
+the validity or enforceability of the remainder of the
+terms of this License, and without further action by the
+parties to this agreement, such provision shall be
+reformed to the minimum extent necessary to make such
+provision valid and enforceable.</li>
+<li>No term or provision of this License shall be deemed
+waived and no breach consented to unless such waiver or
+consent shall be in writing and signed by the party to be
+charged with such waiver or consent.</li>
+<li>This License constitutes the entire agreement between
+the parties with respect to the Work licensed here. There
+are no understandings, agreements or representations with
+respect to the Work not specified here. Licensor shall
+not be bound by any additional provisions that may appear
+in any communication from You. This License may not be
+modified without the mutual written agreement of the
+Licensor and You.</li>
+</ol>
+
+<blockquote>
+<h3>Creative Commons Notice</h3>
+<p>Creative Commons is not a party to this License, and
+makes no warranty whatsoever in connection with the Work.
+Creative Commons will not be liable to You or any party
+on any legal theory for any damages whatsoever, including
+without limitation any general, special, incidental or
+consequential damages arising in connection to this
+license. Notwithstanding the foregoing two (2) sentences,
+if Creative Commons has expressly identified itself as
+the Licensor hereunder, it shall have all rights and
+obligations of Licensor.</p>
+<p>Except for the limited purpose of indicating to the
+public that the Work is licensed under the CCPL, Creative
+Commons does not authorize the use by either party of the
+trademark "Creative Commons" or any related trademark or
+logo of Creative Commons without the prior written
+consent of Creative Commons. Any permitted use will be in
+compliance with Creative Commons' then-current trademark
+usage guidelines, as may be published on its website or
+otherwise made available upon request from time to time.
+For the avoidance of doubt, this trademark restriction
+does not form part of the License.</p>
+<p>Creative Commons may be contacted at <a href="https://creativecommons.org/">https://creativecommons.org/</a>.</p>
+</blockquote>
+</div>
+</div>
+<div id="deed-foot">
+<p id="footer"><a href="./">« Back to Commons Deed</a></p>
+</div>
+</div>
+</body>
+</html>
diff --git a/apps/CtsVerifier/res/layout/ble_advertising_set.xml b/apps/CtsVerifier/res/layout/ble_advertising_set.xml
new file mode 100644
index 0000000..06225d9
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/ble_advertising_set.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2022 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content">
+ <TextView android:text="@string/ble_advertising_set_test_instruction"
+ android:id="@+id/ble_advertising_set_test_instruction"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:scrollbars="vertical"/>
+ <Button android:id="@+id/ble_advertising_set_start_test"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/ble_advertising_set_start_test"/>
+ <ListView android:id="@+id/ble_advertising_set_tests"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:padding="10dip"/>
+ <include android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ layout="@layout/pass_fail_buttons"/>
+</LinearLayout>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index fe56af1..2566646 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -703,6 +703,23 @@
<string name="ble_scan_start">Start scan</string>
<string name="ble_scan_stop">Stop scan</string>
+ <!-- BLE Advertising Set test strings -->
+ <string name="ble_advertising_set_test_name">Bluetooth LE Advertising Set Test</string>
+ <string name="ble_advertising_set_test_info">Bluetooth LE Advertising Set tests AdvertisingSet and AdvertisingSetCallback APIs.</string>
+ <string name="ble_advertising_set_test_instruction">Press the \"Set Up\" button first, then start the test by pressing the \"Start Test\" button. UI thread may freeze for a few seconds while enabling/disabling bluetooth adapter.</string>
+ <string name="ble_advertising_set_start_test">Start Test</string>
+ <string name="ble_advertising_set_running_test">Running Test...</string>
+ <string name="ble_advertising_set_finished_test">Finished Test</string>
+ <string name="ble_advertising_set_start">Starting advertising set.</string>
+ <string name="ble_advertising_set_enable_disable">Enabling/Disabling advertising set.</string>
+ <string name="ble_advertising_set_advertising_data">Setting advertising data.</string>
+ <string name="ble_advertising_set_advertising_params">Setting advertising parameters.</string>
+ <string name="ble_advertising_set_periodic_advertising_data">Setting periodic advertising data.</string>
+ <string name="ble_advertising_set_periodic_advertising_enabled_disabled">Enabling/Disabling periodic advertising.</string>
+ <string name="ble_advertising_set_periodic_advertising_params">Setting periodic advertising parameters.</string>
+ <string name="ble_advertising_set_scan_response_data">Setting scan response data.</string>
+ <string name="ble_advertising_set_stop">Stopping advertising set.</string>
+
<!-- BLE connection priority test strings -->
<string name="ble_client_connection_priority">Testing connection priority switching </string>
<string name="ble_server_connection_priority_result_passed">All test passed</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
new file mode 100644
index 0000000..e02b122
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleAdvertisingSetTestActivity.java
@@ -0,0 +1,438 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 static android.bluetooth.le.AdvertisingSetCallback.ADVERTISE_SUCCESS;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertisingSet;
+import android.bluetooth.le.AdvertisingSetCallback;
+import android.bluetooth.le.AdvertisingSetParameters;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.bluetooth.le.PeriodicAdvertisingParameters;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.util.Log;
+import android.view.View;
+import android.widget.Button;
+import android.widget.ListView;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * Tests {@link AdvertisingSet} and {@link AdvertisingSetCallback}.
+ */
+public class BleAdvertisingSetTestActivity extends PassFailButtons.Activity {
+
+ private static final String TAG = "BleAdvertisingSetTestActivity";
+ private static final int TIMEOUT_MS = 5000;
+
+ private static final int PASS_FLAG_START = 0x1;
+ private static final int PASS_FLAG_ENABLE_DISABLE = 0x2;
+ private static final int PASS_FLAG_SET_ADVERTISING_DATA = 0x4;
+ private static final int PASS_FLAG_SET_ADVERTISING_PARAMS = 0x8;
+ private static final int PASS_FLAG_SET_PERIODIC_ADVERTISING_DATA = 0x10;
+ private static final int PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED = 0x20;
+ private static final int PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS = 0x40;
+ private static final int PASS_FLAG_SET_SCAN_RESPONSE_DATA = 0x80;
+ private static final int PASS_FLAG_STOP = 0x100;
+ private static final int PASS_FLAG_ALL = 0x1FF;
+
+ private static final int TEST_ADAPTER_INDEX_START = 0;
+ private static final int TEST_ADAPTER_INDEX_ENABLE_DISABLE = 1;
+ private static final int TEST_ADAPTER_INDEX_SET_ADVERTISING_DATA = 2;
+ private static final int TEST_ADAPTER_INDEX_SET_ADVERTISING_PARAMS = 3;
+ private static final int TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA = 4;
+ private static final int TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED = 5;
+ private static final int TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS = 6;
+ private static final int TEST_ADAPTER_INDEX_SET_SCAN_RESPONSE_DATA = 7;
+ private static final int TEST_ADAPTER_INDEX_STOP = 8;
+
+ private static final AdvertisingSetParameters ADVERTISING_SET_PARAMETERS =
+ new AdvertisingSetParameters.Builder().setLegacyMode(true).build();
+
+ private BluetoothManager mBluetoothManager;
+ private BluetoothAdapter mBluetoothAdapter;
+ private BluetoothLeAdvertiser mAdvertiser;
+ private TestAdvertisingSetCallback mCallback;
+
+ private TestAdapter mTestAdapter;
+ private Button mStartTestButton;
+
+ private long mAllTestsPassed;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.ble_advertising_set);
+ setPassFailButtonClickListeners();
+ setInfoResources(R.string.ble_advertising_set_test_name,
+ R.string.ble_advertising_set_test_info, -1);
+ getPassButton().setEnabled(false);
+
+ mTestAdapter = new TestAdapter(this, setupTestList());
+ ListView listView = findViewById(R.id.ble_advertising_set_tests);
+ listView.setAdapter(mTestAdapter);
+
+ mStartTestButton = findViewById(R.id.ble_advertising_set_start_test);
+ mStartTestButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mStartTestButton.setEnabled(false);
+ mStartTestButton.setText(R.string.ble_advertising_set_running_test);
+
+ HandlerThread testHandlerThread = new HandlerThread("TestHandlerThread");
+ testHandlerThread.start();
+ Handler handler = new Handler(testHandlerThread.getLooper());
+ handler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (!mBluetoothAdapter.isEnabled()) {
+ assertTrue(BtAdapterUtils.enableAdapter(mBluetoothAdapter,
+ BleAdvertisingSetTestActivity.this));
+ // If BluetoothAdapter was previously not enabled, we need to get the
+ // BluetoothLeAdvertiser instance again.
+ mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+ }
+
+ try {
+ startAdvertisingSet();
+ testEnableAndDisableAdvertising();
+ testSetAdvertisingData();
+ testSetAdvertisingParameters();
+ testPeriodicAdvertising();
+ testSetScanResponseData();
+ stopAdvertisingSet();
+ } catch (InterruptedException e) {
+ Log.e(TAG, "Interrupted while running tests", e);
+ } catch (AssertionError e) {
+ Log.e(TAG, "Test failed", e);
+ }
+
+ // Disable bluetooth adapter
+ assertTrue(BtAdapterUtils.disableAdapter(mBluetoothAdapter,
+ BleAdvertisingSetTestActivity.this));
+
+ BleAdvertisingSetTestActivity.this.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ mStartTestButton.setText(
+ R.string.ble_advertising_set_finished_test);
+
+ // Update test list to reflect whether the tests passed or not.
+ mTestAdapter.notifyDataSetChanged();
+
+ if (mAllTestsPassed == PASS_FLAG_ALL) {
+ getPassButton().setEnabled(true);
+ }
+ }
+ });
+ }
+ });
+ }
+ });
+
+ mAllTestsPassed = 0;
+
+ mBluetoothManager = getSystemService(BluetoothManager.class);
+ mBluetoothAdapter = mBluetoothManager.getAdapter();
+ mAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+ mCallback = new TestAdvertisingSetCallback();
+ }
+
+ private void startAdvertisingSet() throws InterruptedException {
+ mAdvertiser.startAdvertisingSet(ADVERTISING_SET_PARAMETERS,
+ /* advertiseData= */ null, /* scanResponse= */ null,
+ /* periodicParameters= */ null, /* periodicData= */ null,
+ mCallback);
+ assertTrue(mCallback.mAdvertisingSetStartedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingSetStartedStatus.get());
+ assertNotNull(mCallback.mAdvertisingSet);
+
+ mAllTestsPassed |= PASS_FLAG_START;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_START);
+ }
+
+ private void testEnableAndDisableAdvertising() throws InterruptedException {
+ mCallback.reset();
+
+ mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ true, /* duration= */ 1,
+ /* maxExtendedAdvertisingEvents= */ 1);
+ assertTrue(mCallback.mAdvertisingEnabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingEnabledStatus.get());
+
+ mCallback.mAdvertisingSet.get().enableAdvertising(/* enable= */ false, /* duration= */ 1,
+ /* maxExtendedAdvertisingEvents= */ 1);
+ assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_ENABLE_DISABLE;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_ENABLE_DISABLE);
+ }
+
+ private void testSetAdvertisingData() throws InterruptedException {
+ mCallback.reset();
+
+ mCallback.mAdvertisingSet.get().setAdvertisingData(new AdvertiseData.Builder().build());
+ assertTrue(mCallback.mAdvertisingDataSetLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDataSetStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_ADVERTISING_DATA;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_ADVERTISING_DATA);
+ }
+
+ private void testSetScanResponseData() throws InterruptedException {
+ mCallback.reset();
+
+ mCallback.mAdvertisingSet.get().setScanResponseData(new AdvertiseData.Builder().build());
+ assertTrue(mCallback.mScanResponseDataSetLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mScanResponseDataSetStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_SCAN_RESPONSE_DATA;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_SCAN_RESPONSE_DATA);
+ }
+
+ private void testSetAdvertisingParameters() throws InterruptedException {
+ mCallback.reset();
+
+ mCallback.mAdvertisingSet.get().enableAdvertising(false, /* duration= */ 1,
+ /* maxExtendedAdvertisingEvents= */1);
+ assertTrue(mCallback.mAdvertisingDisabledLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingDisabledStatus.get());
+
+ mCallback.mAdvertisingSet.get().setAdvertisingParameters(
+ new AdvertisingSetParameters.Builder()
+ .setLegacyMode(true)
+ .setScannable(false)
+ .build());
+ assertTrue(mCallback.mAdvertisingParametersUpdatedLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingParametersUpdatedStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_ADVERTISING_PARAMS;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_ADVERTISING_PARAMS);
+ }
+
+ // The following order of commands follows the diagram of Bluetooth Core Specification,
+ // Version 5.3, Vol 6, Part D, Figure 3.7: Periodic advertising.
+ private void testPeriodicAdvertising() throws InterruptedException {
+ mCallback.reset();
+
+ mCallback.mAdvertisingSet.get().setAdvertisingParameters(
+ new AdvertisingSetParameters.Builder().build());
+ assertTrue(mCallback.mAdvertisingParametersUpdatedLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mAdvertisingParametersUpdatedStatus.get());
+
+ mCallback.mAdvertisingSet.get().setPeriodicAdvertisingParameters(
+ new PeriodicAdvertisingParameters.Builder().build());
+ assertTrue(mCallback.mPeriodicAdvertisingParamsUpdatedLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingParamsUpdatedStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_PARAMS;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_PARAMS);
+
+ mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(true);
+ assertTrue(mCallback.mPeriodicAdvertisingEnabledLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingEnabledStatus.get());
+
+ mCallback.mAdvertisingSet.get().setPeriodicAdvertisingData(new AdvertiseData.Builder()
+ .build());
+ assertTrue(mCallback.mPeriodicAdvertisingDataSetLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDataSetStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_DATA;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_DATA);
+
+ mCallback.mAdvertisingSet.get().setPeriodicAdvertisingEnabled(false);
+ assertTrue(mCallback.mPeriodicAdvertisingDisabledLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+ assertEquals(ADVERTISE_SUCCESS, mCallback.mPeriodicAdvertisingDisabledStatus.get());
+
+ mAllTestsPassed |= PASS_FLAG_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_SET_PERIODIC_ADVERTISING_ENABLED_DISABLED);
+ }
+
+ private void stopAdvertisingSet() throws InterruptedException {
+ mAdvertiser.stopAdvertisingSet(mCallback);
+ assertTrue(mCallback.mAdvertisingSetStoppedLatch.await(TIMEOUT_MS,
+ TimeUnit.MILLISECONDS));
+
+ mAllTestsPassed |= PASS_FLAG_STOP;
+ mTestAdapter.setTestPass(TEST_ADAPTER_INDEX_STOP);
+ }
+
+ private List<Integer> setupTestList() {
+ List<Integer> testList = new ArrayList<>();
+ testList.add(R.string.ble_advertising_set_start);
+ testList.add(R.string.ble_advertising_set_enable_disable);
+ testList.add(R.string.ble_advertising_set_advertising_data);
+ testList.add(R.string.ble_advertising_set_advertising_params);
+ testList.add(R.string.ble_advertising_set_periodic_advertising_data);
+ testList.add(R.string.ble_advertising_set_periodic_advertising_enabled_disabled);
+ testList.add(R.string.ble_advertising_set_periodic_advertising_params);
+ testList.add(R.string.ble_advertising_set_scan_response_data);
+ testList.add(R.string.ble_advertising_set_stop);
+ return testList;
+ }
+
+ private static class TestAdvertisingSetCallback extends AdvertisingSetCallback {
+ public CountDownLatch mAdvertisingSetStartedLatch = new CountDownLatch(1);
+ public CountDownLatch mAdvertisingEnabledLatch = new CountDownLatch(1);
+ public CountDownLatch mAdvertisingDisabledLatch = new CountDownLatch(1);
+ public CountDownLatch mAdvertisingParametersUpdatedLatch = new CountDownLatch(1);
+ public CountDownLatch mAdvertisingDataSetLatch = new CountDownLatch(1);
+ public CountDownLatch mScanResponseDataSetLatch = new CountDownLatch(1);
+ public CountDownLatch mAdvertisingSetStoppedLatch = new CountDownLatch(1);
+ public CountDownLatch mPeriodicAdvertisingEnabledLatch = new CountDownLatch(1);
+ public CountDownLatch mPeriodicAdvertisingDisabledLatch = new CountDownLatch(1);
+ public CountDownLatch mPeriodicAdvertisingParamsUpdatedLatch = new CountDownLatch(1);
+ public CountDownLatch mPeriodicAdvertisingDataSetLatch = new CountDownLatch(1);
+
+ public AtomicInteger mAdvertisingSetStartedStatus = new AtomicInteger();
+ public AtomicInteger mAdvertisingEnabledStatus = new AtomicInteger();
+ public AtomicInteger mAdvertisingDisabledStatus = new AtomicInteger();
+ public AtomicInteger mAdvertisingParametersUpdatedStatus = new AtomicInteger();
+ public AtomicInteger mAdvertisingDataSetStatus = new AtomicInteger();
+ public AtomicInteger mScanResponseDataSetStatus = new AtomicInteger();
+ public AtomicInteger mPeriodicAdvertisingEnabledStatus = new AtomicInteger();
+ public AtomicInteger mPeriodicAdvertisingDisabledStatus = new AtomicInteger();
+ public AtomicInteger mPeriodicAdvertisingParamsUpdatedStatus = new AtomicInteger();
+ public AtomicInteger mPeriodicAdvertisingDataSetStatus = new AtomicInteger();
+
+ public AtomicReference<AdvertisingSet> mAdvertisingSet = new AtomicReference();
+
+ @Override
+ public void onAdvertisingSetStarted(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ super.onAdvertisingSetStarted(advertisingSet, txPower, status);
+ mAdvertisingSetStartedStatus.set(status);
+ mAdvertisingSet.set(advertisingSet);
+ mAdvertisingSetStartedLatch.countDown();
+ }
+
+ @Override
+ public void onAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ super.onAdvertisingEnabled(advertisingSet, enable, status);
+ if (enable) {
+ mAdvertisingEnabledStatus.set(status);
+ mAdvertisingEnabledLatch.countDown();
+ } else {
+ mAdvertisingDisabledStatus.set(status);
+ mAdvertisingDisabledLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onAdvertisingParametersUpdated(AdvertisingSet advertisingSet, int txPower,
+ int status) {
+ super.onAdvertisingParametersUpdated(advertisingSet, txPower, status);
+ mAdvertisingParametersUpdatedStatus.set(status);
+ mAdvertisingParametersUpdatedLatch.countDown();
+ }
+
+ @Override
+ public void onAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ super.onAdvertisingDataSet(advertisingSet, status);
+ mAdvertisingDataSetStatus.set(status);
+ mAdvertisingDataSetLatch.countDown();
+ }
+
+ @Override
+ public void onPeriodicAdvertisingParametersUpdated(AdvertisingSet advertisingSet,
+ int status) {
+ super.onPeriodicAdvertisingParametersUpdated(advertisingSet, status);
+ mPeriodicAdvertisingParamsUpdatedStatus.set(status);
+ mPeriodicAdvertisingParamsUpdatedLatch.countDown();
+ }
+
+ @Override
+ public void onPeriodicAdvertisingDataSet(AdvertisingSet advertisingSet, int status) {
+ super.onPeriodicAdvertisingDataSet(advertisingSet, status);
+ mPeriodicAdvertisingDataSetStatus.set(status);
+ mPeriodicAdvertisingDataSetLatch.countDown();
+ }
+
+ @Override
+ public void onPeriodicAdvertisingEnabled(AdvertisingSet advertisingSet, boolean enable,
+ int status) {
+ super.onPeriodicAdvertisingEnabled(advertisingSet, enable, status);
+ if (enable) {
+ mPeriodicAdvertisingEnabledStatus.set(status);
+ mPeriodicAdvertisingEnabledLatch.countDown();
+ } else {
+ mPeriodicAdvertisingDisabledStatus.set(status);
+ mPeriodicAdvertisingDisabledLatch.countDown();
+ }
+ }
+
+ @Override
+ public void onScanResponseDataSet(AdvertisingSet advertisingSet, int status) {
+ super.onScanResponseDataSet(advertisingSet, status);
+ mScanResponseDataSetStatus.set(status);
+ mScanResponseDataSetLatch.countDown();
+ }
+
+ @Override
+ public void onAdvertisingSetStopped(AdvertisingSet advertisingSet) {
+ super.onAdvertisingSetStopped(advertisingSet);
+ mAdvertisingSetStoppedLatch.countDown();
+ }
+
+ public void reset() {
+ mAdvertisingSetStartedLatch = new CountDownLatch(1);
+ mAdvertisingEnabledLatch = new CountDownLatch(1);
+ mAdvertisingParametersUpdatedLatch = new CountDownLatch(1);
+ mAdvertisingDataSetLatch = new CountDownLatch(1);
+ mPeriodicAdvertisingParamsUpdatedLatch = new CountDownLatch(1);
+ mPeriodicAdvertisingDataSetLatch = new CountDownLatch(1);
+ mPeriodicAdvertisingEnabledLatch = new CountDownLatch(1);
+ mPeriodicAdvertisingDisabledLatch = new CountDownLatch(1);
+ mScanResponseDataSetLatch = new CountDownLatch(1);
+
+ mAdvertisingSetStartedStatus = new AtomicInteger();
+ mAdvertisingEnabledStatus = new AtomicInteger();
+ mAdvertisingDisabledStatus = new AtomicInteger();
+ mAdvertisingParametersUpdatedStatus = new AtomicInteger();
+ mAdvertisingDataSetStatus = new AtomicInteger();
+ mPeriodicAdvertisingParamsUpdatedStatus = new AtomicInteger();
+ mPeriodicAdvertisingDataSetStatus = new AtomicInteger();
+ mPeriodicAdvertisingEnabledStatus = new AtomicInteger();
+ mPeriodicAdvertisingDisabledStatus = new AtomicInteger();
+ mScanResponseDataSetStatus = new AtomicInteger();
+ }
+ }
+}
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 20d0f12..746c894 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleClientService.java
@@ -323,7 +323,7 @@
private static final int SERVICE_CHANGED_FLAG_TRIGGER_ACTION = 0x01;
private static final int SERVICE_CHANGED_FLAG_ON_SERVICE_CHANGED = 0x02;
private static final int SERVICE_CHANGED_FLAG_ALL = 0x03;
- private static final int SERVOCE_CHANGED_FLAG_IGNORE = 0xFF;
+ private static final int SERVICE_CHANGED_FLAG_IGNORE = 0xFF;
private int mServiceChangedFlag;
private enum ReliableWriteState {
@@ -568,8 +568,13 @@
private void writeCharacteristic(BluetoothGattCharacteristic characteristic, String writeValue) {
if (characteristic != null) {
+ // Note: setValue() should not be necessary when using writeCharacteristic(byte[]) which
+ // is added on Android T, but here we call the method in order to make the test
+ // easier to read. Otherwise, we should verify the written value by calling
+ // readCharacteristic() but that makes the whole test hard to read.
characteristic.setValue(writeValue);
- mBluetoothGatt.writeCharacteristic(characteristic);
+ mBluetoothGatt.writeCharacteristic(characteristic, writeValue.getBytes(),
+ characteristic.getWriteType());
}
}
@@ -590,8 +595,12 @@
private void writeDescriptor(UUID uid, String writeValue) {
BluetoothGattDescriptor descriptor = getDescriptor(uid);
if (descriptor != null) {
+ // Note: setValue() should not be necessary when using writeDescriptor(byte[]) which
+ // is added on Android T, but here we call the method in order to make the test
+ // easier to read. Otherwise, we should verify the written value by calling
+ // readDescriptor() but that makes the whole test hard to read.
descriptor.setValue(writeValue.getBytes());
- mBluetoothGatt.writeDescriptor(descriptor);
+ mBluetoothGatt.writeDescriptor(descriptor, writeValue.getBytes());
}
}
@@ -605,8 +614,12 @@
private void writeDescriptor(UUID cuid, UUID duid, String writeValue) {
BluetoothGattDescriptor descriptor = getDescriptor(cuid, duid);
if (descriptor != null) {
+ // Note: setValue() should not be necessary when using writeDescriptor(byte[]) which
+ // is added on Android T, but here we call the method in order to make the test
+ // easier to read. Otherwise, we should verify the written value by calling
+ // readDescriptor() but that makes the whole test hard to read.
descriptor.setValue(writeValue.getBytes());
- mBluetoothGatt.writeDescriptor(descriptor);
+ mBluetoothGatt.writeDescriptor(descriptor, writeValue.getBytes());
}
}
@@ -644,15 +657,15 @@
synchronized (mServiceChangedLock) {
mServiceChangedFlag |= flag;
if (mServiceChangedFlag == SERVICE_CHANGED_FLAG_ALL) {
- mServiceChangedFlag |= SERVOCE_CHANGED_FLAG_IGNORE;
+ mServiceChangedFlag |= SERVICE_CHANGED_FLAG_IGNORE;
shouldSend = true;
}
}
if (shouldSend) {
+ // This is to send result to the connected GATT server.
writeCharacteristic(getCharacteristic(CHARACTERISTIC_RESULT_UUID),
SERVICE_CHANGED_VALUE);
- notifyServiceChanged();
}
}
@@ -1068,7 +1081,20 @@
}
if (BLE_CLIENT_ACTION_TRIGGER_SERVICE_CHANGED.equals(mCurrentAction)) {
- sendServiceChangedEventIfReady(SERVICE_CHANGED_FLAG_TRIGGER_ACTION);
+ if (SERVICE_CHANGED_VALUE.equals(value)) {
+ if (status == BluetoothGatt.GATT_SUCCESS) {
+ // Waits until the GATT server sends the response, we can then do notify.
+ notifyServiceChanged();
+ } else {
+ notifyError("Failed to send result for service changed event");
+ }
+ } else {
+ // The reason not to check the status code is that we know there is a service
+ // changed event coming later, sometimes the status code will be modified by
+ // bt stack (133), but it's ok, as long as onServiceChanged is called, we then
+ // know the request is successfully sent during this test session.
+ sendServiceChangedEventIfReady(SERVICE_CHANGED_FLAG_TRIGGER_ACTION);
+ }
} else if (BLE_CLIENT_ACTION_REQUEST_MTU_512.equals(mCurrentAction) ||
BLE_CLIENT_ACTION_REQUEST_MTU_23.equals(mCurrentAction)) {
if (status == BluetoothGatt.GATT_SUCCESS) {
@@ -1355,6 +1381,17 @@
}
@Override
+ public void onPhyUpdate(BluetoothGatt gatt, int txPhy, int rxPhy, int status) {
+ // TODO: Currently this is not called when BluetoothGatt.setPreferredPhy() is called.
+ // It is because the path is not wired in native code. (acl_legacy_interface.cc)
+ // Add a proper implementation and related test.
+ super.onPhyUpdate(gatt, txPhy, rxPhy, status);
+ if (DEBUG) {
+ Log.d(TAG, "onPhyUpdate");
+ }
+ }
+
+ @Override
public void onServiceChanged(BluetoothGatt gatt) {
super.onServiceChanged(gatt);
if (DEBUG) {
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
index bace574..1cd3093 100755
--- a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BleServerService.java
@@ -1156,27 +1156,28 @@
Log.d(TAG, " characteristic uuid = " + uid);
}
- descriptor.setValue(value);
UUID duid = descriptor.getUuid();
// If there is a written request to the CCCD for Notify.
if (duid.equals(UPDATE_DESCRIPTOR_UUID)) {
if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE)) {
- mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), false);
+ mGattServer.notifyCharacteristicChanged(
+ mDevice, descriptor.getCharacteristic(), false, value);
mIndicated = false;
} else if (Arrays.equals(value, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE)) {
- mGattServer.notifyCharacteristicChanged(mDevice, descriptor.getCharacteristic(), true);
+ mGattServer.notifyCharacteristicChanged(
+ mDevice, descriptor.getCharacteristic(), true, value);
mIndicated = true;
}
} else if (duid.equals(DESCRIPTOR_NEED_ENCRYPTED_WRITE_UUID)) {
// verify
- if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+ if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), value)) {
notifyDescriptorWriteRequestNeedEncrypted();
} else {
showMessage("Written data is not correct");
}
} else {
// verify
- if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), descriptor.getValue())) {
+ if (Arrays.equals(BleClientService.WRITE_VALUE.getBytes(), value)) {
notifyDescriptorWriteRequest();
} else {
showMessage("Written data is not correct");
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BtAdapterUtils.java b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BtAdapterUtils.java
new file mode 100644
index 0000000..1576d34
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/bluetooth/BtAdapterUtils.java
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS 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 android.bluetooth.BluetoothAdapter;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Looper;
+import android.util.Log;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.Condition;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Utility for controlling the Bluetooth adapter from CTS test.
+ *
+ * Code mostly copied from android.bluetooth.cts.BTAdapterUtils class.
+ */
+public class BtAdapterUtils {
+ private static final String TAG = "BtAdapterUtils";
+
+ // ADAPTER_ENABLE_TIMEOUT_MS = AdapterState.BLE_START_TIMEOUT_DELAY +
+ // AdapterState.BREDR_START_TIMEOUT_DELAY
+ private static final int ADAPTER_ENABLE_TIMEOUT_MS = 8000;
+ // ADAPTER_DISABLE_TIMEOUT_MS = AdapterState.BLE_STOP_TIMEOUT_DELAY +
+ // AdapterState.BREDR_STOP_TIMEOUT_DELAY
+ private static final int ADAPTER_DISABLE_TIMEOUT_MS = 5000;
+
+ private static BroadcastReceiver sAdapterIntentReceiver;
+
+ private static Condition sConditionAdapterIsEnabled;
+ private static ReentrantLock sAdapterStateEnablingLock;
+
+ private static Condition sConditionAdapterIsDisabled;
+ private static ReentrantLock sAdapterStateDisablingLock;
+ private static boolean sAdapterVarsInitialized;
+
+ private static HandlerThread sHandlerThread;
+ private static Looper sLooper;
+ private static Handler sHandler;
+
+ private static class AdapterIntentReceiver extends BroadcastReceiver {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(intent.getAction())) {
+ int previousState = intent.getIntExtra(BluetoothAdapter.EXTRA_PREVIOUS_STATE, -1);
+ int newState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, -1);
+ Log.d(TAG, "Previous state: " + previousState + " New state: " + newState);
+
+ if (newState == BluetoothAdapter.STATE_ON) {
+ sAdapterStateEnablingLock.lock();
+ try {
+ Log.d(TAG, "Signaling to mConditionAdapterIsEnabled");
+ sConditionAdapterIsEnabled.signal();
+ } finally {
+ sAdapterStateEnablingLock.unlock();
+ }
+ } else if (newState == BluetoothAdapter.STATE_OFF) {
+ sAdapterStateDisablingLock.lock();
+ try {
+ Log.d(TAG, "Signaling to mConditionAdapterIsDisabled");
+ sConditionAdapterIsDisabled.signal();
+ } finally {
+ sAdapterStateDisablingLock.unlock();
+ }
+ }
+ }
+ }
+ }
+
+ /** Enables the Bluetooth Adapter. Return true if it is already enabled or is enabled. */
+ public static boolean enableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+ if (!sAdapterVarsInitialized) {
+ initAdapterStateVariables(context);
+ }
+ registerIntentReceiver(context);
+
+ if (bluetoothAdapter.isEnabled()) return true;
+
+ bluetoothAdapter.enable();
+ sAdapterStateEnablingLock.lock();
+ try {
+ // Wait for the Adapter to be enabled
+ while (!bluetoothAdapter.isEnabled()) {
+ if (!sConditionAdapterIsEnabled.await(
+ ADAPTER_ENABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ // Timeout
+ Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter enable");
+ break;
+ } // else spurious wakeups
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "enableAdapter: interrupted");
+ } finally {
+ sAdapterStateEnablingLock.unlock();
+ }
+ return bluetoothAdapter.isEnabled();
+ }
+
+ /** Disable the Bluetooth Adapter. Return true if it is already disabled or is disabled. */
+ public static boolean disableAdapter(BluetoothAdapter bluetoothAdapter, Context context) {
+ if (!sAdapterVarsInitialized) {
+ initAdapterStateVariables(context);
+ }
+ registerIntentReceiver(context);
+
+ if (bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF) return true;
+
+ bluetoothAdapter.disable();
+ sAdapterStateDisablingLock.lock();
+ try {
+ // Wait for the Adapter to be disabled
+ while (bluetoothAdapter.getState() != BluetoothAdapter.STATE_OFF) {
+ if (!sConditionAdapterIsDisabled.await(
+ ADAPTER_DISABLE_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
+ // Timeout
+ Log.e(TAG, "Timeout while waiting for the Bluetooth Adapter disable");
+ break;
+ } // else spurious wakeups
+ }
+ } catch (InterruptedException e) {
+ Log.e(TAG, "disableAdapter: interrupted");
+ } finally {
+ sAdapterStateDisablingLock.unlock();
+ }
+ return bluetoothAdapter.getState() == BluetoothAdapter.STATE_OFF;
+ }
+
+ private static void registerIntentReceiver(Context context) {
+ sAdapterIntentReceiver = new AdapterIntentReceiver();
+ IntentFilter filter = new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED);
+ context.registerReceiver(sAdapterIntentReceiver, filter);
+ }
+
+ // Initialize variables required for TestUtils#enableAdapter and TestUtils#disableAdapter
+ private static void initAdapterStateVariables(Context context) {
+ sAdapterStateEnablingLock = new ReentrantLock();
+ sConditionAdapterIsEnabled = sAdapterStateEnablingLock.newCondition();
+ sAdapterStateDisablingLock = new ReentrantLock();
+ sConditionAdapterIsDisabled = sAdapterStateDisablingLock.newCondition();
+
+ sAdapterVarsInitialized = true;
+ }
+}
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
index faee07a..e68983b 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/usb/device/UsbDeviceTestActivity.java
@@ -84,6 +84,7 @@
private Thread mTestThread;
private TextView mStatus;
private ProgressBar mProgress;
+ private UsbDevice mDevice;
/**
* Some N and older accessories do not send a zero sized package after a request that is a
@@ -156,7 +157,6 @@
case ACTION_USB_PERMISSION:
boolean granted = intent.getBooleanExtra(
UsbManager.EXTRA_PERMISSION_GRANTED, false);
-
if (granted) {
if (!AoapInterface.isDeviceInAoapMode(device)) {
mStatus.setText(R.string.usb_device_test_step3);
@@ -194,7 +194,6 @@
}
}
};
-
registerReceiver(mUsbDeviceConnectionReceiver, filter);
}
@@ -1557,6 +1556,15 @@
connection.close();
}
+ private void syncReconnectDevice(@NonNull UsbDevice device) {
+ this.mDevice = device;
+ }
+
+ private UsbDevice getReconnectDevice() {
+ return mDevice;
+ }
+
+
/**
* <p> This attachedtask the requests and does not care about them anymore after the
* system took them. The {@link attachedTask} handles the test after the main test done.
@@ -1600,6 +1608,8 @@
public void onReceive(Context context, Intent intent) {
synchronized (UsbDeviceTestActivity.this) {
UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
+ syncReconnectDevice(device);
+
switch (intent.getAction()) {
case ACTION_USB_PERMISSION:
boolean granted = intent.getBooleanExtra(
@@ -2267,6 +2277,12 @@
// If reconnect timeout make the test fail
assertEquals(0, errors.size());
+ // Update connection handle after reconnect
+ device = getReconnectDevice();
+ assertNotNull(device);
+ connection = mUsbManager.openDevice(device);
+ assertNotNull(connection);
+
connection.close();
// We should not be able to communicate with the device anymore
diff --git a/hostsidetests/gputools/Android.bp b/hostsidetests/gputools/Android.bp
index f919a8c..28730ae 100644
--- a/hostsidetests/gputools/Android.bp
+++ b/hostsidetests/gputools/Android.bp
@@ -14,12 +14,7 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-MIT
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
java_test_host {
diff --git a/hostsidetests/gputools/layers/Android.bp b/hostsidetests/gputools/layers/Android.bp
index 8d294d6..b007cb5 100644
--- a/hostsidetests/gputools/layers/Android.bp
+++ b/hostsidetests/gputools/layers/Android.bp
@@ -14,12 +14,16 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-MIT
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_hostsidetests_gputools_layers_vulkan_license",
+ ],
+}
+
+license {
+ name: "cts_hostsidetests_gputools_layers_vulkan_license",
+ license_kinds: ["SPDX-license-identifier-MIT"],
+ license_text: ["LICENSE_MIT"]
}
cc_test_library {
diff --git a/hostsidetests/gputools/layers/LICENSE_MIT b/hostsidetests/gputools/layers/LICENSE_MIT
new file mode 100644
index 0000000..fe3c973
--- /dev/null
+++ b/hostsidetests/gputools/layers/LICENSE_MIT
@@ -0,0 +1,18 @@
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and/or associated documentation files (the "Materials"), to
+deal in the Materials without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Materials, and to permit persons to whom the Materials are
+furnished to do so, subject to the following conditions:
+
+The above copyright notice(s) and this permission notice shall be included in
+all copies or substantial portions of the Materials.
+
+THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
+USE OR OTHER DEALINGS IN THE MATERIALS.
diff --git a/hostsidetests/graphics/gpumetrics/OWNERS b/hostsidetests/graphics/gpumetrics/OWNERS
new file mode 100644
index 0000000..959ca7c
--- /dev/null
+++ b/hostsidetests/graphics/gpumetrics/OWNERS
@@ -0,0 +1,7 @@
+# Bug component: 653544
+paulthomson@google.com
+pbaiget@google.com
+chrisforbes@google.com
+lpy@google.com
+lfy@google.com
+alecmouri@google.com
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
index 67c4033..f4961d8 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/BaseHdmiCecCtsTest.java
@@ -46,6 +46,7 @@
public class BaseHdmiCecCtsTest extends BaseHostJUnit4Test {
public static final String PROPERTY_LOCALE = "persist.sys.locale";
+ private static final String POWER_CONTROL_MODE = "power_control_mode";
/** Enum contains the list of possible address types. */
private enum AddressType {
@@ -377,7 +378,7 @@
checkDeviceAsleep();
}
- private void waitForTransitionTo(int finalState) throws Exception {
+ public void waitForTransitionTo(int finalState) throws Exception {
int powerStatus;
int waitTimeSeconds = 0;
LogicalAddress cecClientDevice = hdmiCecClient.getSelfDevice();
@@ -408,10 +409,14 @@
}
}
- public void sendDeviceToSleep() throws Exception {
+ public void sendDeviceToSleepWithoutWait() throws Exception {
ITestDevice device = getDevice();
WakeLockHelper.acquirePartialWakeLock(device);
device.executeShellCommand("input keyevent KEYCODE_SLEEP");
+ }
+
+ public void sendDeviceToSleep() throws Exception {
+ sendDeviceToSleepWithoutWait();
waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
}
@@ -431,4 +436,36 @@
ITestDevice device = getDevice();
device.executeShellCommand("cmd hdmi_control onetouchplay");
}
+
+ public String setPowerControlMode(String valToSet) throws Exception {
+ String val = getSettingsValue(POWER_CONTROL_MODE);
+ setSettingsValue(POWER_CONTROL_MODE, valToSet);
+ return val;
+ }
+
+ public boolean isDeviceActiveSource(ITestDevice device) throws DumpsysParseException {
+ final String activeSource = "activeSource";
+ final String pattern =
+ "(.*?)"
+ + "(isActiveSource\\(\\): )"
+ + "(?<"
+ + activeSource
+ + ">\\btrue\\b|\\bfalse\\b)"
+ + "(.*?)";
+ try {
+ Pattern p = Pattern.compile(pattern);
+ String dumpsys = device.executeShellCommand("dumpsys hdmi_control");
+ BufferedReader reader = new BufferedReader(new StringReader(dumpsys));
+ String line;
+ while ((line = reader.readLine()) != null) {
+ Matcher matcher = p.matcher(line);
+ if (matcher.matches()) {
+ return matcher.group(activeSource).equals("true");
+ }
+ }
+ } catch (IOException | DeviceNotAvailableException e) {
+ throw new DumpsysParseException("Could not fetch 'dumpsys hdmi_control' output.", e);
+ }
+ throw new DumpsysParseException("Could not parse isActiveSource() from dumpsys.");
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index 55409a2..3de26f1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -316,6 +316,31 @@
}
}
+ public void sendMultipleUserControlPressAndRelease(
+ LogicalAddress source, List<Integer> keycodes) throws CecClientWrapperException {
+ try {
+ for (int keycode : keycodes) {
+ String key = String.format("%02x", keycode);
+ mOutputConsole.write(
+ "tx "
+ + source
+ + targetDevice
+ + ":"
+ + CecOperand.USER_CONTROL_PRESSED
+ + ":"
+ + key);
+ mOutputConsole.newLine();
+ mOutputConsole.write(
+ "tx " + source + targetDevice + ":" + CecOperand.USER_CONTROL_RELEASED);
+ mOutputConsole.newLine();
+ mOutputConsole.flush();
+ TimeUnit.MILLISECONDS.sleep(200);
+ }
+ } catch (InterruptedException | IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
+ }
+
/**
* Sends a <USER_CONTROL_PRESSED> and <USER_CONTROL_RELEASED> from source to device through the
* output console of the cec-communication channel with the mentioned keycode.
@@ -345,6 +370,37 @@
}
/**
+ * Sends a {@code <UCP>} with and additional param. This is used to check that the DUT ignores
+ * additional params in an otherwise correct message.
+ */
+ public void sendUserControlPressAndReleaseWithAdditionalParams(
+ LogicalAddress source, LogicalAddress destination, int keyCode, int additionalParam)
+ throws CecClientWrapperException {
+ String key = String.format("%02x", keyCode);
+ String command =
+ "tx "
+ + source
+ + destination
+ + ":"
+ + CecOperand.USER_CONTROL_PRESSED
+ + ":"
+ + key
+ + ":"
+ + additionalParam;
+
+ try {
+ mOutputConsole.write(command);
+ mOutputConsole.newLine();
+ mOutputConsole.write(
+ "tx " + source + destination + ":" + CecOperand.USER_CONTROL_RELEASED);
+ mOutputConsole.newLine();
+ mOutputConsole.flush();
+ } catch (IOException ioe) {
+ throw new CecClientWrapperException(ErrorCodes.WriteConsole, ioe);
+ }
+ }
+
+ /**
* Sends a <UCP> message from source to destination through the output console of the
* cec-communication channel with the mentioned keycode. If holdKey is true, the method will
* send multiple <UCP> messages to simulate a long press. No <UCR> will be sent.
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index 2f1298d..a8426cc 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -29,6 +29,8 @@
public static final int TIMEOUT_CEC_REINIT_SECONDS = 5;
public static final int TIMEOUT_SAFETY_MS = 500;
+ public static final int INVALID_VENDOR_ID = 0xFFFFFF;
+
// Standard delay to allow the DUT to react to a CEC message or ADB command
public static final int DEVICE_WAIT_TIME_SECONDS = 5;
public static final int DEVICE_WAIT_TIME_MS = 5000;
@@ -38,19 +40,52 @@
public static final int TV_PHYSICAL_ADDRESS = 0x0000;
public static final int PHYSICAL_ADDRESS_LENGTH = 4; /* Num nibbles in CEC message */
- public static final int CEC_CONTROL_SELECT = 0x0;
- public static final int CEC_CONTROL_UP = 0x1;
- public static final int CEC_CONTROL_DOWN = 0x2;
- public static final int CEC_CONTROL_LEFT = 0x3;
- public static final int CEC_CONTROL_RIGHT = 0x4;
- public static final int CEC_CONTROL_BACK = 0xd;
- public static final int CEC_CONTROL_POWER = 0x40;
- public static final int CEC_CONTROL_VOLUME_UP = 0x41;
- public static final int CEC_CONTROL_VOLUME_DOWN = 0x42;
- public static final int CEC_CONTROL_MUTE = 0x43;
- public static final int CEC_CONTROL_POWER_TOGGLE_FUNCTION = 0x6B;
- public static final int CEC_CONTROL_POWER_OFF_FUNCTION = 0x6C;
- public static final int CEC_CONTROL_POWER_ON_FUNCTION = 0x6D;
+ public static final int CEC_KEYCODE_SELECT = 0x00;
+ public static final int CEC_KEYCODE_UP = 0x01;
+ public static final int CEC_KEYCODE_DOWN = 0x02;
+ public static final int CEC_KEYCODE_LEFT = 0x03;
+ public static final int CEC_KEYCODE_RIGHT = 0x04;
+ public static final int CEC_KEYCODE_ROOT_MENU = 0x09;
+ public static final int CEC_KEYCODE_SETUP_MENU = 0x0A;
+ public static final int CEC_KEYCODE_CONTENTS_MENU = 0x0B;
+ public static final int CEC_KEYCODE_BACK = 0x0D;
+ public static final int CEC_KEYCODE_MEDIA_TOP_MENU = 0x10;
+ public static final int CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU = 0x11;
+ public static final int CEC_KEYCODE_NUMBER_0_OR_NUMBER_10 = 0x20;
+ public static final int CEC_KEYCODE_NUMBERS_1 = 0x21;
+ public static final int CEC_KEYCODE_NUMBERS_2 = 0x22;
+ public static final int CEC_KEYCODE_NUMBERS_3 = 0x23;
+ public static final int CEC_KEYCODE_NUMBERS_4 = 0x24;
+ public static final int CEC_KEYCODE_NUMBERS_5 = 0x25;
+ public static final int CEC_KEYCODE_NUMBERS_6 = 0x26;
+ public static final int CEC_KEYCODE_NUMBERS_7 = 0x27;
+ public static final int CEC_KEYCODE_NUMBERS_8 = 0x28;
+ public static final int CEC_KEYCODE_NUMBERS_9 = 0x29;
+ public static final int CEC_KEYCODE_CHANNEL_UP = 0x30;
+ public static final int CEC_KEYCODE_CHANNEL_DOWN = 0x31;
+ public static final int CEC_KEYCODE_PREVIOUS_CHANNEL = 0x32;
+ public static final int CEC_KEYCODE_DISPLAY_INFORMATION = 0x35;
+ public static final int CEC_KEYCODE_POWER = 0x40;
+ public static final int CEC_KEYCODE_VOLUME_UP = 0x41;
+ public static final int CEC_KEYCODE_VOLUME_DOWN = 0x42;
+ public static final int CEC_KEYCODE_MUTE = 0x43;
+ public static final int CEC_KEYCODE_PLAY = 0x44;
+ public static final int CEC_KEYCODE_STOP = 0x45;
+ public static final int CEC_KEYCODE_PAUSE = 0x46;
+ public static final int CEC_KEYCODE_RECORD = 0x47;
+ public static final int CEC_KEYCODE_REWIND = 0x48;
+ public static final int CEC_KEYCODE_FAST_FORWARD = 0x49;
+ public static final int CEC_KEYCODE_EJECT = 0x4A;
+ public static final int CEC_KEYCODE_FORWARD = 0x4B;
+ public static final int CEC_KEYCODE_BACKWARD = 0x4C;
+ public static final int CEC_KEYCODE_POWER_TOGGLE_FUNCTION = 0x6B;
+ public static final int CEC_KEYCODE_POWER_OFF_FUNCTION = 0x6C;
+ public static final int CEC_KEYCODE_POWER_ON_FUNCTION = 0x6D;
+ public static final int CEC_KEYCODE_F1_BLUE = 0x71;
+ public static final int CEC_KEYCODE_F2_RED = 0x72;
+ public static final int CEC_KEYCODE_F3_GREEN = 0x73;
+ public static final int CEC_KEYCODE_F4_YELLOW = 0x74;
+ public static final int CEC_KEYCODE_DATA = 0x76;
public static final int UNRECOGNIZED_OPCODE = 0x0;
@@ -95,6 +130,9 @@
public static final int CEC_POWER_STATUS_IN_TRANSITION_TO_ON = 0x2;
public static final int CEC_POWER_STATUS_IN_TRANSITION_TO_STANDBY = 0x3;
+ /** Poll Message Success */
+ public static final String POLL_SUCCESS = "POLL message sent";
+
// CEC Device feature list
public static final String HDMI_CEC_FEATURE = "feature:android.hardware.hdmi.cec";
public static final String LEANBACK_FEATURE = "feature:android.software.leanback";
@@ -107,4 +145,13 @@
*/
public static final File CEC_MAP_FOLDER =
new File(System.getProperty("java.io.tmpdir"), "cec-cts-temp");
+
+
+ // Power Control Modes for source devices
+ public static final String POWER_CONTROL_MODE_BROADCAST = "broadcast";
+ public static final String POWER_CONTROL_MODE_NONE = "none";
+ public static final String POWER_CONTROL_MODE_TV = "to_tv";
+
+ // CEC 2.0 Report Feature Bits
+ public static final int FEATURES_SINK_SUPPORTS_ARC_TX_BIT = 0x4;
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java
index 6486313..c12bae1 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/RemoteControlPassthrough.java
@@ -18,6 +18,8 @@
import com.android.tradefed.device.ITestDevice;
+import java.util.HashMap;
+
/** Helper class with methods to test the remote control passthrough functionality */
public final class RemoteControlPassthrough {
@@ -33,6 +35,9 @@
/** The command to clear the main activity. */
private static final String CLEAR_COMMAND = String.format("pm clear %s", PACKAGE);
+ private static final HashMap<Integer, String> mUserControlPressKeys_20 =
+ createUserControlPressKeys_20();
+
/**
* Tests that the device responds correctly to a {@code <USER_CONTROL_PRESSED>} message followed
* immediately by a {@code <USER_CONTROL_RELEASED>} message.
@@ -50,23 +55,23 @@
// Start the APK and wait for it to complete.
device.executeShellCommand(START_COMMAND);
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_UP, false);
LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_UP");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_DOWN, false);
LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_DOWN");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_LEFT, false);
LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_LEFT");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_RIGHT, false);
LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_RIGHT");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_SELECT, false);
LogHelper.assertLog(
device, CLASS, "Short press KEYCODE_DPAD_CENTER", "Short press KEYCODE_ENTER");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, false);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_BACK, false);
LogHelper.assertLog(device, CLASS, "Short press KEYCODE_BACK");
}
@@ -87,23 +92,23 @@
// Start the APK and wait for it to complete.
device.executeShellCommand(START_COMMAND);
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_UP, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_DOWN, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_LEFT, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_RIGHT, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_SELECT, true);
LogHelper.assertLog(
device, CLASS, "Long press KEYCODE_DPAD_CENTER", "Long press KEYCODE_ENTER");
hdmiCecClient.sendUserControlPressAndRelease(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_BACK, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
}
@@ -124,22 +129,22 @@
// Start the APK and wait for it to complete.
device.executeShellCommand(START_COMMAND);
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_UP, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_UP, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_DOWN, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_DOWN, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_LEFT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_LEFT, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_RIGHT, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_SELECT, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_SELECT, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_CENTER");
hdmiCecClient.sendUserControlPress(
- sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_CONTROL_BACK, true);
+ sourceDevice, dutLogicalAddress, HdmiCecConstants.CEC_KEYCODE_BACK, true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
}
@@ -163,44 +168,160 @@
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_UP,
- HdmiCecConstants.CEC_CONTROL_BACK,
+ HdmiCecConstants.CEC_KEYCODE_UP,
+ HdmiCecConstants.CEC_KEYCODE_BACK,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_UP");
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_DOWN,
- HdmiCecConstants.CEC_CONTROL_UP,
+ HdmiCecConstants.CEC_KEYCODE_DOWN,
+ HdmiCecConstants.CEC_KEYCODE_UP,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_DOWN");
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_LEFT,
- HdmiCecConstants.CEC_CONTROL_DOWN,
+ HdmiCecConstants.CEC_KEYCODE_LEFT,
+ HdmiCecConstants.CEC_KEYCODE_DOWN,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_LEFT");
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_RIGHT,
- HdmiCecConstants.CEC_CONTROL_LEFT,
+ HdmiCecConstants.CEC_KEYCODE_RIGHT,
+ HdmiCecConstants.CEC_KEYCODE_LEFT,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_RIGHT");
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_SELECT,
- HdmiCecConstants.CEC_CONTROL_RIGHT,
+ HdmiCecConstants.CEC_KEYCODE_SELECT,
+ HdmiCecConstants.CEC_KEYCODE_RIGHT,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_DPAD_CENTER");
hdmiCecClient.sendUserControlInterruptedPressAndHold(
sourceDevice,
dutLogicalAddress,
- HdmiCecConstants.CEC_CONTROL_BACK,
- HdmiCecConstants.CEC_CONTROL_SELECT,
+ HdmiCecConstants.CEC_KEYCODE_BACK,
+ HdmiCecConstants.CEC_KEYCODE_SELECT,
true);
LogHelper.assertLog(device, CLASS, "Long press KEYCODE_BACK");
}
+
+ /**
+ * Tests that the device responds correctly to a {@code <User Control Pressed> [keyCode]} press
+ * and release operation when it has an additional parameter following the keyCode.
+ */
+ public static void checkUserControlPressAndReleaseWithAdditionalParams(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+ hdmiCecClient.sendUserControlPressAndReleaseWithAdditionalParams(
+ sourceDevice,
+ dutLogicalAddress,
+ HdmiCecConstants.CEC_KEYCODE_UP,
+ HdmiCecConstants.CEC_KEYCODE_DOWN);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_DPAD_UP");
+ }
+
+ /**
+ * Tests that the device that support cec version 2.0 responds correctly to a
+ * {@code <USER_CONTROL_PRESSED>} message followed immediately by a
+ * {@code <USER_CONTROL_RELEASED>} message.
+ */
+ public static void checkUserControlPressAndRelease_20(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+
+ for (Integer userControlPressKey : mUserControlPressKeys_20.keySet()) {
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, userControlPressKey, false);
+ LogHelper.assertLog(
+ device,
+ CLASS,
+ "Short press KEYCODE_" + mUserControlPressKeys_20.get(userControlPressKey));
+ }
+ }
+
+ private static HashMap<Integer, String> createUserControlPressKeys_20() {
+ HashMap<Integer, String> userControlPressKeys = new HashMap<Integer, String>();
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_UP,"DPAD_UP");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_DOWN,"DPAD_DOWN");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_LEFT,"DPAD_LEFT");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_RIGHT,"DPAD_RIGHT");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_ROOT_MENU,"MENU");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_SETUP_MENU,"SETTINGS");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_CONTENTS_MENU,"TV_CONTENTS_MENU");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_BACK,"BACK");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_MEDIA_TOP_MENU,"MEDIA_TOP_MENU");
+ userControlPressKeys.put(
+ HdmiCecConstants.CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU,"TV_MEDIA_CONTEXT_MENU");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBER_0_OR_NUMBER_10,"0");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_1,"1");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_2,"2");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_3,"3");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_4,"4");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_5,"5");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_6,"6");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_7,"7");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_8,"8");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_NUMBERS_9,"9");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_CHANNEL_UP,"CHANNEL_UP");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_CHANNEL_DOWN,"CHANNEL_DOWN");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_PREVIOUS_CHANNEL,"LAST_CHANNEL");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_DISPLAY_INFORMATION,"INFO");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_PLAY,"MEDIA_PLAY");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_STOP,"MEDIA_STOP");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_PAUSE,"MEDIA_PAUSE");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_RECORD,"MEDIA_RECORD");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_REWIND,"MEDIA_REWIND");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_FAST_FORWARD,"MEDIA_FAST_FORWARD");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_EJECT,"MEDIA_EJECT");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_FORWARD,"MEDIA_NEXT");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_BACKWARD,"MEDIA_PREVIOUS");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_F1_BLUE,"PROG_BLUE");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_F2_RED,"PROG_RED");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_F3_GREEN,"PROG_GREEN");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_F4_YELLOW,"PROG_YELLOW");
+ userControlPressKeys.put(HdmiCecConstants.CEC_KEYCODE_DATA,"TV_DATA_SERVICE");
+ return userControlPressKeys;
+ }
+
+ public static void checkUserControlPressAndRelease(
+ HdmiCecClientWrapper hdmiCecClient,
+ ITestDevice device,
+ LogicalAddress sourceDevice,
+ LogicalAddress dutLogicalAddress,
+ int cecKeycode,
+ String androidKeycode)
+ throws Exception {
+ // Clear activity
+ device.executeShellCommand(CLEAR_COMMAND);
+ // Clear logcat.
+ device.executeAdbCommand("logcat", "-c");
+ // Start the APK and wait for it to complete.
+ device.executeShellCommand(START_COMMAND);
+
+ hdmiCecClient.sendUserControlPressAndRelease(
+ sourceDevice, dutLogicalAddress, cecKeycode, false);
+ LogHelper.assertLog(device, CLASS, "Short press KEYCODE_" + androidKeycode);
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
index 0b217b8..e27ae7e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecSystemAudioModeTest.java
@@ -251,7 +251,7 @@
CecMessage.formatParams(HdmiCecConstants.TV_PHYSICAL_ADDRESS,
HdmiCecConstants.PHYSICAL_ADDRESS_LENGTH));
hdmiCecClient.sendUserControlPressAndRelease(LogicalAddress.TV, AUDIO_DEVICE,
- HdmiCecConstants.CEC_CONTROL_MUTE, false);
+ HdmiCecConstants.CEC_KEYCODE_MUTE, false);
assertWithMessage("Device is not muted")
.that(AudioManagerHelper.isDeviceMuted(getDevice()))
.isTrue();
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
new file mode 100644
index 0000000..140c113
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hdmicec.cts.common;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
+import android.hdmicec.cts.RemoteControlPassthrough;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+/** HDMI CEC 2.0 general protocol tests */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecGeneralProtocolTest extends BaseHdmiCecCtsTest {
+
+ @Rule
+ public RuleChain ruleChain =
+ RuleChain.outerRule(CecRules.requiresCec(this))
+ .around(CecRules.requiresLeanback(this))
+ .around(hdmiCecClient);
+
+ /**
+ * Test HF4-2-5, HF4-2-6 (CEC 2.0)
+ *
+ * <p>Tests that the device ignores any additional trailing parameters in an otherwise correct
+ * CEC message.
+ *
+ * <p>e.g. If {@code 14:44:01:02 (<UCP>[KEYCODE_DPAD_UP])} is sent to the DUT, the DUT should
+ * ignore the last byte of the parameter and treat it as {@code <UCP>[KEYCODE_DPAD_UP]}
+ */
+ @Test
+ public void cect_hf_ignoreAdditionalParams() throws Exception {
+ setCec20();
+ RemoteControlPassthrough.checkUserControlPressAndReleaseWithAdditionalParams(
+ hdmiCecClient, getDevice(), LogicalAddress.RECORDER_1, getTargetLogicalAddress());
+ }
+
+ /**
+ * Test HF4-2-15 (CEC 2.0)
+ *
+ * <p>Tests that the DUT responds to mandatory messages in both on and standby states
+ */
+ @Test
+ public void cect_hf_4_2_15() throws Exception {
+ setCec20();
+ int cecVersion = HdmiCecConstants.CEC_VERSION_2_0;
+ int physicalAddressParams;
+ int features = 0;
+ String osdName;
+
+ sendDeviceToSleep();
+ try {
+ // Check POLL message response
+ hdmiCecClient.sendPoll();
+ if (!hdmiCecClient.checkConsoleOutput(HdmiCecConstants.POLL_SUCCESS)) {
+ throw new Exception("Device did not respond to Poll");
+ }
+
+ // Check CEC version
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GET_CEC_VERSION);
+ String message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.CEC_VERSION);
+ assertThat(CecMessage.getParams(message)).isEqualTo(cecVersion);
+
+ // Give physical address
+ hdmiCecClient.sendCecMessage(
+ hdmiCecClient.getSelfDevice(), CecOperand.GIVE_PHYSICAL_ADDRESS);
+ message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
+ physicalAddressParams = CecMessage.getParams(message);
+
+ // Give features
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GIVE_FEATURES);
+ message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_FEATURES);
+ features = CecMessage.getParams(message);
+
+ // Give power status
+ hdmiCecClient.sendCecMessage(
+ hdmiCecClient.getSelfDevice(), CecOperand.GIVE_POWER_STATUS);
+ message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.REPORT_POWER_STATUS);
+ assertThat(CecMessage.getParams(message))
+ .isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+
+ // Give OSD name
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GIVE_OSD_NAME);
+ message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.SET_OSD_NAME);
+ osdName = CecMessage.getParamsAsString(message);
+ } finally {
+ wakeUpDevice();
+ }
+
+ // Repeat the above with DUT not in standby, and verify that the responses are the same,
+ // except the <Report Power Status> message
+ // Check POLL message response
+ hdmiCecClient.sendPoll();
+ if (!hdmiCecClient.checkConsoleOutput(HdmiCecConstants.POLL_SUCCESS)) {
+ throw new Exception("Device did not respond to Poll");
+ }
+
+ // Check CEC version
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GET_CEC_VERSION);
+ String message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.CEC_VERSION);
+ assertThat(CecMessage.getParams(message)).isEqualTo(cecVersion);
+
+ // Give physical address
+ hdmiCecClient.sendCecMessage(
+ hdmiCecClient.getSelfDevice(), CecOperand.GIVE_PHYSICAL_ADDRESS);
+ message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_PHYSICAL_ADDRESS);
+ assertThat(CecMessage.getParams(message)).isEqualTo(physicalAddressParams);
+
+ // Give features
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GIVE_FEATURES);
+ message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_FEATURES);
+ assertThat(CecMessage.getParams(message)).isEqualTo(features);
+
+ // Give power status
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GIVE_POWER_STATUS);
+ message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.REPORT_POWER_STATUS);
+ assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+
+ // Give OSD name
+ hdmiCecClient.sendCecMessage(hdmiCecClient.getSelfDevice(), CecOperand.GIVE_OSD_NAME);
+ message =
+ hdmiCecClient.checkExpectedOutput(
+ hdmiCecClient.getSelfDevice(), CecOperand.SET_OSD_NAME);
+ assertThat(CecMessage.getParamsAsString(message)).isEqualTo(osdName);
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
index ce4c4a1..fd7f10a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecInvalidMessagesTest.java
@@ -180,7 +180,7 @@
// Start the APK and wait for it to complete.
device.executeShellCommand(START_COMMAND);
hdmiCecClient.sendUserControlPressAndRelease(
- source, LogicalAddress.BROADCAST, HdmiCecConstants.CEC_CONTROL_UP, false);
+ source, LogicalAddress.BROADCAST, HdmiCecConstants.CEC_KEYCODE_UP, false);
LogHelper.assertLogDoesNotContain(getDevice(), CLASS, "Short press KEYCODE_DPAD_UP");
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
index 966173a..50b57de 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecPowerStatusTest.java
@@ -34,6 +34,7 @@
import org.junit.rules.RuleChain;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -124,6 +125,123 @@
}
/**
+ * Test HF4-6-22 (CEC 2.0)
+ *
+ * <p>Verifies that the DUT notifies the transition back to Standby state if an ongoing
+ * transition from standby state to power on state is interrupted.
+ */
+ @Test
+ public void cect_hf4_6_22_interruptedPowerOn() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+
+ try {
+ // Turn device off
+ sendDeviceToSleep();
+
+ List<Integer> keycodes = new ArrayList<>();
+ keycodes.add(HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION);
+ keycodes.add(HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION);
+
+ // Send a <UCP>[Power On] immediately followed by a <UCP>[Power Off]
+ hdmiCecClient.sendMultipleUserControlPressAndRelease(LogicalAddress.TV, keycodes);
+
+ String reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+
+ switch (CecMessage.getParams(reportPowerStatus)) {
+ case HdmiCecConstants.CEC_POWER_STATUS_STANDBY:
+ // No further messages are expected, check for 5s outside the switch case.
+ break;
+ case HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_STANDBY:
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ assertThat(CecMessage.getParams(reportPowerStatus))
+ .isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+ break;
+ case HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_ON:
+ case HdmiCecConstants.CEC_POWER_STATUS_ON:
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ int powerState = CecMessage.getParams(reportPowerStatus);
+ if (powerState == HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_STANDBY) {
+ // If it is in transition, wait for another <Report Power Status>[Power Off]
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ powerState = CecMessage.getParams(reportPowerStatus);
+ }
+ // If no <Report Power Status>[Power Off] is received, fail the test
+ assertThat(powerState).isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+ break;
+ }
+ // Make sure there are no further <Report Power Status> for 5s
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.BROADCAST, CecOperand.REPORT_POWER_STATUS, 5000);
+ } finally {
+ wakeUpDevice();
+ }
+ }
+
+ /**
+ * Test HF4-6-23 (CEC 2.0)
+ *
+ * <p>Verifies that the DUT notifies the transition back to On state if an ongoing transition
+ * from On state to Standby state is interrupted.
+ */
+ @Test
+ public void cect_hf4_6_23_interruptedStandby() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+
+ try {
+ // Turn device off
+ wakeUpDevice();
+ WakeLockHelper.acquirePartialWakeLock(getDevice());
+
+ List<Integer> keycodes = new ArrayList<>();
+ keycodes.add(HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION);
+ keycodes.add(HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION);
+
+ // Send a <UCP>[Power Off] immediately followed by a <UCP>[Power On]
+ hdmiCecClient.sendMultipleUserControlPressAndRelease(LogicalAddress.TV, keycodes);
+
+ String reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+
+ switch (CecMessage.getParams(reportPowerStatus)) {
+ case HdmiCecConstants.CEC_POWER_STATUS_ON:
+ // No further messages are expected, check for 5s outside the switch case.
+ break;
+ case HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_ON:
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ assertThat(CecMessage.getParams(reportPowerStatus))
+ .isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+ break;
+ case HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_STANDBY:
+ case HdmiCecConstants.CEC_POWER_STATUS_STANDBY:
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ int powerState = CecMessage.getParams(reportPowerStatus);
+ if (powerState == HdmiCecConstants.CEC_POWER_STATUS_IN_TRANSITION_TO_ON) {
+ // If it is in transition, wait for another <Report Power Status>[Power On]
+ reportPowerStatus =
+ hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_POWER_STATUS);
+ powerState = CecMessage.getParams(reportPowerStatus);
+ }
+ // If no <Report Power Status>[Power On] is received, fail the test
+ assertThat(powerState).isEqualTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+ break;
+ }
+ // Make sure there are no further <Report Power Status> for 5s
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.BROADCAST, CecOperand.REPORT_POWER_STATUS, 5000);
+ } finally {
+ wakeUpDevice();
+ }
+ }
+
+ /**
* Test 11.1.14-1, 11.2.14-1
*
* <p>Tests that the device sends a {@code <REPORT_POWER_STATUS>} with params 0x0 when the
@@ -186,9 +304,9 @@
@Test
public void cect_hf4_6_8_userControlPressed_powerOn() throws Exception {
ITestDevice device = getDevice();
- List<Integer> powerControlOperands = Arrays.asList(HdmiCecConstants.CEC_CONTROL_POWER,
- HdmiCecConstants.CEC_CONTROL_POWER_ON_FUNCTION,
- HdmiCecConstants.CEC_CONTROL_POWER_TOGGLE_FUNCTION);
+ List<Integer> powerControlOperands = Arrays.asList(HdmiCecConstants.CEC_KEYCODE_POWER,
+ HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION,
+ HdmiCecConstants.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
LogicalAddress source = hasDeviceType(HdmiCecConstants.CEC_DEVICE_TYPE_TV)
? LogicalAddress.PLAYBACK_1
@@ -224,8 +342,8 @@
public void cect_hf4_6_10_userControlPressed_powerOff() throws Exception {
ITestDevice device = getDevice();
List<Integer> powerControlOperands = Arrays.asList(
- HdmiCecConstants.CEC_CONTROL_POWER_OFF_FUNCTION,
- HdmiCecConstants.CEC_CONTROL_POWER_TOGGLE_FUNCTION);
+ HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION,
+ HdmiCecConstants.CEC_KEYCODE_POWER_TOGGLE_FUNCTION);
LogicalAddress source = hasDeviceType(HdmiCecConstants.CEC_DEVICE_TYPE_TV)
? LogicalAddress.PLAYBACK_1
@@ -252,4 +370,97 @@
}
}
}
+
+ /**
+ * Test HF4-6-26
+ *
+ * <p> Verify that, when a Source device is put to Standby by the user, it does not broadcast a
+ * system {@code <Standby>} message unless explicitly requested by the user.
+ */
+ @Test
+ public void cect_hf4_6_26_standby_noBroadcast_20() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_NONE);
+ try {
+ sendDeviceToSleep();
+ hdmiCecClient.checkOutputDoesNotContainMessage(
+ LogicalAddress.BROADCAST, CecOperand.STANDBY);
+ } finally {
+ wakeUpDevice();
+ setPowerControlMode(previousPowerControlMode);
+ }
+ }
+
+ /*
+ * Test HF4-6-28
+ *
+ * <p>Tests that the DUT handles {@code <User Control Pressed>} of any power related buttons
+ * correctly
+ */
+ @Test
+ public void cect_hf_4_6_28_testPowerUcpHandling() throws Exception {
+ setCec20();
+ int waitSeconds = 10;
+ ITestDevice device = getDevice();
+ // Ensure device is awake.
+ wakeUpDevice();
+
+ // Acquire the wakelock.
+ WakeLockHelper.acquirePartialWakeLock(device);
+ try {
+ // All <UCP> commands will be sent from TV.
+ LogicalAddress source = LogicalAddress.TV;
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_TOGGLE_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+
+ // Toggle power again, DUT should wakeup.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_TOGGLE_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+
+ // Send <UCP>[Power On]. DUT should remain in ON state, check for 10s.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+ TimeUnit.SECONDS.sleep(waitSeconds);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+
+ // Send <UCP>[Power Off]. DUT should got to OFF state, check for 10s.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+ TimeUnit.SECONDS.sleep(waitSeconds);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+
+ // Send <UCP>[Power Off] again. DUT should stay in OFF state, check for 10s.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+ TimeUnit.SECONDS.sleep(waitSeconds);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+
+ // Send <UCP>[Power On]. DUT should go to ON state, check for 10s.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+ TimeUnit.SECONDS.sleep(waitSeconds);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+
+ // Send <UCP> [Power]. DUT should go to standby.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_STANDBY);
+
+ // Send <UCP> [Power]. DUT should wakeup.
+ hdmiCecClient.sendUserControlPressAndRelease(
+ source, HdmiCecConstants.CEC_KEYCODE_POWER, false);
+ waitForTransitionTo(HdmiCecConstants.CEC_POWER_STATUS_ON);
+ } finally {
+ // Wake up the device. This will also release the wakelock.
+ wakeUpDevice();
+ }
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
index 5a7cda1..0eebc18 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemAudioControlTest.java
@@ -97,7 +97,7 @@
String message =
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_PRESSED);
- assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_CONTROL_VOLUME_UP);
+ assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_KEYCODE_VOLUME_UP);
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_RELEASED);
/* TODO: b/174733146 For TV devices, assert that the volume level has not changed. */
@@ -107,7 +107,7 @@
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_PRESSED);
assertThat(CecMessage.getParams(message))
- .isEqualTo(HdmiCecConstants.CEC_CONTROL_VOLUME_DOWN);
+ .isEqualTo(HdmiCecConstants.CEC_KEYCODE_VOLUME_DOWN);
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_RELEASED);
/* TODO: b/174733146 For TV devices, assert that the volume level has not changed. */
@@ -138,7 +138,7 @@
String message =
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_PRESSED);
- assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_CONTROL_MUTE);
+ assertThat(CecMessage.getParams(message)).isEqualTo(HdmiCecConstants.CEC_KEYCODE_MUTE);
hdmiCecClient.checkExpectedOutput(
hdmiCecClient.getSelfDevice(), CecOperand.USER_CONTROL_RELEASED);
/* TODO: b/174733146 For TV devices, assert that the volume level has not changed. */
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
index 15eca65..33f705e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemInformationTest.java
@@ -198,4 +198,28 @@
wakeUpDevice();
}
}
+
+ /**
+ * Test HF4-2-16 (CEC 2.0)
+ *
+ * <p>Tests that the DUT responds to a {@code <Give Device Vendor Id>} with a {@code <Device
+ * Vendor ID>} message or a {@code <Feature Abort>[Unrecognized Opcode]}
+ */
+ @Test
+ public void cect_hf_4_2_16_GiveDeviceVendorId() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+ hdmiCecClient.sendCecMessage(
+ hdmiCecClient.getSelfDevice(), CecOperand.GIVE_DEVICE_VENDOR_ID);
+ String message =
+ hdmiCecClient.checkExpectedOutputOrFeatureAbort(
+ LogicalAddress.BROADCAST,
+ CecOperand.DEVICE_VENDOR_ID,
+ CecOperand.GIVE_DEVICE_VENDOR_ID,
+ HdmiCecConstants.ABORT_UNRECOGNIZED_MODE);
+ if (CecMessage.getOperand(message) == CecOperand.GIVE_DEVICE_VENDOR_ID) {
+ assertThat(CecMessage.getParams(message))
+ .isNotEqualTo(HdmiCecConstants.INVALID_VENDOR_ID);
+ }
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemStandbyTest.java
index 19eff6c..6541ca6 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemStandbyTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecSystemStandbyTest.java
@@ -40,10 +40,9 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecSystemStandbyTest extends BaseHdmiCecCtsTest {
- private static final String HDMI_CONTROL_DEVICE_AUTO_OFF =
- "hdmi_control_auto_device_off_enabled";
- private static final String POWER_CONTROL_MODE = "send_standby_on_sleep";
- private static final String POWER_CONTROL_MODE_NONE = "none";
+ private static final String TV_SEND_STANDBY_ON_SLEEP = "tv_send_standby_on_sleep";
+ private static final String TV_SEND_STANDBY_ON_SLEEP_ENABLED = "1";
+ private static final String TV_SEND_STANDBY_ON_SLEEP_DISABLED = "0";
public List<LogicalAddress> mLogicalAddresses = new ArrayList<>();
public boolean previousDeviceAutoOff;
@@ -59,7 +58,7 @@
public void initialTestSetup() throws Exception {
defineLogicalAddressList();
previousDeviceAutoOff = setHdmiControlDeviceAutoOff(false);
- previousPowerControlMode = setPowerControlMode(POWER_CONTROL_MODE_NONE);
+ previousPowerControlMode = setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_NONE);
}
@After
@@ -140,19 +139,9 @@
}
private boolean setHdmiControlDeviceAutoOff(boolean turnOn) throws Exception {
- ITestDevice device = getDevice();
- String val = device.executeShellCommand("settings get global " +
- HDMI_CONTROL_DEVICE_AUTO_OFF).trim();
- String valToSet = turnOn ? "1" : "0";
- device.executeShellCommand("settings put global "
- + HDMI_CONTROL_DEVICE_AUTO_OFF + " " + valToSet);
- device.executeShellCommand("settings get global " + HDMI_CONTROL_DEVICE_AUTO_OFF);
- return val.equals("1");
- }
-
- private String setPowerControlMode(String valToSet) throws Exception {
- String val = getSettingsValue(POWER_CONTROL_MODE);
- setSettingsValue(POWER_CONTROL_MODE, valToSet);
- return val;
+ String val = getSettingsValue(TV_SEND_STANDBY_ON_SLEEP);
+ setSettingsValue(TV_SEND_STANDBY_ON_SLEEP, turnOn ? TV_SEND_STANDBY_ON_SLEEP_ENABLED
+ : TV_SEND_STANDBY_ON_SLEEP_DISABLED);
+ return val == TV_SEND_STANDBY_ON_SLEEP_ENABLED;
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
index 5dd4b9d..408d719 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecPowerStatusTest.java
@@ -52,16 +52,16 @@
private static final List<String> UCP_POWER_MSGS = new ArrayList<>(Arrays.asList(
CecMessage.buildCecMessage(LogicalAddress.PLAYBACK_1, LogicalAddress.TV,
- CecOperand.USER_CONTROL_PRESSED, HdmiCecConstants.CEC_CONTROL_POWER),
+ CecOperand.USER_CONTROL_PRESSED, HdmiCecConstants.CEC_KEYCODE_POWER),
CecMessage.buildCecMessage(LogicalAddress.PLAYBACK_1, LogicalAddress.TV,
CecOperand.USER_CONTROL_PRESSED,
- HdmiCecConstants.CEC_CONTROL_POWER_TOGGLE_FUNCTION),
+ HdmiCecConstants.CEC_KEYCODE_POWER_TOGGLE_FUNCTION),
CecMessage.buildCecMessage(LogicalAddress.PLAYBACK_1, LogicalAddress.TV,
CecOperand.USER_CONTROL_PRESSED,
- HdmiCecConstants.CEC_CONTROL_POWER_OFF_FUNCTION),
+ HdmiCecConstants.CEC_KEYCODE_POWER_OFF_FUNCTION),
CecMessage.buildCecMessage(LogicalAddress.PLAYBACK_1, LogicalAddress.TV,
CecOperand.USER_CONTROL_PRESSED,
- HdmiCecConstants.CEC_CONTROL_POWER_ON_FUNCTION)));
+ HdmiCecConstants.CEC_KEYCODE_POWER_ON_FUNCTION)));
private static final List<CecOperand> VIEW_ON_MSGS =
new ArrayList<>(Arrays.asList(CecOperand.TEXT_VIEW_ON, CecOperand.IMAGE_VIEW_ON));
@@ -140,4 +140,55 @@
wakeUpDevice();
}
}
-}
\ No newline at end of file
+
+ /**
+ * Test HF4-6-16
+ *
+ * <p>Verify that the DUT initially sends a {@code <Standby>} message to the TV when system
+ * standby feature is enabled, before sending any {@code <User Control Pressed>} with
+ * power-related operands. (Ref section 11.5.1 in CEC 2.1 specification)
+ */
+ @Test
+ public void cect_hf4_6_16_standby_tvBeforeUcp_20() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
+
+ try {
+ sendDeviceToSleepWithoutWait();
+ hdmiCecClient.checkMessagesInOrder(
+ LogicalAddress.TV,
+ new ArrayList<>(Arrays.asList(CecOperand.STANDBY)),
+ UCP_POWER_MSGS);
+ } finally {
+ wakeUpDevice();
+ setPowerControlMode(previousPowerControlMode);
+ }
+ }
+
+ /**
+ * Test HF4-6-19
+ *
+ * <p>Verify that the DUT initially broadcasts a {@code <Standby>} message when the system
+ * standby feature is enabled, before sending any {@code <User Control Pressed>} with
+ * power-related operands.
+ */
+ @Test
+ public void cect_hf4_6_19_standby_broadcastBeforeUcp_20() throws Exception {
+ ITestDevice device = getDevice();
+ setCec20();
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_BROADCAST);
+ try {
+ sendDeviceToSleepWithoutWait();
+ hdmiCecClient.checkMessagesInOrder(
+ LogicalAddress.BROADCAST,
+ new ArrayList<>(Arrays.asList(CecOperand.STANDBY)),
+ UCP_POWER_MSGS);
+ } finally {
+ wakeUpDevice();
+ setPowerControlMode(previousPowerControlMode);
+ }
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
index c0ebfb8..cc7d5fd 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRemoteControlPassThroughTest.java
@@ -17,6 +17,8 @@
package android.hdmicec.cts.playback;
import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecMessage;
+import android.hdmicec.cts.CecOperand;
import android.hdmicec.cts.HdmiCecConstants;
import android.hdmicec.cts.LogicalAddress;
import android.hdmicec.cts.RemoteControlPassthrough;
@@ -74,4 +76,69 @@
RemoteControlPassthrough.checkUserControlPressAndHold(
hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
}
+
+ /**
+ * HF 4-8-4
+ *
+ * <p>Verify that the device that support cec version 2.0 accepts {@code <USER_CONTROL_PRESSED>}
+ * messages and maps to appropriate internal action.
+ *
+ * No Android keycode defined for {@code <CEC_KEYCODE_FAVORITE_MENU>},
+ * {@code <CEC_KEYCODE_STOP_RECORD>} and {@code <CEC_KEYCODE_PAUSE_RECORD>}
+ *
+ * The UI commands Audio Description, internet and 3D mode are introduced in CEC 2.0 devices but
+ * they haven't been implemented yet.
+ * TODO: Add these UI commands once they are implemented.
+ */
+ @Test
+ public void cect_4_8_4_UserControlPressAndRelease_20() throws Exception {
+ setCec20();
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndRelease_20(
+ hdmiCecClient, getDevice(), LogicalAddress.TV, dutLogicalAddress);
+ }
+
+ /**
+ * Test HF4-8-12
+ *
+ * <p>Tests that device sends the UCP Commands related to menus (Device Root Menu, Device Setup
+ * Menu, Contents Menu, Media Top Menu, Media Context-Sensitive Menu) in the operand [RC Profile
+ * Source] that is sent in the <Report Features> message and verifies that device reacts to sent
+ * UCP commands.
+ */
+ @Test
+ public void cect_hf4_8_12_UCPForRcProfileSearchOperand() throws Exception {
+ setCec20();
+ hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_FEATURES);
+ String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_FEATURES);
+ int remoteControlProfileSource = CecMessage.getParams(message, 4, 6);
+ if ((remoteControlProfileSource & 0x01) == 0x01) {
+ sendUcpMenuCommand(
+ HdmiCecConstants.CEC_KEYCODE_MEDIA_CONTEXT_SENSITIVE_MENU,
+ "TV_MEDIA_CONTEXT_MENU");
+ }
+ if ((remoteControlProfileSource & 0x02) == 0x02) {
+ sendUcpMenuCommand(HdmiCecConstants.CEC_KEYCODE_MEDIA_TOP_MENU, "MEDIA_TOP_MENU");
+ }
+ if ((remoteControlProfileSource & 0x04) == 0x04) {
+ sendUcpMenuCommand(HdmiCecConstants.CEC_KEYCODE_CONTENTS_MENU, "TV_CONTENTS_MENU");
+ }
+ if ((remoteControlProfileSource & 0x08) == 0x08) {
+ sendUcpMenuCommand(HdmiCecConstants.CEC_KEYCODE_SETUP_MENU, "SETTINGS");
+ }
+ if ((remoteControlProfileSource & 0x10) == 0x10) {
+ sendUcpMenuCommand(HdmiCecConstants.CEC_KEYCODE_ROOT_MENU, "MENU");
+ }
+ }
+
+ private void sendUcpMenuCommand(int cecKeycode, String androidKeycode) throws Exception {
+ LogicalAddress dutLogicalAddress = getTargetLogicalAddress(getDevice(), DUT_DEVICE_TYPE);
+ RemoteControlPassthrough.checkUserControlPressAndRelease(
+ hdmiCecClient,
+ getDevice(),
+ LogicalAddress.TV,
+ dutLogicalAddress,
+ cecKeycode,
+ androidKeycode);
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
index 75d73ea..e715f91 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecRoutingControlTest.java
@@ -39,10 +39,6 @@
public final class HdmiCecRoutingControlTest extends BaseHdmiCecCtsTest {
private static final int PHYSICAL_ADDRESS = 0x1000;
- private static final String POWER_CONTROL_MODE =
- "power_control_mode";
- private static final String POWER_CONTROL_MODE_NONE =
- "none";
public HdmiCecRoutingControlTest() {
super(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
@@ -57,12 +53,6 @@
this, HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE))
.around(hdmiCecClient);
- private String setPowerControlMode(String valToSet) throws Exception {
- String val = getSettingsValue(POWER_CONTROL_MODE);
- setSettingsValue(POWER_CONTROL_MODE, valToSet);
- return val;
- }
-
/**
* Test 11.1.2-2, HF4-7-2
*
@@ -143,7 +133,8 @@
@Test
public void cect_11_2_2_4_InactiveSourceOnStandby() throws Exception {
ITestDevice device = getDevice();
- String previousPowerControlMode = setPowerControlMode(POWER_CONTROL_MODE_NONE);
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_NONE);
try {
int dumpsysPhysicalAddress = getDumpsysPhysicalAddress();
hdmiCecClient.sendCecMessage(
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStandbyTest.java
new file mode 100644
index 0000000..d9f0b95
--- /dev/null
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecStandbyTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.hdmicec.cts.playback;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import android.hdmicec.cts.BaseHdmiCecCtsTest;
+import android.hdmicec.cts.CecOperand;
+import android.hdmicec.cts.HdmiCecConstants;
+import android.hdmicec.cts.LogicalAddress;
+
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+
+import org.junit.runner.RunWith;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+
+import java.util.concurrent.TimeUnit;
+
+/** Tests that check Standby behaviour of playback devices */
+@RunWith(DeviceJUnit4ClassRunner.class)
+public final class HdmiCecStandbyTest extends BaseHdmiCecCtsTest {
+
+ @Rule
+ public RuleChain ruleChain =
+ RuleChain.outerRule(CecRules.requiresCec(this))
+ .around(CecRules.requiresLeanback(this))
+ .around(
+ CecRules.requiresDeviceType(
+ this, HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE))
+ .around(hdmiCecClient);
+
+ private void sendStandbyAndCheckNoStandbySent(LogicalAddress destAddress) throws Exception {
+ hdmiCecClient.broadcastActiveSource(LogicalAddress.TV);
+ TimeUnit.SECONDS.sleep(HdmiCecConstants.DEVICE_WAIT_TIME_SECONDS);
+ assertWithMessage("Device should not have been active source!")
+ .that(isDeviceActiveSource(getDevice()))
+ .isFalse();
+
+ try {
+ sendDeviceToSleep();
+ hdmiCecClient.checkOutputDoesNotContainMessage(destAddress, CecOperand.STANDBY);
+ } finally {
+ wakeUpDevice();
+ }
+ }
+
+ /**
+ * Tests that the DUT does not send a {@code <STANDBY>} to the TV when it is turned off, and is
+ * not the active source.
+ */
+ @Test
+ public void cectNoTvStandbyWhenNotActiveSource() throws Exception {
+ String prevMode = setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
+ sendStandbyAndCheckNoStandbySent(LogicalAddress.TV);
+ setPowerControlMode(prevMode);
+ }
+
+ /**
+ * Tests that the DUT does not broadcast a {@code <STANDBY>} when it is turned off, and is not
+ * the active source.
+ */
+ @Test
+ public void cectNoBroadcastStandbyWhenNotActiveSource() throws Exception {
+ String prevMode = setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_BROADCAST);
+ sendStandbyAndCheckNoStandbySent(LogicalAddress.BROADCAST);
+ setPowerControlMode(prevMode);
+ }
+}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
index fc9c543..963d5e4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
@@ -154,4 +154,19 @@
setSystemLocale(locale);
}
}
+
+ /**
+ * Test HF4-11-4 (CEC 2.0)
+ *
+ * <p>Tests that the DUT responds to {@code <Give Features>} with "Sink supports ARC Tx" bit not
+ * set.
+ */
+ @Test
+ public void cect_hf_4_11_4_SinkArcTxBitReset() throws Exception {
+ setCec20();
+ hdmiCecClient.sendCecMessage(LogicalAddress.TV, CecOperand.GIVE_FEATURES);
+ String message = hdmiCecClient.checkExpectedOutput(CecOperand.REPORT_FEATURES);
+ int params = CecMessage.getParams(message, 6, 8);
+ assertThat(params & HdmiCecConstants.FEATURES_SINK_SUPPORTS_ARC_TX_BIT).isEqualTo(0);
+ }
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
index 141cb63..7f666e4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecTvPowerToggleTest.java
@@ -46,8 +46,6 @@
private static final int OFF = 0x1;
private static final LogicalAddress PLAYBACK_DEVICE = LogicalAddress.PLAYBACK_1;
- private static final String POWER_CONTROL_MODE =
- "hdmi_control_send_standby_on_sleep";
@Rule
public RuleChain ruleChain =
@@ -62,15 +60,6 @@
super(HdmiCecConstants.CEC_DEVICE_TYPE_PLAYBACK_DEVICE);
}
- private String setPowerControlMode(String valToSet) throws Exception {
- ITestDevice device = getDevice();
- String val = device.executeShellCommand("settings get global " +
- POWER_CONTROL_MODE).trim();
- device.executeShellCommand("settings put global "
- + POWER_CONTROL_MODE + " " + valToSet);
- return val;
- }
-
/**
* Tests that KEYCODE_TV_POWER functions as a TV power toggle.
* Device is awake and not active source. TV is on.
@@ -80,7 +69,8 @@
ITestDevice device = getDevice();
// Make sure the device is not booting up/in standby
device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String previousPowerControlMode = setPowerControlMode("to_tv");
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
try {
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
@@ -116,7 +106,8 @@
ITestDevice device = getDevice();
// Make sure the device is not booting up/in standby
device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String previousPowerControlMode = setPowerControlMode("to_tv");
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
try {
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
@@ -151,7 +142,8 @@
ITestDevice device = getDevice();
// Make sure the device is not booting up/in standby
device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String previousPowerControlMode = setPowerControlMode("to_tv");
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
try {
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
@@ -184,7 +176,8 @@
ITestDevice device = getDevice();
// Make sure the device is not booting up/in standby
device.waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
- String previousPowerControlMode = setPowerControlMode("to_tv");
+ String previousPowerControlMode =
+ setPowerControlMode(HdmiCecConstants.POWER_CONTROL_MODE_TV);
try {
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 0");
device.executeShellCommand("cmd hdmi_control cec_setting set hdmi_cec_enabled 1");
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
index e15d634..ff2ff00 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRemoteControlPassThroughTest.java
@@ -40,12 +40,16 @@
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
+import java.util.concurrent.TimeUnit;
/** HDMI CEC test to check Remote Control Pass Through behaviour (Sections 11.1.13) */
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecRemoteControlPassThroughTest extends BaseHdmiCecCtsTest {
+ private static final int WAIT_TIME_MS = 300;
+
private HashMap<String, Integer> remoteControlKeys = new HashMap<String, Integer>();
+ private HashMap<String, Integer> remoteControlAudioKeys = new HashMap<String, Integer>();
@Rule
public RuleChain ruleChain =
@@ -80,6 +84,11 @@
*/
hdmiCecClient.broadcastActiveSource(
LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ try {
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ } catch (InterruptedException ex) {
+ // Do nothing
+ }
}
}
}
@@ -94,7 +103,8 @@
public void cect_11_1_13_1_RemoteControlMessagesToRecorder() throws Exception {
hdmiCecClient.broadcastActiveSource(
LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
- validateKeyeventToUserControlPress(LogicalAddress.RECORDER_1);
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ validateKeyeventToUserControlPress(LogicalAddress.RECORDER_1, remoteControlKeys);
}
/**
@@ -107,7 +117,8 @@
public void cect_11_1_13_2_RemoteControlMessagesToPlayback() throws Exception {
hdmiCecClient.broadcastActiveSource(
LogicalAddress.PLAYBACK_1, hdmiCecClient.getPhysicalAddress());
- validateKeyeventToUserControlPress(LogicalAddress.PLAYBACK_1);
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ validateKeyeventToUserControlPress(LogicalAddress.PLAYBACK_1, remoteControlKeys);
}
/**
@@ -120,7 +131,8 @@
public void cect_11_1_13_3_RemoteControlMessagesToTuner() throws Exception {
hdmiCecClient.broadcastActiveSource(
LogicalAddress.TUNER_1, hdmiCecClient.getPhysicalAddress());
- validateKeyeventToUserControlPress(LogicalAddress.TUNER_1);
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ validateKeyeventToUserControlPress(LogicalAddress.TUNER_1, remoteControlKeys);
}
/**
@@ -133,7 +145,8 @@
public void cect_11_1_13_4_RemoteControlMessagesToAudioSystem() throws Exception {
hdmiCecClient.broadcastActiveSource(
LogicalAddress.AUDIO_SYSTEM, hdmiCecClient.getPhysicalAddress());
- validateKeyeventToUserControlPress(LogicalAddress.AUDIO_SYSTEM);
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ validateKeyeventToUserControlPress(LogicalAddress.AUDIO_SYSTEM, remoteControlAudioKeys);
}
/**
@@ -151,19 +164,23 @@
}
private void mapRemoteControlKeys() {
- remoteControlKeys.put("DPAD_UP", HdmiCecConstants.CEC_CONTROL_UP);
- remoteControlKeys.put("DPAD_DOWN", HdmiCecConstants.CEC_CONTROL_DOWN);
- remoteControlKeys.put("DPAD_LEFT", HdmiCecConstants.CEC_CONTROL_LEFT);
- remoteControlKeys.put("DPAD_RIGHT", HdmiCecConstants.CEC_CONTROL_RIGHT);
+ remoteControlKeys.put("DPAD_UP", HdmiCecConstants.CEC_KEYCODE_UP);
+ remoteControlKeys.put("DPAD_DOWN", HdmiCecConstants.CEC_KEYCODE_DOWN);
+ remoteControlKeys.put("DPAD_LEFT", HdmiCecConstants.CEC_KEYCODE_LEFT);
+ remoteControlKeys.put("DPAD_RIGHT", HdmiCecConstants.CEC_KEYCODE_RIGHT);
+ remoteControlAudioKeys.put("VOLUME_UP", HdmiCecConstants.CEC_KEYCODE_VOLUME_UP);
+ remoteControlAudioKeys.put("VOLUME_DOWN", HdmiCecConstants.CEC_KEYCODE_VOLUME_DOWN);
+ remoteControlAudioKeys.put("VOLUME_MUTE", HdmiCecConstants.CEC_KEYCODE_MUTE);
}
- private void validateKeyeventToUserControlPress(LogicalAddress toDevice) throws Exception {
+ private void validateKeyeventToUserControlPress(LogicalAddress toDevice
+ , HashMap<String, Integer> keyMaps) throws Exception {
ITestDevice device = getDevice();
- for (String remoteKey : remoteControlKeys.keySet()) {
+ for (String remoteKey : keyMaps.keySet()) {
device.executeShellCommand("input keyevent KEYCODE_" + remoteKey);
String message =
hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_PRESSED);
- assertThat(CecMessage.getParams(message)).isEqualTo(remoteControlKeys.get(remoteKey));
+ assertThat(CecMessage.getParams(message)).isEqualTo(keyMaps.get(remoteKey));
hdmiCecClient.checkExpectedOutput(toDevice, CecOperand.USER_CONTROL_RELEASED);
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
index a588ba1..1775f5e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecRoutingControlTest.java
@@ -41,6 +41,8 @@
@RunWith(DeviceJUnit4ClassRunner.class)
public final class HdmiCecRoutingControlTest extends BaseHdmiCecCtsTest {
+ private static final int WAIT_TIME_MS = 300;
+
@Rule
public RuleChain ruleChain =
RuleChain.outerRule(CecRules.requiresCec(this))
@@ -73,6 +75,11 @@
*/
hdmiCecClient.broadcastActiveSource(
hdmiCecClient.getSelfDevice(), hdmiCecClient.getPhysicalAddress());
+ try {
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
+ } catch (InterruptedException ex) {
+ // Do nothing
+ }
}
}
}
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
index 586a7d4..54c296e 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecSystemAudioControlTest.java
@@ -59,6 +59,9 @@
*/
@Test
public void cect_11_1_15_1_DutSendsSystemAudioModeRequest() throws Exception {
+ // Ensure that system audio mode is off before testing 11.1.15-5.
+ setSystemAudioMode(false);
+
hdmiCecClient.broadcastReportPhysicalAddress(LogicalAddress.AUDIO_SYSTEM);
hdmiCecClient.broadcastReportPhysicalAddress(
LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
index 13c0381..4aba289 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/tv/HdmiCecTvOneTouchPlayTest.java
@@ -128,6 +128,7 @@
*/
hdmiCecClient.broadcastActiveSource(
LogicalAddress.RECORDER_1, hdmiCecClient.getPhysicalAddress());
+ TimeUnit.MILLISECONDS.sleep(WAIT_TIME_MS);
}
// Make the TV device the active source.
HdmiControlManagerUtility.setActiveSource(
diff --git a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
index 9472c93..352333a 100644
--- a/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
+++ b/hostsidetests/multidevices/wifi_aware/AndroidTest.xml
@@ -18,6 +18,12 @@
<option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
<device name="device1">
+ <!-- For coverage to work, the APK should not be uninstalled until after coverage is pulled.
+ So it's a lot easier to install APKs outside the python code.
+ -->
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="test-file-name" value="wifi_aware_snippet.apk" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
<option name="run-command" value="wm dismiss-keyguard" />
@@ -28,6 +34,9 @@
</target_preparer>
</device>
<device name="device2">
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="test-file-name" value="wifi_aware_snippet.apk" />
+ </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
<option name="run-command" value="input keyevent KEYCODE_WAKEUP" />
<option name="run-command" value="wm dismiss-keyguard" />
diff --git a/hostsidetests/multidevices/wifi_aware/wifi_aware_test.py b/hostsidetests/multidevices/wifi_aware/wifi_aware_test.py
index 1b323dd..d2ab7df 100644
--- a/hostsidetests/multidevices/wifi_aware/wifi_aware_test.py
+++ b/hostsidetests/multidevices/wifi_aware/wifi_aware_test.py
@@ -14,9 +14,6 @@
WIFI_AWARE_SNIPPET_PATH = 'wifi_aware_snippet.apk'
-# The snippet is packed with the test binary in the same folder
-WIFI_AWARE_SNIPPET_APK_PATH = os.path.dirname(sys.argv[0]) + '/' + WIFI_AWARE_SNIPPET_PATH
-
WIFI_AWARE_SNIPPET_PACKAGE = 'com.google.snippet'
TEST_MESSAGE = 'test message!'
@@ -32,7 +29,8 @@
android_device, min_number=2)
def setup_device(device):
- device.adb.install(WIFI_AWARE_SNIPPET_APK_PATH)
+ # Expect wifi_aware apk to be installed as it is configured to install
+ # with the module configuration AndroidTest.xml on both devices.
device.adb.shell([
'pm', 'grant', WIFI_AWARE_SNIPPET_PACKAGE,
'android.permission.ACCESS_FINE_LOCATION'
diff --git a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
index ef24a7a..ab43151 100644
--- a/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
+++ b/hostsidetests/statsdatom/apps/statsdapp/src/com/android/server/cts/device/statsdatom/AtomTests.java
@@ -29,6 +29,7 @@
import android.app.PendingIntent;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
+import android.app.usage.NetworkStatsManager;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
@@ -63,6 +64,7 @@
import android.os.Looper;
import android.os.PowerManager;
import android.os.Process;
+import android.os.RemoteException;
import android.os.SystemClock;
import android.os.VibrationEffect;
import android.os.Vibrator;
@@ -986,6 +988,23 @@
doGenerateNetworkTraffic(context, NetworkCapabilities.TRANSPORT_CELLULAR);
}
+ /**
+ * Force poll NetworkStatsService to get most updated network stats from lower layer.
+ */
+ @Test
+ public void testForcePollNetworkStats() throws Exception {
+ final Context context = InstrumentationRegistry.getContext();
+ final NetworkStatsManager nsm = context.getSystemService(NetworkStatsManager.class);
+ try {
+ nsm.setPollForce(true);
+ // This query is for triggering force poll NetworkStatsService.
+ nsm.querySummaryForUser(ConnectivityManager.TYPE_WIFI, null, Long.MIN_VALUE,
+ Long.MAX_VALUE);
+ } catch (RemoteException e) {
+ Log.e(TAG, "doPollNetworkStats failed with " + e);
+ }
+ }
+
// Constants which are locally used by doGenerateNetworkTraffic.
private static final int NETWORK_TIMEOUT_MILLIS = 15000;
private static final String HTTPS_HOST_URL =
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/net/BytesTransferredTest.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/net/BytesTransferredTest.java
index 089843a..a340700d4 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/net/BytesTransferredTest.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/net/BytesTransferredTest.java
@@ -65,20 +65,23 @@
mCtsBuild = buildInfo;
}
- // TODO: inline the contents of doTestUsageBytesTransferEnable
public void testDataUsageBytesTransfer() throws Throwable {
- final boolean oldSubtypeCombined = getNetworkStatsCombinedSubTypeEnabled();
+ doTestMobileBytesTransferThat(Atom.DATA_USAGE_BYTES_TRANSFER_FIELD_NUMBER, /*isUidAtom=*/
+ false, (atom) -> {
+ final AtomsProto.DataUsageBytesTransfer data =
+ atom.getDataUsageBytesTransfer();
+ final boolean ratTypeGreaterThanUnknown =
+ (data.getRatType() > NetworkTypeEnum.NETWORK_TYPE_UNKNOWN_VALUE);
- doTestDataUsageBytesTransferEnabled(true);
-
- // Remove old configs from disk and clear any pending statsd reports to clear history.
- ConfigUtils.removeConfig(getDevice());
- ReportUtils.clearReports(getDevice());
-
- doTestDataUsageBytesTransferEnabled(false);
-
- // Restore to original default value.
- setNetworkStatsCombinedSubTypeEnabled(oldSubtypeCombined);
+ if (ratTypeGreaterThanUnknown) {
+ // Assert that subscription info is valid.
+ assertSubscriptionInfo(data);
+ // DataUsageBytesTransferred atom does not report app uid.
+ return new TransferredBytes(data.getRxBytes(), data.getTxBytes(),
+ data.getRxPackets(), data.getTxPackets(), /*appUid=*/-1);
+ }
+ return null;
+ });
}
public void testMobileBytesTransfer() throws Throwable {
@@ -152,32 +155,6 @@
TransferredBytes accept(S s) throws T;
}
- private void doTestDataUsageBytesTransferEnabled(boolean enable) throws Throwable {
- // Set value to enable/disable combine subtype.
- setNetworkStatsCombinedSubTypeEnabled(enable);
-
- doTestMobileBytesTransferThat(Atom.DATA_USAGE_BYTES_TRANSFER_FIELD_NUMBER, /*isUidAtom=*/
- false, (atom) -> {
- final AtomsProto.DataUsageBytesTransfer data =
- atom.getDataUsageBytesTransfer();
- final boolean ratTypeEqualsToUnknown =
- (data.getRatType() == NetworkTypeEnum.NETWORK_TYPE_UNKNOWN_VALUE);
- final boolean ratTypeGreaterThanUnknown =
- (data.getRatType() > NetworkTypeEnum.NETWORK_TYPE_UNKNOWN_VALUE);
-
- if ((data.getState() == 1) // NetworkStats.SET_FOREGROUND
- && ((enable && ratTypeEqualsToUnknown)
- || (!enable && ratTypeGreaterThanUnknown))) {
- // Assert that subscription info is valid.
- assertSubscriptionInfo(data);
- // DataUsageBytesTransferred atom does not report app uid.
- return new TransferredBytes(data.getRxBytes(), data.getTxBytes(),
- data.getRxPackets(), data.getTxPackets(), /*appUid=*/-1);
- }
- return null;
- });
- }
-
private void doTestMobileBytesTransferThat(int atomId, boolean isUidAtom,
ThrowingPredicate<Atom, Exception> p)
throws Throwable {
@@ -197,10 +174,10 @@
"testGenerateMobileTraffic");
Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
// Force poll NetworkStatsService to get most updated network stats from lower layer.
- DeviceUtils.runActivity(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
- "PollNetworkStatsActivity",
- /*actionKey=*/null, /*actionValue=*/null);
+ DeviceUtils.runDeviceTests(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG, ".AtomTests",
+ "testForcePollNetworkStats");
Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
+
// Trigger atom pull.
AtomTestUtils.sendAppBreadcrumbReportedAtom(getDevice());
Thread.sleep(AtomTestUtils.WAIT_TIME_SHORT);
@@ -245,15 +222,4 @@
assertThat(data.getSimMnc()).matches("^\\d{2,3}$");
assertThat(data.getCarrierId()).isNotEqualTo(-1); // TelephonyManager#UNKNOWN_CARRIER_ID
}
-
- private boolean getNetworkStatsCombinedSubTypeEnabled() throws Exception {
- final String output = getDevice().executeShellCommand(
- "settings get global netstats_combine_subtype_enabled").trim();
- return output.equals("1");
- }
-
- private void setNetworkStatsCombinedSubTypeEnabled(boolean enable) throws Exception {
- getDevice().executeShellCommand("settings put global netstats_combine_subtype_enabled "
- + (enable ? "1" : "0"));
- }
}
diff --git a/libs/testserver/Android.bp b/libs/testserver/Android.bp
index 56a0921..295c286 100644
--- a/libs/testserver/Android.bp
+++ b/libs/testserver/Android.bp
@@ -14,12 +14,17 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-BSD
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "cts_libs_testserver_license", // BSD
+ "Android-Apache-2.0",
+ ],
+}
+
+license {
+ name: "cts_libs_testserver_license",
+ package_name: "Android Testserver CTS",
+ license_kinds: ["SPDX-license-identifier-BSD"],
+ license_text: ["LICENSE_BSD"],
}
java_library {
diff --git a/libs/testserver/LICENSE_BSD b/libs/testserver/LICENSE_BSD
new file mode 100644
index 0000000..063941f
--- /dev/null
+++ b/libs/testserver/LICENSE_BSD
@@ -0,0 +1,25 @@
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above
+copyright notice, this list of conditions and the following disclaimer
+in the documentation and/or other materials provided with the
+distribution.
+ * Neither the name of Google Inc. nor the names of its
+contributors may be used to endorse or promote products derived from
+this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/tests/camera/Android.bp b/tests/camera/Android.bp
index 28c0928..7558776 100644
--- a/tests/camera/Android.bp
+++ b/tests/camera/Android.bp
@@ -86,6 +86,7 @@
"android.test.runner.stubs",
"android.test.base.stubs",
],
+ per_testcase_directory: true,
}
genrule {
diff --git a/tests/filesystem/AndroidTest.xml b/tests/filesystem/AndroidTest.xml
index df140d6..3f0ddc0 100644
--- a/tests/filesystem/AndroidTest.xml
+++ b/tests/filesystem/AndroidTest.xml
@@ -26,8 +26,8 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.filesystem.cts" />
<option name="runtime-hint" value="14m48s" />
- <!-- test-timeout unit is ms, value = 60 min -->
- <option name="test-timeout" value="3600000" />
+ <!-- test-timeout unit is ms, value = 70 min -->
+ <option name="test-timeout" value="4200000" />
<!-- shell-timeout unit is ms, value = 180 min for AlmostFullTest -->
<option name="shell-timeout" value="10800000" />
<!-- disable isolated storage so tests can write report log -->
diff --git a/tests/net/Android.bp b/tests/net/Android.bp
new file mode 100644
index 0000000..2a4153a
--- /dev/null
+++ b/tests/net/Android.bp
@@ -0,0 +1,24 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+ name: "CtsNetTestsNonUpdatableLib",
+ srcs: ["src/**/*.java"],
+ static_libs: ["androidx.test.rules"],
+ platform_apis: true,
+}
diff --git a/tests/net/OWNERS b/tests/net/OWNERS
new file mode 100644
index 0000000..67e4fc9
--- /dev/null
+++ b/tests/net/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 31808
+set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
\ No newline at end of file
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
new file mode 100644
index 0000000..a6a02d5
--- /dev/null
+++ b/tests/net/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+ "imports": [
+ {
+ "path": "packages/modules/Connectivity"
+ }
+ ]
+}
diff --git a/tests/net/src/android/net/cts/LocalSocketTest.java b/tests/net/src/android/net/cts/LocalSocketTest.java
new file mode 100644
index 0000000..969f706
--- /dev/null
+++ b/tests/net/src/android/net/cts/LocalSocketTest.java
@@ -0,0 +1,471 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import android.net.Credentials;
+import android.net.LocalServerSocket;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
+import android.os.ParcelFileDescriptor;
+import android.system.Os;
+import android.system.OsConstants;
+
+import junit.framework.TestCase;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+
+public class LocalSocketTest extends TestCase {
+ private final static String ADDRESS_PREFIX = "com.android.net.LocalSocketTest";
+
+ public void testLocalConnections() throws IOException {
+ String address = ADDRESS_PREFIX + "_testLocalConnections";
+ // create client and server socket
+ LocalServerSocket localServerSocket = new LocalServerSocket(address);
+ LocalSocket clientSocket = new LocalSocket();
+
+ // establish connection between client and server
+ LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
+ assertFalse(clientSocket.isConnected());
+ clientSocket.connect(locSockAddr);
+ assertTrue(clientSocket.isConnected());
+
+ LocalSocket serverSocket = localServerSocket.accept();
+ assertTrue(serverSocket.isConnected());
+ assertTrue(serverSocket.isBound());
+ try {
+ serverSocket.bind(localServerSocket.getLocalSocketAddress());
+ fail("Cannot bind a LocalSocket from accept()");
+ } catch (IOException expected) {
+ }
+ try {
+ serverSocket.connect(locSockAddr);
+ fail("Cannot connect a LocalSocket from accept()");
+ } catch (IOException expected) {
+ }
+
+ Credentials credent = clientSocket.getPeerCredentials();
+ assertTrue(0 != credent.getPid());
+
+ // send data from client to server
+ OutputStream clientOutStream = clientSocket.getOutputStream();
+ clientOutStream.write(12);
+ InputStream serverInStream = serverSocket.getInputStream();
+ assertEquals(12, serverInStream.read());
+
+ //send data from server to client
+ OutputStream serverOutStream = serverSocket.getOutputStream();
+ serverOutStream.write(3);
+ InputStream clientInStream = clientSocket.getInputStream();
+ assertEquals(3, clientInStream.read());
+
+ // Test sending and receiving file descriptors
+ clientSocket.setFileDescriptorsForSend(new FileDescriptor[]{FileDescriptor.in});
+ clientOutStream.write(32);
+ assertEquals(32, serverInStream.read());
+
+ FileDescriptor[] out = serverSocket.getAncillaryFileDescriptors();
+ assertEquals(1, out.length);
+ FileDescriptor fd = clientSocket.getFileDescriptor();
+ assertTrue(fd.valid());
+
+ //shutdown input stream of client
+ clientSocket.shutdownInput();
+ assertEquals(-1, clientInStream.read());
+
+ //shutdown output stream of client
+ clientSocket.shutdownOutput();
+ try {
+ clientOutStream.write(10);
+ fail("testLocalSocket shouldn't come to here");
+ } catch (IOException e) {
+ // expected
+ }
+
+ //shutdown input stream of server
+ serverSocket.shutdownInput();
+ assertEquals(-1, serverInStream.read());
+
+ //shutdown output stream of server
+ serverSocket.shutdownOutput();
+ try {
+ serverOutStream.write(10);
+ fail("testLocalSocket shouldn't come to here");
+ } catch (IOException e) {
+ // expected
+ }
+
+ //close client socket
+ clientSocket.close();
+ try {
+ clientInStream.read();
+ fail("testLocalSocket shouldn't come to here");
+ } catch (IOException e) {
+ // expected
+ }
+
+ //close server socket
+ serverSocket.close();
+ try {
+ serverInStream.read();
+ fail("testLocalSocket shouldn't come to here");
+ } catch (IOException e) {
+ // expected
+ }
+ }
+
+ public void testAccessors() throws IOException {
+ String address = ADDRESS_PREFIX + "_testAccessors";
+ LocalSocket socket = new LocalSocket();
+ LocalSocketAddress addr = new LocalSocketAddress(address);
+
+ assertFalse(socket.isBound());
+ socket.bind(addr);
+ assertTrue(socket.isBound());
+ assertEquals(addr, socket.getLocalSocketAddress());
+
+ String str = socket.toString();
+ assertTrue(str.contains("impl:android.net.LocalSocketImpl"));
+
+ socket.setReceiveBufferSize(1999);
+ assertEquals(1999 << 1, socket.getReceiveBufferSize());
+
+ socket.setSendBufferSize(3998);
+ assertEquals(3998 << 1, socket.getSendBufferSize());
+
+ assertEquals(0, socket.getSoTimeout());
+ socket.setSoTimeout(1996);
+ assertTrue(socket.getSoTimeout() > 0);
+
+ try {
+ socket.getRemoteSocketAddress();
+ fail("testLocalSocketSecondary shouldn't come to here");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ try {
+ socket.isClosed();
+ fail("testLocalSocketSecondary shouldn't come to here");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ try {
+ socket.isInputShutdown();
+ fail("testLocalSocketSecondary shouldn't come to here");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ try {
+ socket.isOutputShutdown();
+ fail("testLocalSocketSecondary shouldn't come to here");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ try {
+ socket.connect(addr, 2005);
+ fail("testLocalSocketSecondary shouldn't come to here");
+ } catch (UnsupportedOperationException e) {
+ // expected
+ }
+
+ socket.close();
+ }
+
+ // http://b/31205169
+ public void testSetSoTimeout_readTimeout() throws Exception {
+ String address = ADDRESS_PREFIX + "_testSetSoTimeout_readTimeout";
+
+ try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+ final LocalSocket clientSocket = socketPair.clientSocket;
+
+ // Set the timeout in millis.
+ int timeoutMillis = 1000;
+ clientSocket.setSoTimeout(timeoutMillis);
+
+ // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
+ Callable<Result> reader = () -> {
+ try {
+ clientSocket.getInputStream().read();
+ return Result.noException("Did not block");
+ } catch (IOException e) {
+ return Result.exception(e);
+ }
+ };
+ // Allow the configured timeout, plus some slop.
+ int allowedTime = timeoutMillis + 2000;
+ Result result = runInSeparateThread(allowedTime, reader);
+
+ // Check the message was a timeout, it's all we have to go on.
+ String expectedMessage = Os.strerror(OsConstants.EAGAIN);
+ result.assertThrewIOException(expectedMessage);
+ }
+ }
+
+ // http://b/31205169
+ public void testSetSoTimeout_writeTimeout() throws Exception {
+ String address = ADDRESS_PREFIX + "_testSetSoTimeout_writeTimeout";
+
+ try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+ final LocalSocket clientSocket = socketPair.clientSocket;
+
+ // Set the timeout in millis.
+ int timeoutMillis = 1000;
+ clientSocket.setSoTimeout(timeoutMillis);
+
+ // Set a small buffer size so we know we can flood it.
+ clientSocket.setSendBufferSize(100);
+ final int bufferSize = clientSocket.getSendBufferSize();
+
+ // Avoid blocking the test run if timeout doesn't happen by using a separate thread.
+ Callable<Result> writer = () -> {
+ try {
+ byte[] toWrite = new byte[bufferSize * 2];
+ clientSocket.getOutputStream().write(toWrite);
+ return Result.noException("Did not block");
+ } catch (IOException e) {
+ return Result.exception(e);
+ }
+ };
+ // Allow the configured timeout, plus some slop.
+ int allowedTime = timeoutMillis + 2000;
+
+ Result result = runInSeparateThread(allowedTime, writer);
+
+ // Check the message was a timeout, it's all we have to go on.
+ String expectedMessage = Os.strerror(OsConstants.EAGAIN);
+ result.assertThrewIOException(expectedMessage);
+ }
+ }
+
+ public void testAvailable() throws Exception {
+ String address = ADDRESS_PREFIX + "_testAvailable";
+
+ try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+ LocalSocket clientSocket = socketPair.clientSocket;
+ LocalSocket serverSocket = socketPair.serverSocket.accept();
+
+ OutputStream clientOutputStream = clientSocket.getOutputStream();
+ InputStream serverInputStream = serverSocket.getInputStream();
+ assertEquals(0, serverInputStream.available());
+
+ byte[] buffer = new byte[50];
+ clientOutputStream.write(buffer);
+ assertEquals(50, serverInputStream.available());
+
+ InputStream clientInputStream = clientSocket.getInputStream();
+ OutputStream serverOutputStream = serverSocket.getOutputStream();
+ assertEquals(0, clientInputStream.available());
+ serverOutputStream.write(buffer);
+ assertEquals(50, serverInputStream.available());
+
+ serverSocket.close();
+ }
+ }
+
+ // http://b/34095140
+ public void testLocalSocketCreatedFromFileDescriptor() throws Exception {
+ String address = ADDRESS_PREFIX + "_testLocalSocketCreatedFromFileDescriptor";
+
+ // Establish connection between a local client and server to get a valid client socket file
+ // descriptor.
+ try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+ // Extract the client FileDescriptor we can use.
+ FileDescriptor fileDescriptor = socketPair.clientSocket.getFileDescriptor();
+ assertTrue(fileDescriptor.valid());
+
+ // Create the LocalSocket we want to test.
+ LocalSocket clientSocketCreatedFromFileDescriptor =
+ LocalSocket.createConnectedLocalSocket(fileDescriptor);
+ assertTrue(clientSocketCreatedFromFileDescriptor.isConnected());
+ assertTrue(clientSocketCreatedFromFileDescriptor.isBound());
+
+ // Test the LocalSocket can be used for communication.
+ LocalSocket serverSocket = socketPair.serverSocket.accept();
+ OutputStream clientOutputStream =
+ clientSocketCreatedFromFileDescriptor.getOutputStream();
+ InputStream serverInputStream = serverSocket.getInputStream();
+
+ clientOutputStream.write(12);
+ assertEquals(12, serverInputStream.read());
+
+ // Closing clientSocketCreatedFromFileDescriptor does not close the file descriptor.
+ clientSocketCreatedFromFileDescriptor.close();
+ assertTrue(fileDescriptor.valid());
+
+ // .. while closing the LocalSocket that owned the file descriptor does.
+ socketPair.clientSocket.close();
+ assertFalse(fileDescriptor.valid());
+ }
+ }
+
+ public void testFlush() throws Exception {
+ String address = ADDRESS_PREFIX + "_testFlush";
+
+ try (LocalSocketPair socketPair = LocalSocketPair.createConnectedSocketPair(address)) {
+ LocalSocket clientSocket = socketPair.clientSocket;
+ LocalSocket serverSocket = socketPair.serverSocket.accept();
+
+ OutputStream clientOutputStream = clientSocket.getOutputStream();
+ InputStream serverInputStream = serverSocket.getInputStream();
+ testFlushWorks(clientOutputStream, serverInputStream);
+
+ OutputStream serverOutputStream = serverSocket.getOutputStream();
+ InputStream clientInputStream = clientSocket.getInputStream();
+ testFlushWorks(serverOutputStream, clientInputStream);
+
+ serverSocket.close();
+ }
+ }
+
+ private void testFlushWorks(OutputStream outputStream, InputStream inputStream)
+ throws Exception {
+ final int bytesToTransfer = 50;
+ StreamReader inputStreamReader = new StreamReader(inputStream, bytesToTransfer);
+
+ byte[] buffer = new byte[bytesToTransfer];
+ outputStream.write(buffer);
+ assertEquals(bytesToTransfer, inputStream.available());
+
+ // Start consuming the data.
+ inputStreamReader.start();
+
+ // This doesn't actually flush any buffers, it just polls until the reader has read all the
+ // bytes.
+ outputStream.flush();
+
+ inputStreamReader.waitForCompletion(5000);
+ inputStreamReader.assertBytesRead(bytesToTransfer);
+ assertEquals(0, inputStream.available());
+ }
+
+ private static class StreamReader extends Thread {
+ private final InputStream is;
+ private final int expectedByteCount;
+ private final CountDownLatch completeLatch = new CountDownLatch(1);
+
+ private volatile Exception exception;
+ private int bytesRead;
+
+ private StreamReader(InputStream is, int expectedByteCount) {
+ this.is = is;
+ this.expectedByteCount = expectedByteCount;
+ }
+
+ @Override
+ public void run() {
+ try {
+ byte[] buffer = new byte[10];
+ int readCount;
+ while ((readCount = is.read(buffer)) >= 0) {
+ bytesRead += readCount;
+ if (bytesRead >= expectedByteCount) {
+ break;
+ }
+ }
+ } catch (IOException e) {
+ exception = e;
+ } finally {
+ completeLatch.countDown();
+ }
+ }
+
+ public void waitForCompletion(long waitMillis) throws Exception {
+ if (!completeLatch.await(waitMillis, TimeUnit.MILLISECONDS)) {
+ fail("Timeout waiting for completion");
+ }
+ if (exception != null) {
+ throw new Exception("Read failed", exception);
+ }
+ }
+
+ public void assertBytesRead(int expected) {
+ assertEquals(expected, bytesRead);
+ }
+ }
+
+ private static class Result {
+ private final String type;
+ private final Exception e;
+
+ private Result(String type, Exception e) {
+ this.type = type;
+ this.e = e;
+ }
+
+ static Result noException(String description) {
+ return new Result(description, null);
+ }
+
+ static Result exception(Exception e) {
+ return new Result(e.getClass().getName(), e);
+ }
+
+ void assertThrewIOException(String expectedMessage) {
+ assertEquals("Unexpected result type", IOException.class.getName(), type);
+ assertEquals("Unexpected exception message", expectedMessage, e.getMessage());
+ }
+ }
+
+ private static Result runInSeparateThread(int allowedTime, final Callable<Result> callable)
+ throws Exception {
+ ExecutorService service = Executors.newSingleThreadScheduledExecutor();
+ Future<Result> future = service.submit(callable);
+ Result result = future.get(allowedTime, TimeUnit.MILLISECONDS);
+ if (!future.isDone()) {
+ fail("Worker thread appears blocked");
+ }
+ return result;
+ }
+
+ private static class LocalSocketPair implements AutoCloseable {
+ static LocalSocketPair createConnectedSocketPair(String address) throws Exception {
+ LocalServerSocket localServerSocket = new LocalServerSocket(address);
+ final LocalSocket clientSocket = new LocalSocket();
+
+ // Establish connection between client and server
+ LocalSocketAddress locSockAddr = new LocalSocketAddress(address);
+ clientSocket.connect(locSockAddr);
+ assertTrue(clientSocket.isConnected());
+ return new LocalSocketPair(localServerSocket, clientSocket);
+ }
+
+ final LocalServerSocket serverSocket;
+ final LocalSocket clientSocket;
+
+ LocalSocketPair(LocalServerSocket serverSocket, LocalSocket clientSocket) {
+ this.serverSocket = serverSocket;
+ this.clientSocket = clientSocket;
+ }
+
+ public void close() throws Exception {
+ serverSocket.close();
+ clientSocket.close();
+ }
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
index 43183fe..adfe356 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicAdapterTest.java
@@ -25,6 +25,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.os.SystemProperties;
import android.test.AndroidTestCase;
import android.util.Log;
@@ -245,6 +247,49 @@
assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioSupported());
}
+ public void test_isLeAudioBroadcastSourceSupported() throws IOException {
+ if (!mHasBluetooth) {
+ // Skip the test if bluetooth is not present.
+ return;
+ }
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioBroadcastSourceSupported());
+ }
+
+ public void test_isLeAudioBroadcastAssistantSupported() throws IOException {
+ if (!mHasBluetooth) {
+ // Skip the test if bluetooth is not present.
+ return;
+ }
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ assertNotSame(BluetoothStatusCodes.ERROR_UNKNOWN, adapter.isLeAudioBroadcastAssistantSupported());
+ }
+
+ public void test_getMaxConnectedAudioDevices() {
+ if (!mHasBluetooth) {
+ // Skip the test if bluetooth is not present.
+ return;
+ }
+
+ BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter();
+ assertTrue(BTAdapterUtils.enableAdapter(adapter, mContext));
+ int maxConnectedAudioDevicesConfig = 0;
+ try {
+ Resources bluetoothRes = mContext.getPackageManager()
+ .getResourcesForApplication("com.android.bluetooth");
+ maxConnectedAudioDevicesConfig = bluetoothRes.getInteger(
+ bluetoothRes.getIdentifier("config_bluetooth_max_connected_audio_devices",
+ "integer", "com.android.bluetooth"));
+ } catch (PackageManager.NameNotFoundException e) {
+ e.printStackTrace();
+ }
+
+ maxConnectedAudioDevicesConfig =
+ SystemProperties.getInt("persist.bluetooth.maxconnectedaudiodevices",
+ maxConnectedAudioDevicesConfig);
+ assertEquals(maxConnectedAudioDevicesConfig, adapter.getMaxConnectedAudioDevices());
+ }
+
public void test_listenUsingRfcommWithServiceRecord() throws IOException {
if (!mHasBluetooth) {
// Skip the test if bluetooth is not present.
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceAppSdpSettingsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceAppSdpSettingsTest.java
new file mode 100644
index 0000000..97599e0
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceAppSdpSettingsTest.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.cts;
+
+import android.bluetooth.BluetoothHidDeviceAppSdpSettings;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+/**
+ * Unit test cases for {@link BluetoothHidDeviceAppSdpSettings}.
+ */
+public class BluetoothHidDeviceAppSdpSettingsTest extends AndroidTestCase {
+ @SmallTest
+ public void testGetters() {
+ String name = "test-name";
+ String description = "test-description";
+ String provider = "test-provider";
+ byte subclass = 1;
+ byte[] descriptors = new byte[] {10};
+ BluetoothHidDeviceAppSdpSettings settings = new BluetoothHidDeviceAppSdpSettings(
+ name, description, provider, subclass, descriptors);
+ assertEquals(name, settings.getName());
+ assertEquals(description, settings.getDescription());
+ assertEquals(provider, settings.getProvider());
+ assertEquals(subclass, settings.getSubclass());
+ assertEquals(descriptors.length, settings.getDescriptors().length);
+ assertEquals(descriptors[0], settings.getDescriptors()[0]);
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceCallbackTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceCallbackTest.java
new file mode 100644
index 0000000..bcbe8fb
--- /dev/null
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceCallbackTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.bluetooth.cts;
+
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHidDevice;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class BluetoothHidDeviceCallbackTest {
+ private BluetoothHidDevice.Callback mHidDeviceCallback = new BluetoothHidDevice.Callback() {
+ @Override
+ public void onGetReport(BluetoothDevice device, byte type, byte id, int bufferSize) {
+ super.onGetReport(device, type, id, bufferSize);
+ }
+
+ @Override
+ public void onSetReport(BluetoothDevice device, byte type, byte id, byte[] data) {
+ super.onSetReport(device, type, id, data);
+ }
+
+ @Override
+ public void onSetProtocol(BluetoothDevice device, byte protocol) {
+ super.onSetProtocol(device, protocol);
+ }
+
+ @Override
+ public void onInterruptData(BluetoothDevice device, byte reportId, byte[] data) {
+ super.onInterruptData(device, reportId, data);
+ }
+
+ @Override
+ public void onVirtualCableUnplug(BluetoothDevice device) {
+ super.onVirtualCableUnplug(device);
+ }
+ };
+
+ @Test
+ public void testHidDeviceCallback() {
+ // TODO: Provide a way to simulate BluetoothHidHost for better testing.
+ // We may need to have a new BluetoothAdapter.getProfileProxy method with a new test profile
+ // like HID_DEVICE_TEST which also takes a mock hid host instance.
+ mHidDeviceCallback.onGetReport(null, (byte) 0, (byte) 0, 0);
+ mHidDeviceCallback.onSetReport(null, (byte) 0, (byte) 0, null);
+ mHidDeviceCallback.onSetProtocol(null, (byte) 0);
+ mHidDeviceCallback.onInterruptData(null, (byte) 0, null);
+ mHidDeviceCallback.onVirtualCableUnplug(null);
+ // FYI, onAppStatusChanged and onConnectionStateChanged are covered by CtsVerifier.
+ }
+}
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
index 24bcafb..214645f 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
@@ -140,6 +140,21 @@
mBluetoothLeAudio.getConnectionState(testDevice));
}
+ public void testGetAudioLocation() {
+ if (!(mHasBluetooth && mIsLeAudioSupported)) return;
+
+ assertTrue(waitForProfileConnect());
+ assertNotNull(mBluetoothLeAudio);
+
+ BluetoothDevice testDevice = mAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
+
+ assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
+
+ // Verify returns false if bluetooth is not enabled
+ assertEquals(BluetoothLeAudio.AUDIO_LOCATION_INVALID,
+ mBluetoothLeAudio.getAudioLocation(testDevice));
+ }
+
private boolean waitForProfileConnect() {
mProfileConnectedlock.lock();
try {
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
index ce9746b..209b912 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/InputTestCase.java
@@ -82,6 +82,7 @@
@Before
public void setUp() throws Exception {
mActivityRule.getActivity().clearUnhandleKeyCode();
+ mActivityRule.getActivity().setInputCallback(mInputListener);
mDecorView = mActivityRule.getActivity().getWindow().getDecorView();
mParser = new InputJsonParser(mInstrumentation.getTargetContext());
mVid = mParser.readVendorId(mRegisterResourceId);
@@ -228,7 +229,6 @@
}
protected void verifyEvents(List<InputEvent> events) {
- mActivityRule.getActivity().setInputCallback(mInputListener);
// Make sure we received the expected input events
if (events.size() == 0) {
// If no event is expected we need to wait for event until timeout and fail on
diff --git a/tests/tests/media/Android.bp b/tests/tests/media/Android.bp
index 255ac6a..f991089 100644
--- a/tests/tests/media/Android.bp
+++ b/tests/tests/media/Android.bp
@@ -14,13 +14,16 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license",
+ ],
+}
+
+license {
+ name: "cts_tests_tests_media_license",
+ license_kinds: ["SPDX-license-identifier-CC-BY-3.0"],
+ license_text: ["LICENSE_CC_BY"],
}
java_library {
diff --git a/tests/tests/media/AndroidManifest.xml b/tests/tests/media/AndroidManifest.xml
index ad7bc25..cd495f9 100644
--- a/tests/tests/media/AndroidManifest.xml
+++ b/tests/tests/media/AndroidManifest.xml
@@ -109,13 +109,6 @@
</activity>
<activity android:name="android.media.cts.MockActivity"/>
<activity android:name="android.media.cts.MediaRouter2TestActivity"/>
- <service android:name="android.media.cts.RemoteVirtualDisplayService"
- android:process=":remoteService"
- android:exported="true">
- <intent-filter>
- <action android:name="android.intent.action.MAIN"/>
- </intent-filter>
- </service>
<service android:name="android.media.cts.StubMediaBrowserService"
android:exported="true">
<intent-filter>
diff --git a/tests/tests/media/DynamicConfig.xml b/tests/tests/media/DynamicConfig.xml
index 942ab80..62ba6b7 100644
--- a/tests/tests/media/DynamicConfig.xml
+++ b/tests/tests/media/DynamicConfig.xml
@@ -14,18 +14,6 @@
-->
<dynamicConfig>
- <entry key="media_codec_capabilities_test_avc_baseline12">
- <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=160&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD.702DE9BA7AF96785FD6930AD2DD693A0486C880E&key=ik0</value>
- </entry>
- <entry key="media_codec_capabilities_test_avc_baseline30">
- <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=18&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA.7A83031734CB1EDCE06766B6228842F954927960&key=ik0</value>
- </entry>
- <entry key="media_codec_capabilities_test_avc_high31">
- <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=22&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=179525311196616BD8E1381759B0E5F81A9E91B5.C4A50E44059FEBCC6BBC78E3B3A4E0E0065777&key=ik0</value>
- </entry>
- <entry key="media_codec_capabilities_test_avc_high40">
- <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=137&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=B0976085596DD42DEA3F08307F76587241CB132B.043B719C039E8B92F45391ADC0BE3665E2332930&key=ik0</value>
- </entry>
<entry key="streaming_media_player_test_http_h263_amr_video1">
<value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=13&source=youtube&ip=0.0.0.0&ipbits=0&expire=19000000000&sparams=ip,ipbits,expire,id,itag,source&signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE.443B81C1E8E6D64E4E1555F568BA46C206507D78&key=ik0&user=android-device-test</value>
</entry>
diff --git a/tests/tests/media/LICENSE_CC_BY b/tests/tests/media/LICENSE_CC_BY
new file mode 100644
index 0000000..e3feb12
--- /dev/null
+++ b/tests/tests/media/LICENSE_CC_BY
@@ -0,0 +1,348 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta name="generator" content="HTML Tidy for Linux/x86 (vers 1 September 2005), see www.w3.org" />
+<title>Creative Commons Legal Code</title>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3.css" media="screen" />
+<link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3-print.css" media="print" />
+<!--[if lt IE 7]><link rel="stylesheet" type="text/css" href="https://creativecommons.org/includes/deed3-ie.css" media="screen" /><![endif]-->
+<script type="text/javascript" src="https://creativecommons.org/includes/errata.js">
+</script>
+</head>
+<body>
+<p align="center" id="header"><a href="https://creativecommons.org/">Creative Commons</a></p>
+<div id="deed" class="green">
+<div id="deed-head">
+<div id="cc-logo">
+<img src="https://creativecommons.org/images/deed/cc-logo.jpg" alt="" />
+</div>
+<h1><span>Creative Commons Legal Code</span></h1>
+<div id="deed-license">
+<h2>Attribution 3.0 United States</h2>
+</div>
+</div>
+<div id="deed-main">
+<div id="deed-main-content">
+<img src="https://creativecommons.org/images/international/us.png" alt="" />
+<blockquote>
+CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES
+NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE
+DOES NOT CREATE AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE
+COMMONS PROVIDES THIS INFORMATION ON AN "AS-IS" BASIS.
+CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE
+INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR DAMAGES
+RESULTING FROM ITS USE.
+</blockquote>
+<h3><em>License</em></h3>
+<p>THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS
+OF THIS CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR
+"LICENSE"). THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER
+APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS
+AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS
+PROHIBITED.</p>
+<p>BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU
+ACCEPT AND AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE.
+TO THE EXTENT THIS LICENSE MAY BE CONSIDERED TO BE A
+CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED HERE
+IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND
+CONDITIONS.</p>
+<p><strong>1. Definitions</strong></p>
+<ol type="a">
+<li><strong>"Collective Work"</strong> means a work, such
+as a periodical issue, anthology or encyclopedia, in
+which the Work in its entirety in unmodified form, along
+with one or more other contributions, constituting
+separate and independent works in themselves, are
+assembled into a collective whole. A work that
+constitutes a Collective Work will not be considered a
+Derivative Work (as defined below) for the purposes of
+this License.</li>
+<li><strong>"Derivative Work"</strong> means a work based
+upon the Work or upon the Work and other pre-existing
+works, such as a translation, musical arrangement,
+dramatization, fictionalization, motion picture version,
+sound recording, art reproduction, abridgment,
+condensation, or any other form in which the Work may be
+recast, transformed, or adapted, except that a work that
+constitutes a Collective Work will not be considered a
+Derivative Work for the purpose of this License. For the
+avoidance of doubt, where the Work is a musical
+composition or sound recording, the synchronization of
+the Work in timed-relation with a moving image
+("synching") will be considered a Derivative Work for the
+purpose of this License.</li>
+<li><strong>"Licensor"</strong> means the individual,
+individuals, entity or entities that offers the Work
+under the terms of this License.</li>
+<li><strong>"Original Author"</strong> means the
+individual, individuals, entity or entities who created
+the Work.</li>
+<li><strong>"Work"</strong> means the copyrightable work
+of authorship offered under the terms of this
+License.</li>
+<li><strong>"You"</strong> means an individual or entity
+exercising rights under this License who has not
+previously violated the terms of this License with
+respect to the Work, or who has received express
+permission from the Licensor to exercise rights under
+this License despite a previous violation.</li>
+</ol>
+<p><strong>2. Fair Use Rights.</strong> Nothing in this
+license is intended to reduce, limit, or restrict any
+rights arising from fair use, first sale or other
+limitations on the exclusive rights of the copyright owner
+under copyright law or other applicable laws.</p>
+<p><strong>3. License Grant.</strong> Subject to the terms
+and conditions of this License, Licensor hereby grants You
+a worldwide, royalty-free, non-exclusive, perpetual (for
+the duration of the applicable copyright) license to
+exercise the rights in the Work as stated below:</p>
+<ol type="a">
+<li>to reproduce the Work, to incorporate the Work into
+one or more Collective Works, and to reproduce the Work
+as incorporated in the Collective Works;</li>
+<li>to create and reproduce Derivative Works provided
+that any such Derivative Work, including any translation
+in any medium, takes reasonable steps to clearly label,
+demarcate or otherwise identify that changes were made to
+the original Work. For example, a translation could be
+marked "The original work was translated from English to
+Spanish," or a modification could indicate "The original
+work has been modified.";;</li>
+<li>to distribute copies or phonorecords of, display
+publicly, perform publicly, and perform publicly by means
+of a digital audio transmission the Work including as
+incorporated in Collective Works;</li>
+<li>to distribute copies or phonorecords of, display
+publicly, perform publicly, and perform publicly by means
+of a digital audio transmission Derivative Works.</li>
+<li>
+<p>For the avoidance of doubt, where the Work is a
+musical composition:</p>
+<ol type="i">
+<li><strong>Performance Royalties Under Blanket
+Licenses</strong>. Licensor waives the exclusive
+right to collect, whether individually or, in the
+event that Licensor is a member of a performance
+rights society (e.g. ASCAP, BMI, SESAC), via that
+society, royalties for the public performance or
+public digital performance (e.g. webcast) of the
+Work.</li>
+<li><strong>Mechanical Rights and Statutory
+Royalties</strong>. Licensor waives the exclusive
+right to collect, whether individually or via a music
+rights agency or designated agent (e.g. Harry Fox
+Agency), royalties for any phonorecord You create
+from the Work ("cover version") and distribute,
+subject to the compulsory license created by 17 USC
+Section 115 of the US Copyright Act (or the
+equivalent in other jurisdictions).</li>
+</ol>
+</li>
+<li><strong>Webcasting Rights and Statutory
+Royalties</strong>. For the avoidance of doubt, where the
+Work is a sound recording, Licensor waives the exclusive
+right to collect, whether individually or via a
+performance-rights society (e.g. SoundExchange),
+royalties for the public digital performance (e.g.
+webcast) of the Work, subject to the compulsory license
+created by 17 USC Section 114 of the US Copyright Act (or
+the equivalent in other jurisdictions).</li>
+</ol>
+<p>The above rights may be exercised in all media and
+formats whether now known or hereafter devised. The above
+rights include the right to make such modifications as are
+technically necessary to exercise the rights in other media
+and formats. All rights not expressly granted by Licensor
+are hereby reserved.</p>
+<p><strong>4. Restrictions.</strong> The license granted in
+Section 3 above is expressly made subject to and limited by
+the following restrictions:</p>
+<ol type="a">
+<li>You may distribute, publicly display, publicly
+perform, or publicly digitally perform the Work only
+under the terms of this License, and You must include a
+copy of, or the Uniform Resource Identifier for, this
+License with every copy or phonorecord of the Work You
+distribute, publicly display, publicly perform, or
+publicly digitally perform. You may not offer or impose
+any terms on the Work that restrict the terms of this
+License or the ability of a recipient of the Work to
+exercise the rights granted to that recipient under the
+terms of the License. You may not sublicense the Work.
+You must keep intact all notices that refer to this
+License and to the disclaimer of warranties. When You
+distribute, publicly display, publicly perform, or
+publicly digitally perform the Work, You may not impose
+any technological measures on the Work that restrict the
+ability of a recipient of the Work from You to exercise
+the rights granted to that recipient under the terms of
+the License. This Section 4(a) applies to the Work as
+incorporated in a Collective Work, but this does not
+require the Collective Work apart from the Work itself to
+be made subject to the terms of this License. If You
+create a Collective Work, upon notice from any Licensor
+You must, to the extent practicable, remove from the
+Collective Work any credit as required by Section 4(b),
+as requested. If You create a Derivative Work, upon
+notice from any Licensor You must, to the extent
+practicable, remove from the Derivative Work any credit
+as required by Section 4(b), as requested.</li>
+<li>If You distribute, publicly display, publicly
+perform, or publicly digitally perform the Work (as
+defined in Section 1 above) or any Derivative Works (as
+defined in Section 1 above) or Collective Works (as
+defined in Section 1 above), You must, unless a request
+has been made pursuant to Section 4(a), keep intact all
+copyright notices for the Work and provide, reasonable to
+the medium or means You are utilizing: (i) the name of
+the Original Author (or pseudonym, if applicable) if
+supplied, and/or (ii) if the Original Author and/or
+Licensor designate another party or parties (e.g. a
+sponsor institute, publishing entity, journal) for
+attribution ("Attribution Parties") in Licensor's
+copyright notice, terms of service or by other reasonable
+means, the name of such party or parties; the title of
+the Work if supplied; to the extent reasonably
+practicable, the Uniform Resource Identifier, if any,
+that Licensor specifies to be associated with the Work,
+unless such URI does not refer to the copyright notice or
+licensing information for the Work; and, consistent with
+Section 3(b) in the case of a Derivative Work, a credit
+identifying the use of the Work in the Derivative Work
+(e.g., "French translation of the Work by Original
+Author," or "Screenplay based on original Work by
+Original Author"). The credit required by this Section
+4(b) may be implemented in any reasonable manner;
+provided, however, that in the case of a Derivative Work
+or Collective Work, at a minimum such credit will appear,
+if a credit for all contributing authors of the
+Derivative Work or Collective Work appears, then as part
+of these credits and in a manner at least as prominent as
+the credits for the other contributing authors. For the
+avoidance of doubt, You may only use the credit required
+by this Section for the purpose of attribution in the
+manner set out above and, by exercising Your rights under
+this License, You may not implicitly or explicitly assert
+or imply any connection with, sponsorship or endorsement
+by the Original Author, Licensor and/or Attribution
+Parties, as appropriate, of You or Your use of the Work,
+without the separate, express prior written permission of
+the Original Author, Licensor and/or Attribution
+Parties.</li>
+</ol>
+<p><strong>5. Representations, Warranties and
+Disclaimer</strong></p>
+<p>UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN
+WRITING, LICENSOR OFFERS THE WORK AS-IS AND ONLY TO THE
+EXTENT OF ANY RIGHTS HELD IN THE LICENSED WORK BY THE
+LICENSOR. THE LICENSOR MAKES NO REPRESENTATIONS OR
+WARRANTIES OF ANY KIND CONCERNING THE WORK, EXPRESS,
+IMPLIED, STATUTORY OR OTHERWISE, INCLUDING, WITHOUT
+LIMITATION, WARRANTIES OF TITLE, MARKETABILITY,
+MERCHANTIBILITY, FITNESS FOR A PARTICULAR PURPOSE,
+NONINFRINGEMENT, OR THE ABSENCE OF LATENT OR OTHER DEFECTS,
+ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, WHETHER OR
+NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE
+EXCLUSION OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT
+APPLY TO YOU.</p>
+<p><strong>6. Limitation on Liability.</strong> EXCEPT TO
+THE EXTENT REQUIRED BY APPLICABLE LAW, IN NO EVENT WILL
+LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR ANY
+SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY
+DAMAGES ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK,
+EVEN IF LICENSOR HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.</p>
+<p><strong>7. Termination</strong></p>
+<ol type="a">
+<li>This License and the rights granted hereunder will
+terminate automatically upon any breach by You of the
+terms of this License. Individuals or entities who have
+received Derivative Works (as defined in Section 1 above)
+or Collective Works (as defined in Section 1 above) from
+You under this License, however, will not have their
+licenses terminated provided such individuals or entities
+remain in full compliance with those licenses. Sections
+1, 2, 5, 6, 7, and 8 will survive any termination of this
+License.</li>
+<li>Subject to the above terms and conditions, the
+license granted here is perpetual (for the duration of
+the applicable copyright in the Work). Notwithstanding
+the above, Licensor reserves the right to release the
+Work under different license terms or to stop
+distributing the Work at any time; provided, however that
+any such election will not serve to withdraw this License
+(or any other license that has been, or is required to
+be, granted under the terms of this License), and this
+License will continue in full force and effect unless
+terminated as stated above.</li>
+</ol>
+ <p><strong>8. Miscellaneous</strong></p>
+<ol type="a">
+<li>Each time You distribute or publicly digitally
+perform the Work (as defined in Section 1 above) or a
+Collective Work (as defined in Section 1 above), the
+Licensor offers to the recipient a license to the Work on
+the same terms and conditions as the license granted to
+You under this License.</li>
+<li>Each time You distribute or publicly digitally
+perform a Derivative Work, Licensor offers to the
+recipient a license to the original Work on the same
+terms and conditions as the license granted to You under
+this License.</li>
+<li>If any provision of this License is invalid or
+unenforceable under applicable law, it shall not affect
+the validity or enforceability of the remainder of the
+terms of this License, and without further action by the
+parties to this agreement, such provision shall be
+reformed to the minimum extent necessary to make such
+provision valid and enforceable.</li>
+<li>No term or provision of this License shall be deemed
+waived and no breach consented to unless such waiver or
+consent shall be in writing and signed by the party to be
+charged with such waiver or consent.</li>
+<li>This License constitutes the entire agreement between
+the parties with respect to the Work licensed here. There
+are no understandings, agreements or representations with
+respect to the Work not specified here. Licensor shall
+not be bound by any additional provisions that may appear
+in any communication from You. This License may not be
+modified without the mutual written agreement of the
+Licensor and You.</li>
+</ol>
+
+<blockquote>
+<h3>Creative Commons Notice</h3>
+<p>Creative Commons is not a party to this License, and
+makes no warranty whatsoever in connection with the Work.
+Creative Commons will not be liable to You or any party
+on any legal theory for any damages whatsoever, including
+without limitation any general, special, incidental or
+consequential damages arising in connection to this
+license. Notwithstanding the foregoing two (2) sentences,
+if Creative Commons has expressly identified itself as
+the Licensor hereunder, it shall have all rights and
+obligations of Licensor.</p>
+<p>Except for the limited purpose of indicating to the
+public that the Work is licensed under the CCPL, Creative
+Commons does not authorize the use by either party of the
+trademark "Creative Commons" or any related trademark or
+logo of Creative Commons without the prior written
+consent of Creative Commons. Any permitted use will be in
+compliance with Creative Commons' then-current trademark
+usage guidelines, as may be published on its website or
+otherwise made available upon request from time to time.
+For the avoidance of doubt, this trademark restriction
+does not form part of the License.</p>
+<p>Creative Commons may be contacted at <a href="https://creativecommons.org/">https://creativecommons.org/</a>.</p>
+</blockquote>
+</div>
+</div>
+<div id="deed-foot">
+<p id="footer"><a href="./">« Back to Commons Deed</a></p>
+</div>
+</div>
+</body>
+</html>
diff --git a/tests/tests/media/assets/ringer.mp3 b/tests/tests/media/assets/ringer.mp3
deleted file mode 100644
index aa052e7..0000000
--- a/tests/tests/media/assets/ringer.mp3
+++ /dev/null
Binary files differ
diff --git a/tests/tests/media/audio/Android.bp b/tests/tests/media/audio/Android.bp
index d7c4c89..e7f1363 100644
--- a/tests/tests/media/audio/Android.bp
+++ b/tests/tests/media/audio/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
}
cc_test_library {
diff --git a/tests/tests/media/codec/Android.bp b/tests/tests/media/codec/Android.bp
new file mode 100644
index 0000000..dd26ec2
--- /dev/null
+++ b/tests/tests/media/codec/Android.bp
@@ -0,0 +1,64 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ // See: http://go/android-license-faq
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
+}
+
+android_test {
+ name: "CtsMediaCodecTestCases",
+ defaults: ["cts_defaults"],
+ // include both the 32 and 64 bit versions
+ compile_multilib: "both",
+ static_libs: [
+ "ctstestrunner-axt",
+ "cts-media-common",
+ "testng",
+ ],
+ jni_libs: [
+ "libctsmediacodec_jni",
+ ],
+ aaptflags: [
+ // Do not compress these files:
+ "-0 .vp9",
+ "-0 .ts",
+ "-0 .heic",
+ "-0 .trp",
+ "-0 .ota",
+ "-0 .mxmf",
+ ],
+ srcs: [
+ "src/**/*.java",
+ "aidl/**/*.aidl",
+ ],
+ // This test uses private APIs
+ platform_apis: true,
+ jni_uses_sdk_apis: true,
+ libs: [
+ "android.test.base",
+ "android.test.runner",
+ ],
+ test_suites: [
+ "cts",
+ "general-tests",
+ "mts-media",
+ ],
+ host_required: ["cts-dynamic-config"],
+ min_sdk_version: "29",
+ target_sdk_version: "31",
+}
diff --git a/tests/tests/media/codec/AndroidManifest.xml b/tests/tests/media/codec/AndroidManifest.xml
new file mode 100644
index 0000000..4ff8f2d
--- /dev/null
+++ b/tests/tests/media/codec/AndroidManifest.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="android.media.codec.cts"
+ android:targetSandboxVersion="2">
+
+ <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="31"/>
+
+ <uses-permission android:name="android.permission.WAKE_LOCK"/>
+ <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
+ <uses-permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"/>
+
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
+ <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
+
+ <application android:requestLegacyExternalStorage="true"
+ android:largeHeap="true">
+ <uses-library android:name="android.test.runner"/>
+ <service android:name="android.media.codec.cts.RemoteVirtualDisplayService"
+ android:process=":remoteService"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ </intent-filter>
+ </service>
+ </application>
+
+ <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+ android:targetPackage="android.media.codec.cts"
+ android:label="CTS tests of android.media">
+ <meta-data android:name="listener"
+ android:value="com.android.cts.runner.CtsTestRunListener"/>
+ </instrumentation>
+
+</manifest>
diff --git a/tests/tests/media/codec/AndroidTest.xml b/tests/tests/media/codec/AndroidTest.xml
new file mode 100644
index 0000000..ce2b7ed
--- /dev/null
+++ b/tests/tests/media/codec/AndroidTest.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<configuration description="Config for CTS Media test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="media" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.tradefed.targetprep.DeviceSetup">
+ <option name="force-skip-system-props" value="true" /> <!-- avoid restarting device -->
+ <option name="set-test-harness" value="false" />
+ <option name="screen-always-on" value="on" />
+ <option name="screen-adaptive-brightness" value="off" />
+ <option name="disable-audio" value="false"/>
+ <option name="screen-saver" value="off"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="host" />
+ <option name="config-filename" value="CtsMediaCodecTestCases" />
+ <option name="dynamic-config-name" value="CtsMediaCodecTestCases" />
+ <option name="version" value="1.0"/>
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
+ <option name="push-all" value="true" />
+ <option name="media-folder-name" value="CtsMediaCodecTestCases-1.0" />
+ <option name="dynamic-config-module" value="CtsMediaCodecTestCases" />
+ </target_preparer>
+ <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+ <option name="cleanup-apks" value="true" />
+ <option name="test-file-name" value="CtsMediaCodecTestCases.apk" />
+ </target_preparer>
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
+ <option name="target" value="device" />
+ <option name="config-filename" value="CtsMediaCodecTestCases" />
+ <option name="version" value="7.0"/>
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+ <option name="package" value="android.media.codec.cts" />
+ <!-- setup can be expensive so limit the number of shards -->
+ <option name="ajur-max-shard" value="5" />
+ <!-- test-timeout unit is ms, value = 30 min -->
+ <option name="test-timeout" value="1800000" />
+ <option name="runtime-hint" value="4h" />
+ <option name="exclude-annotation" value="org.junit.Ignore" />
+ <option name="hidden-api-checks" value="false" />
+ <!-- disable isolated storage so tests can access dynamic config stored in /sdcard. -->
+ <option name="isolated-storage" value="false" />
+ </test>
+</configuration>
diff --git a/tests/tests/media/codec/DynamicConfig.xml b/tests/tests/media/codec/DynamicConfig.xml
new file mode 100644
index 0000000..53dbb01
--- /dev/null
+++ b/tests/tests/media/codec/DynamicConfig.xml
@@ -0,0 +1,32 @@
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<dynamicConfig>
+ <entry key="media_codec_capabilities_test_avc_baseline12">
+ <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=160&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD.702DE9BA7AF96785FD6930AD2DD693A0486C880E&key=ik0</value>
+ </entry>
+ <entry key="media_codec_capabilities_test_avc_baseline30">
+ <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=18&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA.7A83031734CB1EDCE06766B6228842F954927960&key=ik0</value>
+ </entry>
+ <entry key="media_codec_capabilities_test_avc_high31">
+ <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=22&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=179525311196616BD8E1381759B0E5F81A9E91B5.C4A50E44059FEBCC6BBC78E3B3A4E0E0065777&key=ik0</value>
+ </entry>
+ <entry key="media_codec_capabilities_test_avc_high40">
+ <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&itag=137&source=youtube&user=android-device-test&sparams=ip,ipbits,expire,id,itag,source,user&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=B0976085596DD42DEA3F08307F76587241CB132B.043B719C039E8B92F45391ADC0BE3665E2332930&key=ik0</value>
+ </entry>
+ <entry key="media_files_url">
+ <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/codec/CtsMediaCodecTestCases-1.0.zip</value>
+ </entry>
+</dynamicConfig>
diff --git a/tests/tests/media/codec/OWNERS b/tests/tests/media/codec/OWNERS
new file mode 100644
index 0000000..f3d95c44
--- /dev/null
+++ b/tests/tests/media/codec/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 1344
+include ../../../media/OWNERS
diff --git a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
index 4bada72..5820089 100644
--- a/tests/tests/media/src/android/media/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.cts.InputSurface;
+import android.media.cts.OutputSurface;
import android.opengl.GLES20;
import android.test.AndroidTestCase;
import android.util.Log;
diff --git a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
old mode 100755
new mode 100644
similarity index 99%
rename from tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
index b82019a..00b2e82
--- a/tests/tests/media/src/android/media/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.graphics.ImageFormat;
import android.media.Image;
@@ -22,6 +22,12 @@
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.cts.InputSurface;
+import android.media.cts.InputSurfaceInterface;
+import android.media.cts.MediaCodecWrapper;
+import android.media.cts.NdkMediaCodec;
+import android.media.cts.OutputSurface;
+import android.media.cts.SdkMediaCodec;
import android.opengl.GLES20;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresDevice;
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
index 96ae72a..9250141 100755
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.app.Presentation;
import android.content.Context;
@@ -26,6 +26,10 @@
import android.media.MediaCodecList;
import android.media.MediaFormat;
import android.media.MediaMuxer;
+import android.media.cts.CompositionTextureView;
+import android.media.cts.InputSurface;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.OutputSurface;
import android.opengl.GLES20;
import android.os.Build;
import android.os.Bundle;
diff --git a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTest.java
index de54f12..0625743 100644
--- a/tests/tests/media/src/android/media/cts/EncodeVirtualDisplayWithCompositionTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTest.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.media.MediaFormat;
+import android.media.cts.NonMediaMainlineTest;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresDevice;
import android.test.AndroidTestCase;
diff --git a/tests/tests/media/common/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
similarity index 99%
rename from tests/tests/media/common/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
rename to tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
index 4ad8d27..b9c1856 100644
--- a/tests/tests/media/common/src/android/media/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayWithCompositionTestImpl.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.app.Presentation;
import android.content.ComponentName;
@@ -30,7 +30,10 @@
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.cts.CompositionTextureView;
import android.media.cts.R;
+import android.media.cts.InputSurface;
+import android.media.cts.OutputSurface;
import android.opengl.GLES11Ext;
import android.opengl.GLES20;
import android.opengl.Matrix;
@@ -1403,8 +1406,8 @@
void connect() throws Exception {
Intent intent = new Intent();
- intent.setClassName("android.media.cts",
- "android.media.cts.RemoteVirtualDisplayService");
+ intent.setClassName("android.media.codec.cts",
+ "android.media.codec.cts.RemoteVirtualDisplayService");
mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
if (!mConnectionWait.tryAcquire(DEFAULT_WAIT_TIMEOUT_MS, TimeUnit.MILLISECONDS)) {
fail("cannot bind to service");
diff --git a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java b/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
index a1a8150..eec4568 100644
--- a/tests/tests/media/src/android/media/cts/ExtractDecodeEditEncodeMuxTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/ExtractDecodeEditEncodeMuxTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.annotation.TargetApi;
import android.content.res.AssetFileDescriptor;
@@ -27,6 +27,10 @@
import android.media.MediaFormat;
import android.media.MediaMuxer;
import android.media.MediaPlayer;
+import android.media.cts.InputSurface;
+import android.media.cts.MediaStubActivity;
+import android.media.cts.OutputSurface;
+import android.media.cts.Preconditions;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
diff --git a/tests/tests/media/src/android/media/cts/IvfReader.java b/tests/tests/media/codec/src/android/media/codec/cts/IvfReader.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/IvfReader.java
rename to tests/tests/media/codec/src/android/media/codec/cts/IvfReader.java
index 2f679ae..35d3220 100644
--- a/tests/tests/media/src/android/media/cts/IvfReader.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/IvfReader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import java.io.IOException;
import java.io.RandomAccessFile;
diff --git a/tests/tests/media/src/android/media/cts/IvfWriter.java b/tests/tests/media/codec/src/android/media/codec/cts/IvfWriter.java
similarity index 85%
rename from tests/tests/media/src/android/media/cts/IvfWriter.java
rename to tests/tests/media/codec/src/android/media/codec/cts/IvfWriter.java
index 36fb679..a41143b 100644
--- a/tests/tests/media/src/android/media/cts/IvfWriter.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/IvfWriter.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.media.MediaFormat;
+import android.util.Log;
import java.io.IOException;
import java.io.RandomAccessFile;
@@ -29,6 +30,7 @@
*/
public class IvfWriter {
+ private static final String TAG = "IvfWriter";
private static final byte HEADER_END = 32;
private RandomAccessFile mOutputFile;
private int mWidth;
@@ -102,6 +104,24 @@
mFrameCount++;
}
+ private static byte[] getCodecFourcc(String mimeType) {
+ switch(mimeType) {
+ case MediaFormat.MIMETYPE_VIDEO_AVC:
+ return new byte[] {'H', '2', '6', '4'};
+ case MediaFormat.MIMETYPE_VIDEO_HEVC:
+ return new byte[] {'H', 'E', 'V', 'C'};
+ case MediaFormat.MIMETYPE_VIDEO_VP8:
+ return new byte[] {'V', 'P', '8', '0'};
+ case MediaFormat.MIMETYPE_VIDEO_VP9:
+ return new byte[] {'V', 'P', '9', '0'};
+ case MediaFormat.MIMETYPE_VIDEO_AV1:
+ return new byte[] {'A', 'V', '0', '1'};
+ default:
+ Log.w(TAG, "Unexpected mimeType in getCodecFourcc: " + mimeType);
+ return new byte[] {'0', '0', '0', '0'};
+ }
+ }
+
/**
* Makes a 32 byte file header for IVF format.
*
@@ -122,10 +142,11 @@
ivfHeader[3] = 'F';
lay16Bits(ivfHeader, 4, 0); // version
lay16Bits(ivfHeader, 6, 32); // header size
- ivfHeader[8] = 'V'; // fourcc
- ivfHeader[9] = 'P';
- ivfHeader[10] = (byte) (MediaFormat.MIMETYPE_VIDEO_VP8.equals(mimeType) ? '8' : '9');
- ivfHeader[11] = '0';
+ byte[] codecFourcc = getCodecFourcc(mimeType);
+ ivfHeader[8] = codecFourcc[0];
+ ivfHeader[9] = codecFourcc[1];
+ ivfHeader[10] = codecFourcc[2];
+ ivfHeader[11] = codecFourcc[3];
lay16Bits(ivfHeader, 12, width);
lay16Bits(ivfHeader, 14, height);
lay32Bits(ivfHeader, 16, rate); // scale/rate
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecBlockModelTest.java
similarity index 98%
rename from tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/MediaCodecBlockModelTest.java
index b4f41cd..475bd74 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecBlockModelTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecBlockModelTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.content.res.AssetFileDescriptor;
import android.hardware.HardwareBuffer;
@@ -26,6 +26,8 @@
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.cts.MediaCodecBlockModelHelper;
+import android.media.cts.NonMediaMainlineTest;
+import android.media.cts.Preconditions;
import android.os.Build;
import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
index 4511867..91dcf3a 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.app.ActivityManager;
import android.content.Context;
@@ -37,6 +37,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import android.media.cts.MediaPlayerTestBase;
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
import android.util.Range;
@@ -82,7 +83,7 @@
"media_codec_capabilities_test_avc_baseline30";
private static final String AVC_HIGH_31_KEY = "media_codec_capabilities_test_avc_high31";
private static final String AVC_HIGH_40_KEY = "media_codec_capabilities_test_avc_high40";
- private static final String MODULE_NAME = "CtsMediaTestCases";
+ private static final String MODULE_NAME = "CtsMediaCodecTestCases";
private DynamicConfigDeviceSide dynamicConfig;
@Before
diff --git a/tests/tests/media/src/android/media/cts/MediaCodecTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/MediaCodecTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
index b20e259..6ea7ef9 100644
--- a/tests/tests/media/src/android/media/cts/MediaCodecTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecTest.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import static org.testng.Assert.assertThrows;
@@ -38,6 +38,9 @@
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.cts.AudioHelper;
+import android.media.cts.InputSurface;
+import android.media.cts.OutputSurface;
+import android.media.cts.Preconditions;
import android.media.cts.StreamUtils;
import android.opengl.GLES20;
import android.os.Build;
diff --git a/tests/tests/media/common/src/android/media/cts/RemoteVirtualDisplayService.java b/tests/tests/media/codec/src/android/media/codec/cts/RemoteVirtualDisplayService.java
similarity index 99%
rename from tests/tests/media/common/src/android/media/cts/RemoteVirtualDisplayService.java
rename to tests/tests/media/codec/src/android/media/codec/cts/RemoteVirtualDisplayService.java
index 38cd279..fbcc904 100644
--- a/tests/tests/media/common/src/android/media/cts/RemoteVirtualDisplayService.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/RemoteVirtualDisplayService.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.app.Presentation;
import android.app.Service;
diff --git a/tests/tests/media/src/android/media/cts/VideoCodecTest.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/VideoCodecTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
index 697d3ff..2ee1137 100644
--- a/tests/tests/media/src/android/media/cts/VideoCodecTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTest.java
@@ -14,12 +14,14 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.cts.MediaCodecWrapper;
+import android.media.cts.MediaHeavyPresubmitTest;
import android.platform.test.annotations.AppModeFull;
import android.util.Log;
diff --git a/tests/tests/media/src/android/media/cts/VideoCodecTestBase.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
similarity index 99%
rename from tests/tests/media/src/android/media/cts/VideoCodecTestBase.java
rename to tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
index 31785e3..02754ab 100644
--- a/tests/tests/media/src/android/media/cts/VideoCodecTestBase.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoCodecTestBase.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.content.Context;
import android.content.res.Resources;
@@ -24,6 +24,10 @@
import android.media.MediaCodecList;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
+import android.media.cts.MediaCodecWrapper;
+import android.media.cts.NdkMediaCodec;
+import android.media.cts.Preconditions;
+import android.media.cts.SdkMediaCodec;
import android.os.Bundle;
import android.os.Environment;
import android.os.Looper;
diff --git a/tests/tests/media/src/android/media/cts/VideoDecoderRotationTest.java b/tests/tests/media/codec/src/android/media/codec/cts/VideoDecoderRotationTest.java
similarity index 97%
rename from tests/tests/media/src/android/media/cts/VideoDecoderRotationTest.java
rename to tests/tests/media/codec/src/android/media/codec/cts/VideoDecoderRotationTest.java
index 08c22b7..2cd4632 100644
--- a/tests/tests/media/src/android/media/cts/VideoDecoderRotationTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/VideoDecoderRotationTest.java
@@ -14,11 +14,12 @@
* limitations under the License.
*/
-package android.media.cts;
+package android.media.codec.cts;
import android.media.MediaCodecInfo;
import android.media.MediaCodecList;
import android.media.MediaFormat;
+import android.media.cts.NonMediaMainlineTest;
import android.platform.test.annotations.RequiresDevice;
import android.util.Log;
import android.util.Size;
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/WorkDir.java b/tests/tests/media/codec/src/android/media/codec/cts/WorkDir.java
new file mode 100644
index 0000000..10921c8
--- /dev/null
+++ b/tests/tests/media/codec/src/android/media/codec/cts/WorkDir.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.codec.cts;
+
+import android.media.cts.WorkDirBase;
+
+class WorkDir extends WorkDirBase {
+ public static final String getMediaDirString() {
+ return getMediaDirString("CtsMediaCodecTestCases-1.0");
+ }
+}
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecBlockModelHelper.java b/tests/tests/media/common/src/android/media/cts/MediaCodecBlockModelHelper.java
index c5f9209..8db3a81 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecBlockModelHelper.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecBlockModelHelper.java
@@ -318,12 +318,12 @@
}
public static class SlotEvent {
- SlotEvent(boolean input, int index) {
+ public SlotEvent(boolean input, int index) {
this.input = input;
this.index = index;
}
- final boolean input;
- final int index;
+ public final boolean input;
+ public final int index;
}
private static final UUID CLEARKEY_SCHEME_UUID =
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecPlayerTestBase.java b/tests/tests/media/common/src/android/media/cts/MediaCodecPlayerTestBase.java
index 56197fc..f200586 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecPlayerTestBase.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecPlayerTestBase.java
@@ -27,6 +27,7 @@
import android.test.ActivityInstrumentationTestCase2;
import android.util.Log;
import android.view.Surface;
+
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
@@ -36,7 +37,10 @@
private static final String TAG = MediaCodecPlayerTestBase.class.getSimpleName();
private static final int CONNECTION_RETRIES = 10;
private static final int SLEEP_TIME_MS = 1000;
- private static final long PLAY_TIME_MS = TimeUnit.MILLISECONDS.convert(25, TimeUnit.SECONDS);
+ // The first ten seconds in PLAY_TIME_MS plays the clear lead,
+ // the next ten seconds verifies encrypted playback.
+ // This applies to both streaming and offline tests.
+ private static final long PLAY_TIME_MS = TimeUnit.MILLISECONDS.convert(20, TimeUnit.SECONDS);
protected Context mContext;
protected MediaCodecClearKeyPlayer mMediaCodecPlayer;
diff --git a/tests/tests/media/decoder/Android.bp b/tests/tests/media/decoder/Android.bp
index 1449f1b..92d7af9 100644
--- a/tests/tests/media/decoder/Android.bp
+++ b/tests/tests/media/decoder/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
}
cc_test_library {
diff --git a/tests/tests/media/decoder/AndroidTest.xml b/tests/tests/media/decoder/AndroidTest.xml
index c07d154..623f744 100644
--- a/tests/tests/media/decoder/AndroidTest.xml
+++ b/tests/tests/media/decoder/AndroidTest.xml
@@ -35,7 +35,7 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaTestCases-1.4" />
+ <option name="media-folder-name" value="CtsMediaDecoderTestCases-1.0" />
<option name="dynamic-config-module" value="CtsMediaDecoderTestCases" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/media/decoder/DynamicConfig.xml b/tests/tests/media/decoder/DynamicConfig.xml
index 53528de..3c08d19 100644
--- a/tests/tests/media/decoder/DynamicConfig.xml
+++ b/tests/tests/media/decoder/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/CtsMediaTestCases-1.4.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/decoder/CtsMediaDecoderTestCases-1.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java b/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
index 43e62b7a..c5f178c 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/ImageReaderDecoderTest.java
@@ -17,10 +17,8 @@
package android.media.decoder.cts;
import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
-import android.content.Context;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.Resources.NotFoundException;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.media.Image;
@@ -30,38 +28,46 @@
import android.media.MediaCodecInfo;
import android.media.MediaCodecInfo.CodecCapabilities;
import android.media.MediaCodecInfo.VideoCapabilities;
-import android.media.MediaCodecList;
import android.media.MediaExtractor;
import android.media.MediaFormat;
import android.media.cts.CodecUtils;
import android.media.cts.Preconditions;
import android.os.Handler;
import android.os.HandlerThread;
-import android.os.ParcelFileDescriptor;
import android.platform.test.annotations.AppModeFull;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.RequiresDevice;
-import android.test.AndroidTestCase;
+
import android.util.Log;
import android.view.Surface;
-import androidx.test.filters.FlakyTest;
import androidx.test.filters.SmallTest;
import com.android.compatibility.common.util.MediaUtils;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.io.InputStream;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
/**
* Basic test for ImageReader APIs.
* <p>
@@ -76,7 +82,8 @@
@SmallTest
@RequiresDevice
@AppModeFull(reason = "Instant apps cannot access the SD card")
-public class ImageReaderDecoderTest extends AndroidTestCase {
+@RunWith(Parameterized.class)
+public class ImageReaderDecoderTest {
private static final String TAG = "ImageReaderDecoderTest";
private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE);
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
@@ -99,31 +106,80 @@
private Handler mHandler;
private ImageListener mImageListener;
- @Override
- public void setContext(Context context) {
- super.setContext(context);
+ public String mMime;
+ public String mCodecName;
+ public MediaAsset mMediaAsset;
+ public int mMode;
+
+ public ImageReaderDecoderTest(String mime, String codecName, MediaAsset asset, int mode,
+ String testId) {
+ mMime = mime;
+ mCodecName = codecName;
+ mMediaAsset = asset;
+ mMode = mode;
}
- @Override
- protected void setUp() throws Exception {
- super.setUp();
+ @Parameterized.Parameters(name = "{index}({0}_{1}_{4})")
+ public static Collection<Object[]> input() {
+ final List<Object[]> argsList = new ArrayList<>();
+ for (MediaAssets assets : ASSETS) {
+ String mime = assets.getMime();
+ String[] decoders = MediaUtils.getDecoderNamesForMime(mime);
+ for (String decoder: decoders) {
+ for (MediaAsset asset : assets.getAssets()) {
+ String id = asset.getWidth() + "x" + asset.getHeight();
+ if (asset.getIsSwirl()) {
+ id += "_swirl";
+ argsList.add(new Object[]{mime, decoder, asset, MODE_IMAGE, id + "_image"});
+ }
+ argsList.add(new Object[]{mime, decoder, asset, MODE_IMAGEREADER,
+ id + "_imagereader"});
+ }
+ }
+ }
+ return argsList;
+ }
+
+ @Test
+ public void decodeTest() {
+ Decoder decoder = new Decoder(mMime, mCodecName, mMediaAsset);
+ try {
+ decoder.videoDecode(mMode);
+ } finally {
+ closeImageReader();
+ }
+ }
+
+ @Before
+ public void setUp() throws Exception {
mHandlerThread = new HandlerThread(TAG);
mHandlerThread.start();
mHandler = new Handler(mHandlerThread.getLooper());
mImageListener = new ImageListener();
}
- @Override
- protected void tearDown() throws Exception {
+ @After
+ public void tearDown() throws Exception {
mHandlerThread.quitSafely();
mHandler = null;
}
static class MediaAsset {
- public MediaAsset(String resource, int width, int height) {
+ public MediaAsset(String resource, int width, int height, boolean isSwirl,
+ int bitDepth) {
mResource = resource;
mWidth = width;
mHeight = height;
+ mIsSwirl = isSwirl;
+ mBitDepth = bitDepth;
+ }
+
+ public MediaAsset(String resource, int width, int height) {
+ this(resource, width, height, true, 8);
+ }
+
+ public MediaAsset(String resource, int width, int height, boolean isSwirl) {
+ this(resource, width, height, isSwirl, 8);
}
public int getWidth() {
@@ -134,6 +190,14 @@
return mHeight;
}
+ public boolean getIsSwirl() {
+ return mIsSwirl;
+ }
+
+ public int getBitDepth() {
+ return mBitDepth;
+ }
+
public String getResource() {
return mResource;
}
@@ -141,6 +205,8 @@
private final String mResource;
private final int mWidth;
private final int mHeight;
+ private final boolean mIsSwirl;
+ private final int mBitDepth;
}
static class MediaAssets {
@@ -162,14 +228,6 @@
}
static final String mInpPrefix = WorkDir.getMediaDirString();
- protected AssetFileDescriptor getAssetFileDescriptorFor(final String res)
- throws FileNotFoundException {
- Preconditions.assertTestFileExists(mInpPrefix + res);
- File inpFile = new File(mInpPrefix + res);
- ParcelFileDescriptor parcelFD =
- ParcelFileDescriptor.open(inpFile, ParcelFileDescriptor.MODE_READ_ONLY);
- return new AssetFileDescriptor(parcelFD, 0, parcelFD.getStatSize());
- }
private static MediaAssets H263_ASSETS = new MediaAssets(
MediaFormat.MIMETYPE_VIDEO_H263,
@@ -191,7 +249,9 @@
new MediaAsset("swirl_144x136_h264.mp4", 144, 136),
new MediaAsset("swirl_136x144_h264.mp4", 136, 144),
new MediaAsset("swirl_132x130_h264.mp4", 132, 130),
- new MediaAsset("swirl_130x132_h264.mp4", 130, 132));
+ new MediaAsset("swirl_130x132_h264.mp4", 130, 132),
+ new MediaAsset("video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
+ 480, 360, false));
private static MediaAssets H265_ASSETS = new MediaAssets(
MediaFormat.MIMETYPE_VIDEO_HEVC,
@@ -219,86 +279,57 @@
static final float SWIRL_FPS = 12.f;
+ private static MediaAssets[] ASSETS = {H263_ASSETS, MPEG4_ASSETS, H264_ASSETS, H265_ASSETS,
+ VP8_ASSETS, VP9_ASSETS};
+
class Decoder {
final private String mName;
final private String mMime;
- final private VideoCapabilities mCaps;
- final private ArrayList<MediaAsset> mAssets;
+ final private MediaAsset mAsset;
- boolean isFlexibleFormatSupported(CodecCapabilities caps) {
+ boolean isColorFormatSupported(CodecCapabilities caps, int colorFormat) {
for (int c : caps.colorFormats) {
- if (c == COLOR_FormatYUV420Flexible) {
+ if (c == colorFormat) {
return true;
}
}
return false;
}
- Decoder(String name, MediaAssets assets, CodecCapabilities caps) {
+ Decoder(String mime, String name, MediaAsset asset) {
+ mMime = mime;
mName = name;
- mMime = assets.getMime();
- mCaps = caps.getVideoCapabilities();
- mAssets = new ArrayList<MediaAsset>();
-
- for (MediaAsset asset : assets.getAssets()) {
- if (mCaps.areSizeAndRateSupported(asset.getWidth(), asset.getHeight(), SWIRL_FPS)
- && isFlexibleFormatSupported(caps)) {
- mAssets.add(asset);
- }
- }
+ mAsset = asset;
}
- public boolean videoDecode(int mode, boolean checkSwirl) {
- boolean skipped = true;
- for (MediaAsset asset: mAssets) {
- // TODO: loop over all supported image formats
- int imageFormat = ImageFormat.YUV_420_888;
- int colorFormat = COLOR_FormatYUV420Flexible;
- videoDecode(asset, imageFormat, colorFormat, mode, checkSwirl);
- skipped = false;
+ private void videoDecode(int mode) {
+ int imageFormat = ImageFormat.YUV_420_888;
+ int colorFormat = COLOR_FormatYUV420Flexible;
+ String video = mMediaAsset.getResource();
+ int width = mMediaAsset.getWidth();
+ int height = mMediaAsset.getHeight();
+
+ if (8 == mMediaAsset.getBitDepth()) {
+ imageFormat = ImageFormat.YUV_420_888;
+ colorFormat = COLOR_FormatYUV420Flexible;
+ } else {
+ imageFormat = ImageFormat.YCBCR_P010;
+ colorFormat = COLOR_FormatYUVP010;
}
- return skipped;
- }
- private void videoDecode(
- MediaAsset asset, int imageFormat, int colorFormat, int mode, boolean checkSwirl) {
- String video = asset.getResource();
- int width = asset.getWidth();
- int height = asset.getHeight();
-
- if (DEBUG) Log.d(TAG, "videoDecode " + mName + " " + width + "x" + height);
+ if (DEBUG) {
+ Log.d(TAG, "videoDecode " + mName + " " + width + "x" + height + " bit depth " +
+ mMediaAsset.getBitDepth());
+ }
MediaCodec decoder = null;
- AssetFileDescriptor vidFD = null;
MediaExtractor extractor = null;
- File tmpFile = null;
- InputStream is = null;
- FileOutputStream os = null;
MediaFormat mediaFormat = null;
try {
extractor = new MediaExtractor();
-
- try {
- vidFD = getAssetFileDescriptorFor(video);
- extractor.setDataSource(
- vidFD.getFileDescriptor(), vidFD.getStartOffset(), vidFD.getLength());
- } catch (NotFoundException e) {
- // resource is compressed, uncompress locally
- String tmpName = "tempStream";
- tmpFile = File.createTempFile(tmpName, null, mContext.getCacheDir());
- is = new FileInputStream(mInpPrefix + video);
- os = new FileOutputStream(tmpFile);
- byte[] buf = new byte[1024];
- int len;
- while ((len = is.read(buf, 0, buf.length)) > 0) {
- os.write(buf, 0, len);
- }
- os.close();
- is.close();
-
- extractor.setDataSource(tmpFile.getAbsolutePath());
- }
+ Preconditions.assertTestFileExists(mInpPrefix + video);
+ extractor.setDataSource(mInpPrefix + video);
mediaFormat = extractor.getTrackFormat(0);
mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
@@ -306,15 +337,22 @@
// Create decoder
decoder = MediaCodec.createByCodecName(mName);
assertNotNull("couldn't create decoder" + mName, decoder);
+ MediaCodecInfo info = decoder.getCodecInfo();
+ CodecCapabilities caps = info.getCapabilitiesForType(mMime);
+ VideoCapabilities videoCaps = caps.getVideoCapabilities();
+
+ assumeTrue(mMediaAsset.getWidth() + "x" + mMediaAsset.getHeight() + " @ " +
+ SWIRL_FPS + " fps is not supported by " + mName,
+ videoCaps.areSizeAndRateSupported(mMediaAsset.getWidth(),
+ mMediaAsset.getHeight(), SWIRL_FPS));
+ assumeTrue("Color format " + colorFormat + " is not supported by " + mName,
+ isColorFormatSupported(caps, colorFormat));
decodeFramesToImage(
decoder, extractor, mediaFormat,
- width, height, imageFormat, mode, checkSwirl);
+ width, height, imageFormat, mode, mMediaAsset.getIsSwirl());
decoder.stop();
- if (vidFD != null) {
- vidFD.close();
- }
} catch (Throwable e) {
throw new RuntimeException(
"while " + mName + " decoding " + video + ": " + mediaFormat, e);
@@ -325,135 +363,10 @@
if (extractor != null) {
extractor.release();
}
- if (tmpFile != null) {
- tmpFile.delete();
- }
}
}
}
- private Decoder[] decoders(MediaAssets assets, boolean goog) {
- String mime = assets.getMime();
- MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
- ArrayList<Decoder> result = new ArrayList<Decoder>();
-
- for (MediaCodecInfo info : mcl.getCodecInfos()) {
- if (info.isEncoder() || info.isAlias() || !info.isVendor() != goog) {
- continue;
- }
- CodecCapabilities caps = null;
- try {
- caps = info.getCapabilitiesForType(mime);
- } catch (IllegalArgumentException e) { // mime is not supported
- continue;
- }
- assertNotNull(info.getName() + " capabilties for " + mime + " returned null", caps);
- result.add(new Decoder(info.getName(), assets, caps));
- }
- return result.toArray(new Decoder[result.size()]);
- }
-
- private Decoder[] goog(MediaAssets assets) {
- return decoders(assets, true /* goog */);
- }
-
- private Decoder[] other(MediaAssets assets) {
- return decoders(assets, false /* goog */);
- }
-
- private Decoder[] googH265() { return goog(H265_ASSETS); }
- private Decoder[] googH264() { return goog(H264_ASSETS); }
- private Decoder[] googH263() { return goog(H263_ASSETS); }
- private Decoder[] googMpeg4() { return goog(MPEG4_ASSETS); }
- private Decoder[] googVP8() { return goog(VP8_ASSETS); }
- private Decoder[] googVP9() { return goog(VP9_ASSETS); }
-
- private Decoder[] otherH265() { return other(H265_ASSETS); }
- private Decoder[] otherH264() { return other(H264_ASSETS); }
- private Decoder[] otherH263() { return other(H263_ASSETS); }
- private Decoder[] otherMpeg4() { return other(MPEG4_ASSETS); }
- private Decoder[] otherVP8() { return other(VP8_ASSETS); }
- private Decoder[] otherVP9() { return other(VP9_ASSETS); }
-
- public void testGoogH265Image() { swirlTest(googH265(), MODE_IMAGE); }
- public void testGoogH264Image() { swirlTest(googH264(), MODE_IMAGE); }
- public void testGoogH263Image() { swirlTest(googH263(), MODE_IMAGE); }
- public void testGoogMpeg4Image() { swirlTest(googMpeg4(), MODE_IMAGE); }
- public void testGoogVP8Image() { swirlTest(googVP8(), MODE_IMAGE); }
- public void testGoogVP9Image() { swirlTest(googVP9(), MODE_IMAGE); }
-
- public void testOtherH265Image() { swirlTest(otherH265(), MODE_IMAGE); }
- public void testOtherH264Image() { swirlTest(otherH264(), MODE_IMAGE); }
- public void testOtherH263Image() { swirlTest(otherH263(), MODE_IMAGE); }
- public void testOtherMpeg4Image() { swirlTest(otherMpeg4(), MODE_IMAGE); }
- public void testOtherVP8Image() { swirlTest(otherVP8(), MODE_IMAGE); }
- public void testOtherVP9Image() { swirlTest(otherVP9(), MODE_IMAGE); }
-
- public void testGoogH265ImageReader() { swirlTest(googH265(), MODE_IMAGEREADER); }
- public void testGoogH264ImageReader() { swirlTest(googH264(), MODE_IMAGEREADER); }
- public void testGoogH263ImageReader() { swirlTest(googH263(), MODE_IMAGEREADER); }
- public void testGoogMpeg4ImageReader() { swirlTest(googMpeg4(), MODE_IMAGEREADER); }
- public void testGoogVP8ImageReader() { swirlTest(googVP8(), MODE_IMAGEREADER); }
- public void testGoogVP9ImageReader() { swirlTest(googVP9(), MODE_IMAGEREADER); }
-
- // TODO: b/186001256
- @FlakyTest
- public void testOtherH265ImageReader() { swirlTest(otherH265(), MODE_IMAGEREADER); }
- @FlakyTest
- public void testOtherH264ImageReader() { swirlTest(otherH264(), MODE_IMAGEREADER); }
- public void testOtherH263ImageReader() { swirlTest(otherH263(), MODE_IMAGEREADER); }
- public void testOtherMpeg4ImageReader() { swirlTest(otherMpeg4(), MODE_IMAGEREADER); }
- @FlakyTest
- public void testOtherVP8ImageReader() { swirlTest(otherVP8(), MODE_IMAGEREADER); }
- @FlakyTest
- public void testOtherVP9ImageReader() { swirlTest(otherVP9(), MODE_IMAGEREADER); }
-
- /**
- * Test ImageReader with 480x360 non-google AVC decoding for flexible yuv format
- */
- public void testHwAVCDecode360pForFlexibleYuv() throws Exception {
- Decoder[] decoders = other(new MediaAssets(
- MediaFormat.MIMETYPE_VIDEO_AVC,
- new MediaAsset(
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
- 480 /* width */, 360 /* height */)));
-
- decodeTest(decoders, MODE_IMAGEREADER, false /* checkSwirl */);
- }
-
- /**
- * Test ImageReader with 480x360 google (SW) AVC decoding for flexible yuv format
- */
- public void testSwAVCDecode360pForFlexibleYuv() throws Exception {
- Decoder[] decoders = goog(new MediaAssets(
- MediaFormat.MIMETYPE_VIDEO_AVC,
- new MediaAsset(
- "video_480x360_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4",
- 480 /* width */, 360 /* height */)));
-
- decodeTest(decoders, MODE_IMAGEREADER, false /* checkSwirl */);
- }
-
- private void swirlTest(Decoder[] decoders, int mode) {
- decodeTest(decoders, mode, true /* checkSwirl */);
- }
-
- private void decodeTest(Decoder[] decoders, int mode, boolean checkSwirl) {
- try {
- boolean skipped = true;
- for (Decoder codec : decoders) {
- if (codec.videoDecode(mode, checkSwirl)) {
- skipped = false;
- }
- }
- if (skipped) {
- MediaUtils.skipTest("decoder does not any of the input files");
- }
- } finally {
- closeImageReader();
- }
- }
-
private static class ImageListener implements ImageReader.OnImageAvailableListener {
private final LinkedBlockingQueue<Image> mQueue =
new LinkedBlockingQueue<Image>();
@@ -721,10 +634,11 @@
private static void validateYuvData(byte[] yuvData, int width, int height, int format,
long ts) {
- assertTrue("YUV format must be one of the YUV_420_888, NV21, or YV12",
+ assertTrue("YUV format must be one of the YUV_420_888, NV21, YV12 or YCBCR_P010",
format == ImageFormat.YUV_420_888 ||
format == ImageFormat.NV21 ||
- format == ImageFormat.YV12);
+ format == ImageFormat.YV12 ||
+ format == ImageFormat.YCBCR_P010);
if (VERBOSE) Log.v(TAG, "Validating YUV data");
int expectedSize = width * height * ImageFormat.getBitsPerPixel(format) / 8;
@@ -734,7 +648,8 @@
private static void checkYuvFormat(int format) {
if ((format != ImageFormat.YUV_420_888) &&
(format != ImageFormat.NV21) &&
- (format != ImageFormat.YV12)) {
+ (format != ImageFormat.YV12) &&
+ (format != ImageFormat.YCBCR_P010)) {
fail("Wrong formats: " + format);
}
}
diff --git a/tests/tests/media/decoder/src/android/media/decoder/cts/WorkDir.java b/tests/tests/media/decoder/src/android/media/decoder/cts/WorkDir.java
index 87c499d..dedb3f6 100644
--- a/tests/tests/media/decoder/src/android/media/decoder/cts/WorkDir.java
+++ b/tests/tests/media/decoder/src/android/media/decoder/cts/WorkDir.java
@@ -20,6 +20,6 @@
class WorkDir extends WorkDirBase {
public static final String getMediaDirString() {
- return getMediaDirString("CtsMediaTestCases-1.4");
+ return getMediaDirString("CtsMediaDecoderTestCases-1.0");
}
}
diff --git a/tests/tests/media/drm/Android.bp b/tests/tests/media/drm/Android.bp
index 173f4d6..63facc3a 100644
--- a/tests/tests/media/drm/Android.bp
+++ b/tests/tests/media/drm/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license",
+ ],
}
android_test {
diff --git a/tests/tests/media/drm/jni/Android.bp b/tests/tests/media/drm/jni/Android.bp
index edbe659..0dc55fa 100644
--- a/tests/tests/media/drm/jni/Android.bp
+++ b/tests/tests/media/drm/jni/Android.bp
@@ -16,12 +16,7 @@
//------------------------------------------------------------------------------
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: ["Android-Apache-2.0"],
}
//------------------------------------------------------------------------------
diff --git a/tests/tests/media/encoder/Android.bp b/tests/tests/media/encoder/Android.bp
index b871bd0..cd860cc 100644
--- a/tests/tests/media/encoder/Android.bp
+++ b/tests/tests/media/encoder/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license",
+ ],
}
android_test {
diff --git a/tests/tests/media/encoder/AndroidTest.xml b/tests/tests/media/encoder/AndroidTest.xml
index a1946c6..65d8d6d 100644
--- a/tests/tests/media/encoder/AndroidTest.xml
+++ b/tests/tests/media/encoder/AndroidTest.xml
@@ -35,7 +35,7 @@
</target_preparer>
<target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
<option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaTestCases-1.4" />
+ <option name="media-folder-name" value="CtsMediaEncoderTestCases-1.0" />
<option name="dynamic-config-module" value="CtsMediaEncoderTestCases" />
</target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/media/encoder/DynamicConfig.xml b/tests/tests/media/encoder/DynamicConfig.xml
index 53528de..4dd9839 100644
--- a/tests/tests/media/encoder/DynamicConfig.xml
+++ b/tests/tests/media/encoder/DynamicConfig.xml
@@ -15,6 +15,6 @@
<dynamicConfig>
<entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/CtsMediaTestCases-1.4.zip</value>
+ <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/encoder/CtsMediaEncoderTestCases-1.0.zip</value>
</entry>
</dynamicConfig>
diff --git a/tests/tests/media/encoder/src/android/media/encoder/cts/WorkDir.java b/tests/tests/media/encoder/src/android/media/encoder/cts/WorkDir.java
index 0277561..60d307d 100644
--- a/tests/tests/media/encoder/src/android/media/encoder/cts/WorkDir.java
+++ b/tests/tests/media/encoder/src/android/media/encoder/cts/WorkDir.java
@@ -20,6 +20,6 @@
class WorkDir extends WorkDirBase {
public static final String getMediaDirString() {
- return getMediaDirString("CtsMediaTestCases-1.4");
+ return getMediaDirString("CtsMediaEncoderTestCases-1.0");
}
}
diff --git a/tests/tests/media/extractor/Android.bp b/tests/tests/media/extractor/Android.bp
index bf48cb8..cdda629 100644
--- a/tests/tests/media/extractor/Android.bp
+++ b/tests/tests/media/extractor/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
}
android_test {
diff --git a/tests/tests/media/extractor/src/android/media/extractor/cts/MediaExtractorTest.java b/tests/tests/media/extractor/src/android/media/extractor/cts/MediaExtractorTest.java
index 63ab3fd..5d67c62 100644
--- a/tests/tests/media/extractor/src/android/media/extractor/cts/MediaExtractorTest.java
+++ b/tests/tests/media/extractor/src/android/media/extractor/cts/MediaExtractorTest.java
@@ -120,43 +120,6 @@
return ds;
}
- @Ignore
- @Test
- public void SKIP_testNullMediaDataSourceIsRejected() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorUnitTest$TestApi
- // #testIfNullMediaDataSourceIsRejectedBySetDataSource
- try {
- mExtractor.setDataSource((MediaDataSource)null);
- fail("Expected IllegalArgumentException.");
- } catch (IllegalArgumentException ex) {
- // Expected, test passed.
- }
- }
-
- @Ignore
- @Test
- public void SKIP_testMediaDataSourceIsClosedOnRelease() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testMediaDataSource
- TestMediaDataSource dataSource = setDataSource("testvideo.3gp");
- mExtractor.release();
- assertTrue(dataSource.isClosed());
- }
-
- @Ignore
- @Test
- public void SKIP_testExtractorFailsIfMediaDataSourceThrows() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorUnitTest$TestApi
- // #testIfInvalidDataSourceIsRejectedBySetDataSource
- TestMediaDataSource dataSource = getDataSourceFor("testvideo.3gp");
- dataSource.throwFromReadAt();
- try {
- mExtractor.setDataSource(dataSource);
- fail("Expected IOException.");
- } catch (IOException e) {
- // Expected.
- }
- }
-
@Test
public void testExtractorFailsIfMediaDataSourceReturnsAnError() throws Exception {
TestMediaDataSource dataSource = getDataSourceFor("testvideo.3gp");
@@ -169,28 +132,6 @@
}
}
- // Smoke test MediaExtractor reading from a DataSource.
- @Ignore
- @Test
- public void SKIP_testExtractFromAMediaDataSource() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testMediaDataSource and
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest#testMetrics
- TestMediaDataSource dataSource = setDataSource("testvideo.3gp");
- checkExtractorSamplesAndMetrics();
- }
-
- // Smoke test MediaExtractor reading from an AssetFileDescriptor.
- @Ignore
- @Test
- public void SKIP_testExtractFromAssetFileDescriptor() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testAssetFD and
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest#testMetrics
- AssetFileDescriptor afd = getAssetFileDescriptorFor("testvideo.3gp");
- mExtractor.setDataSource(afd);
- checkExtractorSamplesAndMetrics();
- afd.close();
- }
-
private boolean advertisesDolbyVision() {
// Device advertises support for DV if 1) it has a DV decoder, OR
// 2) it lists DV on the Display HDR capabilities.
@@ -258,32 +199,6 @@
assertEquals("video/hevc", mimeType);
}
- // DolbyVisionMediaExtractor for profile-level (DvheStn/Fhd60).
- @CddTest(requirement="5.3.8")
- @Ignore
- @Test
- public void SKIP_testDolbyVisionMediaExtractorProfileDvheStn() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$ValidateKeyValuePairs[video/dolby-vision]
- TestMediaDataSource dataSource = setDataSource("video_dovi_1920x1080_60fps_dvhe_05.mp4");
-
- if (advertisesDolbyVision()) {
- // DvheStn exposes only a single non-backward compatible Dolby Vision HDR track.
- assertEquals("There must be 1 track", 1, mExtractor.getTrackCount());
- final MediaFormat trackFormat = mExtractor.getTrackFormat(0);
-
- final String mimeType = trackFormat.getString(MediaFormat.KEY_MIME);
- assertEquals("video/dolby-vision", mimeType);
-
- final int profile = trackFormat.getInteger(MediaFormat.KEY_PROFILE);
- assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionProfileDvheStn, profile);
-
- final int level = trackFormat.getInteger(MediaFormat.KEY_LEVEL);
- assertEquals(MediaCodecInfo.CodecProfileLevel.DolbyVisionLevelFhd60, level);
- } else {
- MediaUtils.skipTest("Device does not provide a Dolby Vision decoder");
- }
- }
-
// DolbyVisionMediaExtractor for profile-level (DvheSt/Fhd60).
@CddTest(requirement="5.3.8")
@Test
@@ -658,71 +573,6 @@
}
}
- @AppModeFull(reason = "Instant apps cannot bind sockets.")
- @Ignore
- @Test
- public void SKIP_testExtractorGetCachedDuration() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testUrlDataSource
- CtsTestServer foo = new CtsTestServer(getContext());
- String url = foo.getAssetUrl("ringer.mp3");
- mExtractor.setDataSource(url);
- long cachedDurationUs = mExtractor.getCachedDuration();
- assertTrue("cached duration should be non-negative", cachedDurationUs >= 0);
- foo.shutdown();
- }
-
- @Ignore
- @Test
- public void SKIP_testExtractorHasCacheReachedEndOfStream() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testUrlDataSource
- // Using file source to get deterministic result.
- AssetFileDescriptor afd = getAssetFileDescriptorFor("testvideo.3gp");
- mExtractor.setDataSource(afd);
- assertTrue(mExtractor.hasCacheReachedEndOfStream());
- afd.close();
- }
-
- /*
- * Makes sure if PTS(order) of a video file with BFrames matches the expected values in
- * the corresponding text file with just PTS values.
- */
- @Ignore
- @Test
- public void SKIP_testVideoPresentationTimeStampsMatch() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$ExtractorTimeStampTest
- setDataSource("binary_counter_320x240_30fps_600frames.mp4");
- // Select the only video track present in the file.
- final int trackCount = mExtractor.getTrackCount();
- for (int i = 0; i < trackCount; i++) {
- mExtractor.selectTrack(i);
- }
-
- Reader txtRdr = new BufferedReader(new InputStreamReader(new FileInputStream(
- mInpPrefix + "timestamps_binary_counter_320x240_30fps_600frames.txt")));
- StreamTokenizer strTok = new StreamTokenizer(txtRdr);
- strTok.parseNumbers();
-
- boolean srcAdvance = false;
- long srcSampleTimeUs = -1;
- long testSampleTimeUs = -1;
-
- strTok.nextToken();
- do {
- srcSampleTimeUs = mExtractor.getSampleTime();
- testSampleTimeUs = (long) strTok.nval;
-
- // Ignore round-off error if any.
- if (Math.abs(srcSampleTimeUs - testSampleTimeUs) > 1) {
- Log.d(TAG, "srcSampleTimeUs:" + srcSampleTimeUs + " testSampleTimeUs:" +
- testSampleTimeUs);
- fail("video presentation timestamp not equal");
- }
-
- srcAdvance = mExtractor.advance();
- strTok.nextToken();
- } while (srcAdvance);
- }
-
/* package */ static class ByteBufferDataSource extends MediaDataSource {
private final long mSize;
private TreeMap<Long, ByteBuffer> mMap = new TreeMap<Long, ByteBuffer>();
@@ -873,78 +723,6 @@
}
}
- @SmallTest
- @Ignore
- @Test
- public void SKIP_testFlacIdentity() throws Exception {
- // duplicate of CtsMediaV2TestCases:CodecEncoderTest$testLosslessEncodeDecode[audio/flac]
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FusedExtractorDecoderTest[audio/flac]
- final int PCM_FRAMES = 1152 * 4; // FIXME: requires 4 flac frames to work with OMX codecs.
- final int CHANNEL_COUNT = 2;
- final int SAMPLES = PCM_FRAMES * CHANNEL_COUNT;
- final int[] SAMPLE_RATES = {44100, 192000}; // ensure 192kHz supported.
-
- for (int sampleRate : SAMPLE_RATES) {
- final MediaFormat format = new MediaFormat();
- format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_FLAC);
- format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate);
- format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNEL_COUNT);
-
- Log.d(TAG, "Trying sample rate: " + sampleRate
- + " channel count: " + CHANNEL_COUNT);
- format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, 5);
-
- // TODO: Add float mode when MediaExtractor supports float configuration.
- final StreamUtils.PcmAudioBufferStream audioStream =
- new StreamUtils.PcmAudioBufferStream(
- SAMPLES, sampleRate, 1000 /* frequency */, 100 /* sweep */,
- false /* useFloat */);
-
- final StreamUtils.MediaCodecStream rawToFlac =
- new StreamUtils.MediaCodecStream(
- new StreamUtils.ByteBufferInputStream(audioStream),
- format, true /* encode */);
- final MediaExtractorStream flacToRaw =
- new MediaExtractorStream(MediaFormat.MIMETYPE_AUDIO_FLAC /* inMime */,
- MediaFormat.MIMETYPE_AUDIO_RAW /* outMime */, rawToFlac);
-
- // Note: the existence of signed zero (as well as NAN) may make byte
- // comparisons invalid for floating point output. In our case, since the
- // floats come through integer to float conversion, it does not matter.
- assertEquals("Audio data not identical after compression",
- audioStream.sizeInBytes(),
- StreamUtils.compareStreams(new StreamUtils.ByteBufferInputStream(flacToRaw),
- new StreamUtils.ByteBufferInputStream(
- new StreamUtils.PcmAudioBufferStream(audioStream))));
- }
- }
-
- @Ignore
- @Test
- public void SKIP_testFlacMovExtraction() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FusedExtractorDecoderTest[audio/flac]
- AssetFileDescriptor testFd = getAssetFileDescriptorFor("sinesweepalac.mov");
- MediaExtractor extractor = new MediaExtractor();
- extractor.setDataSource(testFd.getFileDescriptor(), testFd.getStartOffset(),
- testFd.getLength());
- testFd.close();
- extractor.selectTrack(0);
- boolean lastAdvanceResult = true;
- boolean lastReadResult = true;
- ByteBuffer buf = ByteBuffer.allocate(2*1024*1024);
- int totalSize = 0;
- while(true) {
- int n = extractor.readSampleData(buf, 0);
- if (n > 0) {
- totalSize += n;
- }
- if (!extractor.advance()) {
- break;
- }
- }
- assertTrue("could not read alac mov", totalSize > 0);
- }
-
@Test
public void testProgramStreamExtraction() throws Exception {
AssetFileDescriptor testFd = getAssetFileDescriptorFor("programstream.mpeg");
@@ -1070,29 +848,6 @@
extractor.release();
}
- @Ignore
- @Test
- public void SKIP_testAdvance() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest and
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest#testExtract[*]
- // audio-only
- doTestAdvance("sinesweepm4a.m4a");
- doTestAdvance("sinesweepmp3lame.mp3");
- doTestAdvance("sinesweepmp3smpb.mp3");
- doTestAdvance("sinesweepwav.wav");
- doTestAdvance("sinesweepflac.flac");
- doTestAdvance("sinesweepogg.ogg");
- doTestAdvance("sinesweepoggmkv.mkv");
-
- // video-only
- doTestAdvance("swirl_144x136_mpeg4.mp4");
- doTestAdvance("video_640x360_mp4_hevc_450kbps_no_b.mp4");
-
- // audio+video
- doTestAdvance("video_480x360_mp4_h264_500kbps_30fps_aac_stereo_128kbps_44100hz.mp4");
- doTestAdvance("video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz.mkv");
- }
-
private void readAllData() {
// 1MB is enough for any sample.
final ByteBuffer buf = ByteBuffer.allocate(1024*1024);
@@ -1110,46 +865,6 @@
} while (mExtractor.advance());
}
- @Ignore
- @Test
- public void SKIP_testAC3inMP4() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest[audio/ac3]
- setDataSource("testac3mp4.mp4");
- readAllData();
- }
-
- @Ignore
- @Test
- public void SKIP_testEAC3inMP4() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest[audio/eac3]
- setDataSource("testeac3mp4.mp4");
- readAllData();
- }
-
- @Ignore
- @Test
- public void SKIP_testAC3inTS() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest[audio/ac3]
- setDataSource("testac3ts.ts");
- readAllData();
- }
-
- @Ignore
- @Test
- public void SKIP_testEAC3inTS() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest[audio/eac3]
- setDataSource("testeac3ts.ts");
- readAllData();
- }
-
- @Ignore
- @Test
- public void SKIP_testAC4inMP4() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest[audio/ac4]
- setDataSource("multi0.mp4");
- readAllData();
- }
-
@Test
public void testAV1InMP4() throws Exception {
setDataSource("video_dovi_3840x2160_30fps_dav1_10_2.mp4");
diff --git a/tests/tests/media/libmediandkjni/Android.bp b/tests/tests/media/libmediandkjni/Android.bp
index a5aaea4..dc4b821 100644
--- a/tests/tests/media/libmediandkjni/Android.bp
+++ b/tests/tests/media/libmediandkjni/Android.bp
@@ -23,7 +23,20 @@
// to get the below license kinds:
// SPDX-license-identifier-Apache-2.0
// legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_libmediaandkjni_license",
+ ],
+}
+
+license_kind {
+ name: "libmediaandkjni_public_domain",
+ conditions: ["unencumbered"],
+}
+
+license {
+ name: "cts_tests_tests_media_libmediaandkjni_license",
+ license_kinds: ["libmediaandkjni_public_domain"],
}
cc_test_library {
@@ -56,8 +69,6 @@
name: "libctsmediacodec_jni",
srcs: [
"native-media-jni.cpp",
- "native_media_utils.cpp",
- "native_media_decoder_source.cpp",
],
shared_libs: [
"libandroid",
diff --git a/tests/tests/media/libmediandkjni/codec-utils-jni.cpp b/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
index 9af0cfe..bf6bd24 100644
--- a/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
+++ b/tests/tests/media/libmediandkjni/codec-utils-jni.cpp
@@ -38,6 +38,9 @@
#include "md5_utils.h"
+// ImageFormat.YCBCR_P010 was defined in API31.
+#define __YCBCR_P010_MIN_API__ 31
+
typedef ssize_t offs_t;
struct NativeImage {
@@ -99,6 +102,7 @@
static struct ImageFieldsAndMethods {
// android.graphics.ImageFormat
int YUV_420_888;
+ int YCBCR_P010;
// android.media.Image
jmethodID methodWidth;
jmethodID methodHeight;
@@ -126,6 +130,14 @@
jclass imageFormatClazz = env->FindClass("android/graphics/ImageFormat");
const jfieldID fieldYUV420888 = env->GetStaticFieldID(imageFormatClazz, "YUV_420_888", "I");
gFields.YUV_420_888 = env->GetStaticIntField(imageFormatClazz, fieldYUV420888);
+ if (__builtin_available(android __YCBCR_P010_MIN_API__, *)) {
+ const jfieldID fieldYCBCRP010 = env->GetStaticFieldID(imageFormatClazz,
+ "YCBCR_P010", "I");
+ gFields.YCBCR_P010 = env->GetStaticIntField(imageFormatClazz, fieldYCBCRP010);
+ } else {
+ // Set this to -1 to ensure it doesn't get equated to any valid color format
+ gFields.YCBCR_P010 = -1;
+ }
env->DeleteLocalRef(imageFormatClazz);
imageFormatClazz = NULL;
}
@@ -199,10 +211,10 @@
cropRect = NULL;
}
- if (img->format != gFields.YUV_420_888) {
+ if (img->format != gFields.YUV_420_888 && img->format != gFields.YCBCR_P010) {
jniThrowException(
env, "java/lang/UnsupportedOperationException",
- "only support YUV_420_888 images");
+ "only support YUV_420_888 and YCBCR_P010 images");
delete img;
img = NULL;
return NULL;
@@ -406,9 +418,16 @@
uint8_t *vcol = (uint8_t *)vrow;
for (size_t x = img->plane[0].cropWidth; x; --x) {
- uint64_t Y = *ycol;
- uint64_t U = *ucol;
- uint64_t V = *vcol;
+ uint64_t Y = 0, U = 0, V = 0;
+ if (img->format == gFields.YCBCR_P010) {
+ Y = ((uint16_t)(*(ycol + 1)) << 2) || (*ycol >> 6);
+ U = ((uint16_t)(*(ucol + 1)) << 2) || (*ucol >> 6);
+ V = ((uint16_t)(*(vcol + 1)) << 2) || (*vcol >> 6);
+ } else {
+ Y = *ycol;
+ U = *ucol;
+ V = *vcol;
+ }
sum_x[0] += Y;
sum_x[1] += U;
diff --git a/tests/tests/media/libmediandkjni/native-media-jni.cpp b/tests/tests/media/libmediandkjni/native-media-jni.cpp
index 13ad46d..7d5506a 100644
--- a/tests/tests/media/libmediandkjni/native-media-jni.cpp
+++ b/tests/tests/media/libmediandkjni/native-media-jni.cpp
@@ -41,255 +41,6 @@
#include "media/NdkMediaFormat.h"
#include "media/NdkMediaMuxer.h"
-template <class T>
-class simplevector {
- T *storage;
- int capacity;
- int numfilled;
-public:
- simplevector() {
- capacity = 16;
- numfilled = 0;
- storage = new T[capacity];
- }
- ~simplevector() {
- delete[] storage;
- }
-
- void add(T item) {
- if (numfilled == capacity) {
- T *old = storage;
- capacity *= 2;
- storage = new T[capacity];
- for (int i = 0; i < numfilled; i++) {
- storage[i] = old[i];
- }
- delete[] old;
- }
- storage[numfilled] = item;
- numfilled++;
- }
-
- int size() {
- return numfilled;
- }
-
- T* data() {
- return storage;
- }
-};
-
-static int adler32(const uint8_t *input, int len) {
-
- int a = 1;
- int b = 0;
- for (int i = 0; i < len; i++) {
- a += input[i];
- b += a;
- a = a % 65521;
- b = b % 65521;
- }
- int ret = b * 65536 + a;
- ALOGV("adler %d/%d", len, ret);
- return ret;
-}
-
-jobject testExtractor(AMediaExtractor *ex, JNIEnv *env) {
-
- simplevector<int> sizes;
- int numtracks = AMediaExtractor_getTrackCount(ex);
- sizes.add(numtracks);
- for (int i = 0; i < numtracks; i++) {
- AMediaFormat *format = AMediaExtractor_getTrackFormat(ex, i);
- const char *s = AMediaFormat_toString(format);
- ALOGI("track %d format: %s", i, s);
- const char *mime;
- if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
- ALOGE("no mime type");
- return NULL;
- } else if (!strncmp(mime, "audio/", 6)) {
- sizes.add(0);
- int32_t val32;
- int64_t val64;
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &val32);
- sizes.add(val32);
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &val32);
- sizes.add(val32);
- AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
- sizes.add(val64);
- } else if (!strncmp(mime, "video/", 6)) {
- sizes.add(1);
- int32_t val32;
- int64_t val64;
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &val32);
- sizes.add(val32);
- AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &val32);
- sizes.add(val32);
- AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &val64);
- sizes.add(val64);
- } else {
- ALOGE("expected audio or video mime type, got %s", mime);
- }
- AMediaFormat_delete(format);
- AMediaExtractor_selectTrack(ex, i);
- }
- int bufsize = 1024*1024;
- uint8_t *buf = new uint8_t[bufsize];
- while(true) {
- int n = AMediaExtractor_readSampleData(ex, buf, bufsize);
- ssize_t sampleSize = AMediaExtractor_getSampleSize(ex);
- if (n < 0 || n != sampleSize) {
- break;
- }
- sizes.add(n);
- sizes.add(AMediaExtractor_getSampleTrackIndex(ex));
- sizes.add(AMediaExtractor_getSampleFlags(ex));
- sizes.add(AMediaExtractor_getSampleTime(ex));
- sizes.add(adler32(buf, n));
- AMediaExtractor_advance(ex);
- }
-
- // allocate java int array for result and return it
- int *data = sizes.data();
- int numsamples = sizes.size();
- jintArray ret = env->NewIntArray(numsamples);
- jboolean isCopy;
- jint *dst = env->GetIntArrayElements(ret, &isCopy);
- for (int i = 0; i < numsamples; ++i) {
- dst[i] = data[i];
- }
- env->ReleaseIntArrayElements(ret, dst, 0);
-
- delete[] buf;
- AMediaExtractor_delete(ex);
- return ret;
-}
-
-
-// get the sample sizes for the file
-extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNative(JNIEnv *env,
- jclass /*clazz*/, int fd, jlong offset, jlong size)
-{
- AMediaExtractor *ex = AMediaExtractor_new();
- int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
- if (err != 0) {
- ALOGE("setDataSource error: %d", err);
- return NULL;
- }
- return testExtractor(ex, env);
-}
-
-// get the sample sizes for the path
-extern "C" jobject Java_android_media_cts_NativeDecoderTest_getSampleSizesNativePath(JNIEnv *env,
- jclass /*clazz*/, jstring jpath, jobjectArray jkeys, jobjectArray jvalues,
- jboolean testNativeSource)
-{
- AMediaExtractor *ex = AMediaExtractor_new();
-
- const char *tmp = env->GetStringUTFChars(jpath, NULL);
- if (tmp == NULL) { // Out of memory
- return NULL;
- }
-
- int numkeys = jkeys ? env->GetArrayLength(jkeys) : 0;
- int numvalues = jvalues ? env->GetArrayLength(jvalues) : 0;
- int numheaders = numkeys < numvalues ? numkeys : numvalues;
- const char **key_values = numheaders ? new const char *[numheaders * 2] : NULL;
- for (int i = 0; i < numheaders; i++) {
- jstring jkey = (jstring) (env->GetObjectArrayElement(jkeys, i));
- jstring jvalue = (jstring) (env->GetObjectArrayElement(jvalues, i));
- const char *key = env->GetStringUTFChars(jkey, NULL);
- const char *value = env->GetStringUTFChars(jvalue, NULL);
- key_values[i * 2] = key;
- key_values[i * 2 + 1] = value;
- }
-
- int err;
- AMediaDataSource *src = NULL;
- if (testNativeSource) {
- src = AMediaDataSource_newUri(tmp, numheaders, key_values);
- err = src ? AMediaExtractor_setDataSourceCustom(ex, src) : -1;
- } else {
- err = AMediaExtractor_setDataSource(ex, tmp);
- }
-
- for (int i = 0; i < numheaders; i++) {
- jstring jkey = (jstring) (env->GetObjectArrayElement(jkeys, i));
- jstring jvalue = (jstring) (env->GetObjectArrayElement(jvalues, i));
- env->ReleaseStringUTFChars(jkey, key_values[i * 2]);
- env->ReleaseStringUTFChars(jvalue, key_values[i * 2 + 1]);
- }
-
- env->ReleaseStringUTFChars(jpath, tmp);
- delete[] key_values;
-
- if (err != 0) {
- ALOGE("setDataSource error: %d", err);
- AMediaExtractor_delete(ex);
- AMediaDataSource_delete(src);
- return NULL;
- }
-
- jobject ret = testExtractor(ex, env);
- AMediaDataSource_delete(src);
- return ret;
-}
-
-extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorFileDurationNative(
- JNIEnv * /*env*/, jclass /*clazz*/, int fd, jlong offset, jlong size)
-{
- AMediaExtractor *ex = AMediaExtractor_new();
- int err = AMediaExtractor_setDataSourceFd(ex, fd, offset, size);
- if (err != 0) {
- ALOGE("setDataSource error: %d", err);
- AMediaExtractor_delete(ex);
- return -1;
- }
- int64_t durationUs = -1;
- AMediaFormat *format = AMediaExtractor_getFileFormat(ex);
- AMediaFormat_getInt64(format, AMEDIAFORMAT_KEY_DURATION, &durationUs);
- AMediaFormat_delete(format);
- AMediaExtractor_delete(ex);
- return durationUs;
-}
-
-extern "C" jlong Java_android_media_cts_NativeDecoderTest_getExtractorCachedDurationNative(
- JNIEnv * env, jclass /*clazz*/, jstring jpath, jboolean testNativeSource)
-{
- AMediaExtractor *ex = AMediaExtractor_new();
-
- const char *tmp = env->GetStringUTFChars(jpath, NULL);
- if (tmp == NULL) { // Out of memory
- AMediaExtractor_delete(ex);
- return -1;
- }
-
- int err;
- AMediaDataSource *src = NULL;
- if (testNativeSource) {
- src = AMediaDataSource_newUri(tmp, 0, NULL);
- err = src ? AMediaExtractor_setDataSourceCustom(ex, src) : -1;
- } else {
- err = AMediaExtractor_setDataSource(ex, tmp);
- }
-
- env->ReleaseStringUTFChars(jpath, tmp);
-
- if (err != 0) {
- ALOGE("setDataSource error: %d", err);
- AMediaExtractor_delete(ex);
- AMediaDataSource_delete(src);
- return -1;
- }
-
- int64_t cachedDurationUs = AMediaExtractor_getCachedDuration(ex);
- AMediaExtractor_delete(ex);
- AMediaDataSource_delete(src);
- return cachedDurationUs;
-
-}
-
-
extern "C" jboolean Java_android_media_cts_NativeDecoderTest_testFormatNative(JNIEnv * /*env*/,
jclass /*clazz*/) {
AMediaFormat* format = AMediaFormat_new();
diff --git a/tests/tests/media/libmediandkjni/native_media_decoder_source.cpp b/tests/tests/media/libmediandkjni/native_media_decoder_source.cpp
deleted file mode 100644
index 040e78b..0000000
--- a/tests/tests/media/libmediandkjni/native_media_decoder_source.cpp
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NativeMediaEnc-Source"
-#include <log/log.h>
-
-#include "native_media_source.h"
-
-using namespace Utils;
-
-class DecoderSource : public Thread, public Source {
-public:
- DecoderSource(
- int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping, bool regulate);
- ~DecoderSource();
- DecoderSource(const DecoderSource& ) = delete;
-
- Status setDataSourceFd(int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize);
- Status prepare(std::shared_ptr<Listener> l, std::shared_ptr<ANativeWindow> n) override;
- Status start() override;
- Status stop() override;
-
-protected:
- void run() override;
-
-private:
- // seek the extractor back to beginning
- void rewindExtractor();
-
- // When setting dynamic params, if the source is faster than the encoder,
- // there is a possibility of param set via setParameters() will get delayed.
- // Simulate a real-time source by slowing down the feeding rate (up to configured fps)
- bool mRegulateFramerate;
-
- std::shared_ptr<AMediaExtractor> mEx;
- std::shared_ptr<AMediaCodec> mDec;
- std::shared_ptr<AMediaFormat> mFormat;
- std::string mMime;
- int mVideoTrackIndex;
- int mFrameCount;
- bool mStopRequest;
- bool mStarted;
-};
-
-std::shared_ptr<Source> createDecoderSource(
- int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping,
- bool regulateFeedingRate, /* WA for dynamic settings */
- int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize) {
- DecoderSource *d = new DecoderSource(w, h, colorFormat, fps, looping, regulateFeedingRate);
- d->setDataSourceFd(sourceFileFd, sourceFileOffset, sourceFileSize);
- std::shared_ptr<Source> src(d);
- return src;
-}
-
-DecoderSource::DecoderSource(
- int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping, bool regulate)
- : Source(w, h, colorFormat, fps, looping),
- mRegulateFramerate(regulate),
- mEx(nullptr),
- mDec(nullptr),
- mFormat(nullptr),
- mMime(""),
- mVideoTrackIndex(-1),
- mFrameCount(0),
- mStopRequest(false),
- mStarted(false) {
-}
-
-Status DecoderSource::setDataSourceFd(
- int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize) {
-
- mEx = std::shared_ptr<AMediaExtractor>(AMediaExtractor_new(), deleter_AMediExtractor);
- int err = AMediaExtractor_setDataSourceFd(mEx.get(), sourceFileFd, sourceFileOffset, sourceFileSize);
- if (err != 0) {
- ALOGE("setDataSource error: %d", err);
- return FAIL;
- }
-
- const char *mime;
- mVideoTrackIndex = -1;
- int numtracks = AMediaExtractor_getTrackCount(mEx.get());
- for (int i = 0; i < numtracks; i++) {
- AMediaFormat *format = AMediaExtractor_getTrackFormat(mEx.get(), i);
- const char *s = AMediaFormat_toString(format);
- ALOGV("track %d format: %s", i, s);
- if (!AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime)) {
- ALOGE("no mime type");
- mEx = nullptr;
- AMediaFormat_delete(format);
- return FAIL;
- } else if (!strncmp(mime, "video/", 6)) {
- mVideoTrackIndex = i;
- mFormat = std::shared_ptr<AMediaFormat>(format, deleter_AMediaFormat);
- mMime = mime;
- break;
- } else {
- ALOGE("expected video mime type, got %s", mime);
- mEx = nullptr;
- }
- AMediaFormat_delete(format);
- }
- return mVideoTrackIndex == -1 ? FAIL : OK;
-}
-
-DecoderSource::~DecoderSource() {
- mDec = nullptr;
- mEx = nullptr;
- mFormat = nullptr;
-}
-
-void DecoderSource::run() {
- while(!mStopRequest) {
- int t = AMediaExtractor_getSampleTrackIndex(mEx.get());
- if (t < 0) {
- if (mLooping) {
- rewindExtractor();
- continue;
- } else {
- ALOGV("no more samples");
- break;
- }
- } else if (t != mVideoTrackIndex) {
- continue;
- }
-
- ssize_t bufidx = AMediaCodec_dequeueInputBuffer(mDec.get(), 5000);
- if (bufidx >= 0) {
- size_t bufsize;
- uint8_t *buf = AMediaCodec_getInputBuffer(mDec.get(), bufidx, &bufsize);
- int sampleSize = AMediaExtractor_readSampleData(mEx.get(), buf, bufsize);
- int32_t flags = 0;
- if (sampleSize < 0) {
- if (mLooping) {
- rewindExtractor();
- continue;
- } else {
- flags = AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM;
- }
- }
- // synthesize timestamps based on required fps
- int64_t timeStampUs = 1e6 / mFps * mFrameCount;
- AMediaCodec_queueInputBuffer(mDec.get(), bufidx, 0, sampleSize, timeStampUs, flags);
-
- AMediaExtractor_advance(mEx.get());
- ++mFrameCount;
- }
-
- AMediaCodecBufferInfo info;
- int status = AMediaCodec_dequeueOutputBuffer(mDec.get(), &info, 1000);
- if (status >= 0) {
- ALOGV("got decoded buffer of size=%d @%lld us",
- info.size, (long long)info.presentationTimeUs);
- bool render = info.size > 0;
- if (mBufListener != nullptr) {
- //TBD
- //mBufListener->onBufferAvailable(..);
- }
-
- // WA: if decoder runs free, dynamic settings applied by
- // MediaCodec.setParameters() are off
- if (mRegulateFramerate) {
- usleep(1e6/mFps);
- }
-
- AMediaCodec_releaseOutputBuffer(mDec.get(), status, render);
-
- if (info.flags & AMEDIACODEC_BUFFER_FLAG_END_OF_STREAM) {
- ALOGV("saw EOS");
- break;
- }
-
- } else if (status == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) {
- } else if (status == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) {
- mFormat = std::shared_ptr<AMediaFormat>(
- AMediaCodec_getOutputFormat(mDec.get()), deleter_AMediaFormat);
- ALOGV("format changed: %s", AMediaFormat_toString(mFormat.get()));
- } else if (status == AMEDIACODEC_INFO_TRY_AGAIN_LATER) {
- } else {
- ALOGV("Invalid status : %d", status);
- }
- }
-}
-
-Status DecoderSource::prepare(
- std::shared_ptr<Listener> l, std::shared_ptr<ANativeWindow> n) {
-
- mBufListener = l;
- mSurface = n;
-
- if (mVideoTrackIndex < 0) {
- ALOGE("Video track not found !");
- return FAIL;
- }
-
- assert(mEx.get() != nullptr);
- AMediaExtractor_selectTrack(mEx.get(), mVideoTrackIndex);
-
- AMediaCodec *dec = AMediaCodec_createDecoderByType(mMime.c_str());
- mDec = std::shared_ptr<AMediaCodec>(dec, deleter_AMediaCodec);
-
- ALOGI("configure decoder. surface = %p", mSurface.get());
- media_status_t status = AMediaCodec_configure(
- mDec.get(), mFormat.get(), mSurface.get(), NULL /* crypto */, 0);
- if (status != AMEDIA_OK) {
- ALOGE("failed to configure decoder");
- return FAIL;
- }
- return OK;
-}
-
-Status DecoderSource::start() {
- ALOGV("start");
- media_status_t status = AMediaCodec_start(mDec.get());
- if (status != AMEDIA_OK) {
- ALOGE("failed to start decoder");
- return FAIL;
- }
- if (startThread() != OK) {
- return FAIL;
- }
- mStarted = true;
- return OK;
-}
-
-Status DecoderSource::stop() {
- if (!mStarted) {
- return FAIL;
- }
-
- ALOGV("Stopping decoder source..");
- mStopRequest = true;
- joinThread();
-
- media_status_t status = AMediaCodec_stop(mDec.get());
- if (status != AMEDIA_OK) {
- ALOGE("failed to stop decoder");
- }
-
- mDec = nullptr;
- mEx = nullptr;
- mFormat = nullptr;
- return OK;
-}
-
-void DecoderSource::rewindExtractor() {
- assert(mEx.get() != nullptr);
- media_status_t status = AMediaExtractor_seekTo(mEx.get(), 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
- if (status != AMEDIA_OK) {
- ALOGE("failed to seek Extractor to 0");
- }
-}
-
diff --git a/tests/tests/media/libmediandkjni/native_media_source.h b/tests/tests/media/libmediandkjni/native_media_source.h
deleted file mode 100644
index 4320aed..0000000
--- a/tests/tests/media/libmediandkjni/native_media_source.h
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _NATIVE_MEDIA_SOURCE_H_
-#define _NATIVE_MEDIA_SOURCE_H_
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <memory>
-#include <string>
-
-#include <android/native_window_jni.h>
-
-#include "media/NdkMediaFormat.h"
-#include "media/NdkMediaExtractor.h"
-#include "media/NdkMediaCodec.h"
-#include "media/NdkMediaMuxer.h"
-
-#include "native_media_utils.h"
-using Utils::Thread;
-using Utils::Status;
-
-class Source {
-public:
- Source(int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping)
- : mWidth(w),
- mHeight(h),
- mColorFormat(colorFormat),
- mFps(fps),
- mLooping(looping),
- mBufListener(nullptr) {
- }
- virtual ~Source() = default;
-
- class Listener {
- public:
- virtual void onBufferAvailable(
- uint8_t *buffer, int32_t size, int64_t timeStampUs, uint32_t flags) = 0;
- virtual ~Listener() = default;
- };
- virtual Status prepare(std::shared_ptr<Listener> l, std::shared_ptr<ANativeWindow> n) = 0;
- virtual Status start() = 0;
- virtual Status stop() = 0;
-
-protected:
- int32_t mWidth;
- int32_t mHeight;
- int32_t mColorFormat;
- float mFps;
- bool mLooping;
- std::shared_ptr<Listener> mBufListener;
- std::shared_ptr<ANativeWindow> mSurface;
-};
-
-std::shared_ptr<Source> createDecoderSource(
- int32_t w, int32_t h, int32_t colorFormat, float fps, bool looping,
- bool regulateFeedingRate, /* WA for dynamic settings */
- int sourceFileFd, off64_t sourceFileOffset, off64_t sourceFileSize);
-
-#endif // _NATIVE_MEDIA_SOURCE_H_
diff --git a/tests/tests/media/libmediandkjni/native_media_utils.cpp b/tests/tests/media/libmediandkjni/native_media_utils.cpp
deleted file mode 100644
index 21b7f7f..0000000
--- a/tests/tests/media/libmediandkjni/native_media_utils.cpp
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "NativeMedia"
-#include <log/log.h>
-
-#include <stdlib.h>
-#include <math.h>
-#include <string>
-#include <algorithm>
-#include <iterator>
-#include "native_media_utils.h"
-
-namespace Utils {
-
-Status Thread::startThread() {
- assert(mHandle == 0);
- if (pthread_create(&mHandle, nullptr, Thread::thread_wrapper, this) != 0) {
- ALOGE("Failed to create thread");
- return FAIL;
- }
- return OK;
-}
-
-Status Thread::joinThread() {
- assert(mHandle != 0);
- void *ret;
- pthread_join(mHandle, &ret);
- return OK;
-}
-
-//static
-void* Thread::thread_wrapper(void *obj) {
- assert(obj != nullptr);
- Thread *t = reinterpret_cast<Thread *>(obj);
- t->run();
- return nullptr;
-}
-
-}; // namespace Utils
diff --git a/tests/tests/media/libmediandkjni/native_media_utils.h b/tests/tests/media/libmediandkjni/native_media_utils.h
deleted file mode 100644
index e5842f7..0000000
--- a/tests/tests/media/libmediandkjni/native_media_utils.h
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _NATIVE_MEDIA_UTILS_H_
-#define _NATIVE_MEDIA_UTILS_H_
-
-#include <pthread.h>
-#include <sys/cdefs.h>
-#include <stddef.h>
-#include <assert.h>
-#include <vector>
-
-#include <android/native_window_jni.h>
-
-#include "media/NdkMediaFormat.h"
-#include "media/NdkMediaExtractor.h"
-#include "media/NdkMediaCodec.h"
-#include "media/NdkMediaMuxer.h"
-
-namespace Utils {
-
-enum Status : int32_t {
- FAIL = -1,
- OK = 0,
-};
-
-class Thread {
-public:
- Thread()
- : mHandle(0) {
- }
- virtual ~Thread() {
- assert(mExited);
- mHandle = 0;
- }
- Thread(const Thread& ) = delete;
- Status startThread();
- Status joinThread();
-
-protected:
- virtual void run() = 0;
-
-private:
- static void* thread_wrapper(void *);
- pthread_t mHandle;
-};
-
-static inline void deleter_AMediExtractor(AMediaExtractor *_a) {
- AMediaExtractor_delete(_a);
-}
-
-static inline void deleter_AMediaCodec(AMediaCodec *_a) {
- AMediaCodec_delete(_a);
-}
-
-static inline void deleter_AMediaFormat(AMediaFormat *_a) {
- AMediaFormat_delete(_a);
-}
-
-static inline void deleter_AMediaMuxer(AMediaMuxer *_a) {
- AMediaMuxer_delete(_a);
-}
-
-static inline void deleter_ANativeWindow(ANativeWindow *_a) {
- ANativeWindow_release(_a);
-}
-
-}; //namespace Utils
-
-#endif // _NATIVE_MEDIA_UTILS_H_
diff --git a/tests/tests/media/muxer/Android.bp b/tests/tests/media/muxer/Android.bp
index 4fbe3ad..3eb38a6 100644
--- a/tests/tests/media/muxer/Android.bp
+++ b/tests/tests/media/muxer/Android.bp
@@ -14,13 +14,7 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: ["cts_tests_tests_media_license"],
}
cc_test_library {
diff --git a/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java b/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
index a31a80f..bf69401 100644
--- a/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
+++ b/tests/tests/media/muxer/src/android/media/muxer/cts/MediaMuxerTest.java
@@ -35,7 +35,6 @@
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
-import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.HashSet;
@@ -53,8 +52,9 @@
private static final float BAD_LONGITUDE = -181.0f;
private static final float TOLERANCE = 0.0002f;
private static final long OFFSET_TIME_US = 29 * 60 * 1000000L; // 29 minutes
- static final String mInpPrefix = WorkDir.getMediaDirString();
- private boolean mAndroid11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
+
+ private final String mInpPrefix = WorkDir.getMediaDirString();
+ private final boolean mAndroid11 = Build.VERSION.SDK_INT >= Build.VERSION_CODES.R;
@Override
public void setContext(Context context) {
@@ -70,109 +70,6 @@
return new AssetFileDescriptor(parcelFD, 0, parcelFD.getStatSize());
}
- /**
- * Test: make sure the muxer handles both video and audio tracks correctly.
- */
- public void SKIP_testVideoAudio() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestMultiTrack#testMultiTrack[*]
- // numTracks @ {1, 1}
- final String source = "video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz.3gp";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideo", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- public void SKIP_testDualVideoTrack() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestMultiTrack#testMultiTrack[*]
- // numTracks @ {2, 0}
- final String source = "video_176x144_h264_408kbps_30fps_352x288_h264_122kbps_30fps.mp4";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testDualVideo", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- public void SKIP_testDualAudioTrack() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestMultiTrack#testMultiTrack[*]
- // numTracks @ {0, 2}
- if (!MediaUtils.check(mAndroid11, "test needs Android 11")) return;
-
- final String source = "audio_aac_mono_70kbs_44100hz_aac_mono_70kbs_44100hz.mp4";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testDualAudio", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- public void SKIP_testDualVideoAndAudioTrack() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestMultiTrack#testMultiTrack[*]
- // numTracks @ {2, 2}
- if (!MediaUtils.check(mAndroid11, "test needs Android 11")) return;
-
- final String source = "video_h264_30fps_video_h264_30fps_aac_44100hz_aac_44100hz.mp4";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testDualVideoAudio", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 4, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- /**
- * Test: make sure the muxer handles video, audio and non standard compliant metadata tracks
- * that generated before API29 correctly. This test will use extractor to extract the video
- * track, audio and the non standard compliant metadata track from the source file, then
- * remuxes them into a new file with standard compliant metadata track. Finally, it will check
- * to make sure the new file's metadata track matches the source file's metadata track for the
- * mime format and data payload.
- */
- public void SKIP_testVideoAudioMedatadataWithNonCompliantMetadataTrack() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[application/gyro]
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[video/h263]
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[audio/aac]
- final String source =
- "video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_non_compliant.3gp";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- /**
- * Test: make sure the muxer handles video, audio and standard compliant metadata tracks that
- * generated from API29 correctly. This test will use extractor to extract the video track,
- * audio and the standard compliant metadata track from the source file, then remuxes them
- * into a new file with standard compliant metadata track. Finally, it will check to make sure
- * the new file's metadata track matches the source file's metadata track for the mime format
- * and data payload.
- */
- public void SKIP_testVideoAudioMedatadataWithCompliantMetadataTrack() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[application/gyro]
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[video/h263]
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[audio/aac]
- final String source =
- "video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_11025hz_metadata_gyro_compliant.3gp";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioVideoMetadata", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 3, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- /**
- * Test: make sure the muxer handles audio track only file correctly.
- */
- public void SKIP_testAudioOnly() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[audio/*]
- final String source = "sinesweepm4a.m4a";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testAudioOnly", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 1, -1, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
- /**
- * Test: make sure the muxer handles video track only file correctly.
- */
- public void SKIP_testVideoOnly() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[video/*]
- final String source = "video_only_176x144_3gp_h263_25fps.mp4";
- String outputFilePath = File.createTempFile("MediaMuxerTest_videoOnly", ".mp4")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 1, 180, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- }
-
public void testWebmOutput() throws Exception {
final String source =
"video_480x360_webm_vp9_333kbps_25fps_vorbis_stereo_128kbps_48000hz.webm";
@@ -181,142 +78,6 @@
cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM);
}
- public void SKIP_testThreegppOutput() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[*]
- final String source = "video_176x144_3gp_h263_300kbps_12fps_aac_stereo_128kbps_22050hz.3gp";
- String outputFilePath = File.createTempFile("testThreegppOutput", ".3gp")
- .getAbsolutePath();
- cloneAndVerify(source, outputFilePath, 2, 90, MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP);
- }
-
- /**
- * Tests: make sure the muxer handles exceptions correctly.
- * <br> Throws exception b/c start() is not called.
- * <br> Throws exception b/c 2 video tracks were added.
- * <br> Throws exception b/c 2 audio tracks were added.
- * <br> Throws exception b/c 3 tracks were added.
- * <br> Throws exception b/c no tracks was added.
- * <br> Throws exception b/c a wrong format.
- */
- public void SKIP_testIllegalStateExceptions() throws IOException {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestMultiTrack#testMultiTrack[*] and
- // duplicate of CtsMediaV2TestCases:MuxerUnitTest$TestApi
- String outputFilePath = File.createTempFile("MediaMuxerTest_testISEs", ".mp4")
- .getAbsolutePath();
- MediaMuxer muxer;
-
- // Throws exception b/c start() is not called.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
-
- try {
- muxer.stop();
- fail("should throw IllegalStateException.");
- } catch (IllegalStateException e) {
- // expected
- } finally {
- muxer.release();
- }
-
- // Should not throw exception when 2 video tracks were added.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
-
- try {
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
- } catch (IllegalStateException e) {
- fail("should not throw IllegalStateException.");
- } finally {
- muxer.release();
- }
-
- // Should not throw exception when 2 audio tracks were added.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
- try {
- muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
- } catch (IllegalStateException e) {
- fail("should not throw IllegalStateException.");
- } finally {
- muxer.release();
- }
-
- // Should not throw exception when 3 tracks were added.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
- muxer.addTrack(MediaFormat.createAudioFormat(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 1));
- try {
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
- } catch (IllegalStateException e) {
- fail("should not throw IllegalStateException.");
- } finally {
- muxer.release();
- }
-
- // Throws exception b/c no tracks was added.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- try {
- muxer.start();
- fail("should throw IllegalStateException.");
- } catch (IllegalStateException e) {
- // expected
- } finally {
- muxer.release();
- }
-
- // Throws exception b/c a wrong format.
- muxer = new MediaMuxer(outputFilePath, MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- try {
- muxer.addTrack(MediaFormat.createVideoFormat("vidoe/mp4", 480, 320));
- fail("should throw IllegalStateException.");
- } catch (IllegalStateException e) {
- // expected
- } finally {
- muxer.release();
- }
-
- // Test FileDescriptor Constructor expect sucess.
- RandomAccessFile file = null;
- try {
- file = new RandomAccessFile(outputFilePath, "rws");
- muxer = new MediaMuxer(file.getFD(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- muxer.addTrack(MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 320));
- } finally {
- file.close();
- muxer.release();
- }
-
- // Test FileDescriptor Constructor expect exception with read only mode.
- RandomAccessFile file2 = null;
- try {
- file2 = new RandomAccessFile(outputFilePath, "r");
- muxer = new MediaMuxer(file2.getFD(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- fail("should throw IOException.");
- } catch (IOException e) {
- // expected
- } finally {
- file2.close();
- // No need to release the muxer.
- }
-
- // Test FileDescriptor Constructor expect NO exception with write only mode.
- ParcelFileDescriptor out = null;
- try {
- out = ParcelFileDescriptor.open(new File(outputFilePath),
- ParcelFileDescriptor.MODE_WRITE_ONLY | ParcelFileDescriptor.MODE_CREATE);
- muxer = new MediaMuxer(out.getFileDescriptor(), MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
- } catch (IllegalArgumentException e) {
- fail("should not throw IllegalArgumentException.");
- } catch (IOException e) {
- fail("should not throw IOException.");
- } finally {
- out.close();
- muxer.release();
- }
-
- new File(outputFilePath).delete();
- }
-
/**
* Test: makes sure if audio and video muxing using MPEG4Writer works well when there are frame
* drops as in b/63590381 and b/64949961 while B Frames encoding is enabled.
@@ -338,27 +99,6 @@
}
/**
- * Test: makes sure if video only muxing using MPEG4Writer works well when there are B Frames.
- */
- public void SKIP_testAllTimestampsBVideoOnly() throws Exception {
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[video/avc] and
- // duplicate of CtsMediaV2TestCases:MuxerTest$TestSimpleMux#testSimpleMux[video/hevc]
- final String source = "video_480x360_mp4_h264_bframes_495kbps_30fps_editlist.mp4";
- String outputFilePath = File.createTempFile("MediaMuxerTest_testAllTimestampsBVideoOnly",
- ".mp4").getAbsolutePath();
- try {
- // No samples to drop in this case.
- // No start offsets for any track.
- cloneMediaWithSamplesDropAndStartOffsets(source, outputFilePath,
- MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4, null, null);
- verifyTSWithSamplesDropAndStartOffset(
- source, true /* has B frames */, outputFilePath, null, null);
- } finally {
- new File(outputFilePath).delete();
- }
- }
-
- /**
* Test: makes sure muxing works well when video with B Frames are muxed using MPEG4Writer
* and a few frames drop.
*/
diff --git a/tests/tests/media/player/Android.bp b/tests/tests/media/player/Android.bp
index 63ebcc6..ecda2ff 100644
--- a/tests/tests/media/player/Android.bp
+++ b/tests/tests/media/player/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
}
android_test {
diff --git a/tests/tests/media/recorder/Android.bp b/tests/tests/media/recorder/Android.bp
index 3db7dd5..9e17567 100644
--- a/tests/tests/media/recorder/Android.bp
+++ b/tests/tests/media/recorder/Android.bp
@@ -14,13 +14,10 @@
package {
// See: http://go/android-license-faq
- // A large-scale-change added 'default_applicable_licenses' to import
- // all of the 'license_kinds' from "cts_license"
- // to get the below license kinds:
- // SPDX-license-identifier-Apache-2.0
- // SPDX-license-identifier-CC-BY
- // legacy_unencumbered
- default_applicable_licenses: ["cts_license"],
+ default_applicable_licenses: [
+ "Android-Apache-2.0",
+ "cts_tests_tests_media_license", // CC-BY
+ ],
}
android_test {
diff --git a/tests/tests/media/recorder/AndroidTest.xml b/tests/tests/media/recorder/AndroidTest.xml
index d443d1d..772e6ec 100644
--- a/tests/tests/media/recorder/AndroidTest.xml
+++ b/tests/tests/media/recorder/AndroidTest.xml
@@ -27,30 +27,10 @@
<option name="disable-audio" value="false"/>
<option name="screen-saver" value="off"/>
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="host" />
- <option name="config-filename" value="CtsMediaRecorderTestCases" />
- <option name="dynamic-config-name" value="CtsMediaRecorderTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.MediaPreparer">
- <option name="push-all" value="true" />
- <option name="media-folder-name" value="CtsMediaTestCases-1.4" />
- <option name="dynamic-config-module" value="CtsMediaRecorderTestCases" />
- </target_preparer>
<target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
<option name="cleanup-apks" value="true" />
<option name="test-file-name" value="CtsMediaRecorderTestCases.apk" />
</target_preparer>
- <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DynamicConfigPusher">
- <option name="target" value="device" />
- <option name="config-filename" value="CtsMediaRecorderTestCases" />
- <option name="version" value="1.0"/>
- </target_preparer>
- <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
- <!-- MediaProjectionTest needs this one to not be granted, SuiteApkInstaller grants all of them by default.-->
- <option name="run-command" value="pm revoke android.media.recorder.cts android.permission.SYSTEM_ALERT_WINDOW"/>
- </target_preparer>
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="android.media.recorder.cts" />
<!-- setup can be expensive so limit the number of shards -->
diff --git a/tests/tests/media/res/values/exifinterface.xml b/tests/tests/media/res/values/exifinterface.xml
index d19d128..be002e5 100644
--- a/tests/tests/media/res/values/exifinterface.xml
+++ b/tests/tests/media/res/values/exifinterface.xml
@@ -229,7 +229,7 @@
<item>337</item>
<item>600</item>
<item>800</item>
- <item>1</item>
+ <item>0</item>
<item>0</item>
<item>true</item>
<item>826</item>
@@ -493,7 +493,7 @@
<item>3072</item>
<item>4608</item>
<item>200</item>
- <item>8</item>
+ <item>0</item>
<item>0</item>
<item>true</item>
<item>472</item>
@@ -537,7 +537,7 @@
<item>3000</item>
<item>4000</item>
<item>3200</item>
- <item>8</item>
+ <item>0</item>
<item>0</item>
<item>false</item>
<item />
diff --git a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
index 1811cb2..75ba4b1 100644
--- a/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
+++ b/tests/tests/media/src/android/media/cts/ExifInterfaceTest.java
@@ -643,6 +643,7 @@
public void testReadExifDataFromLgG4Iso800Dng() throws Throwable {
readFromFilesWithExif(DNG_WITH_EXIF_WITH_XMP, R.array.dng_with_exif_with_xmp);
+ writeToFilesWithExif(DNG_WITH_EXIF_WITH_XMP, R.array.dng_with_exif_with_xmp);
}
public void testReadExifDataFromLgG4Iso800Jpg() throws Throwable {
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
index 0e23ebf..7203df4 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserServiceTest.java
@@ -40,6 +40,8 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
/**
* Test {@link android.service.media.MediaBrowserService}.
@@ -51,98 +53,86 @@
private static final long WAIT_TIME_FOR_NO_RESPONSE_MS = 500L;
private static final ComponentName TEST_BROWSER_SERVICE = new ComponentName(
"android.media.cts", "android.media.cts.StubMediaBrowserService");
- private final Object mWaitLock = new Object();
- private final MediaBrowser.ConnectionCallback mConnectionCallback =
- new MediaBrowser.ConnectionCallback() {
- @Override
- public void onConnected() {
- synchronized (mWaitLock) {
- mMediaBrowserService = StubMediaBrowserService.sInstance;
- mWaitLock.notify();
- }
- }
- };
+ private final TestCountDownLatch mOnChildrenLoadedLatch = new TestCountDownLatch();
+ private final TestCountDownLatch mOnChildrenLoadedWithOptionsLatch = new TestCountDownLatch();
+ private final TestCountDownLatch mOnItemLoadedLatch = new TestCountDownLatch();
private final MediaBrowser.SubscriptionCallback mSubscriptionCallback =
new MediaBrowser.SubscriptionCallback() {
@Override
public void onChildrenLoaded(String parentId, List<MediaItem> children) {
- synchronized (mWaitLock) {
- mOnChildrenLoaded = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
+ if (children != null) {
+ for (MediaItem item : children) {
+ assertRootHints(item);
}
- mWaitLock.notify();
}
+ mOnChildrenLoadedLatch.countDown();
}
@Override
public void onChildrenLoaded(String parentId, List<MediaItem> children,
Bundle options) {
- synchronized (mWaitLock) {
- mOnChildrenLoadedWithOptions = true;
- if (children != null) {
- for (MediaItem item : children) {
- assertRootHints(item);
- }
+ if (children != null) {
+ for (MediaItem item : children) {
+ assertRootHints(item);
}
- mWaitLock.notify();
}
+ mOnChildrenLoadedWithOptionsLatch.countDown();
}
};
private final MediaBrowser.ItemCallback mItemCallback = new MediaBrowser.ItemCallback() {
@Override
public void onItemLoaded(MediaItem item) {
- synchronized (mWaitLock) {
- mOnItemLoaded = true;
- assertRootHints(item);
- mWaitLock.notify();
- }
+ assertRootHints(item);
+ mOnItemLoadedLatch.countDown();
}
};
private MediaBrowser mMediaBrowser;
private RemoteUserInfo mBrowserInfo;
private StubMediaBrowserService mMediaBrowserService;
- private boolean mOnChildrenLoaded;
- private boolean mOnChildrenLoadedWithOptions;
- private boolean mOnItemLoaded;
private Bundle mRootHints;
@Override
public void setUp() throws Exception {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mRootHints = new Bundle();
- mRootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_RECENT, true);
- mRootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_OFFLINE, true);
- mRootHints.putBoolean(MediaBrowserService.BrowserRoot.EXTRA_SUGGESTED, true);
- mMediaBrowser = new MediaBrowser(getInstrumentation().getTargetContext(),
- TEST_BROWSER_SERVICE, mConnectionCallback, mRootHints);
- mBrowserInfo = new RemoteUserInfo(
- getInstrumentation().getTargetContext().getPackageName(),
- Process.myPid(),
- Process.myUid());
- }
- });
- synchronized (mWaitLock) {
+ mRootHints = new Bundle();
+ mRootHints.putBoolean(BrowserRoot.EXTRA_RECENT, true);
+ mRootHints.putBoolean(BrowserRoot.EXTRA_OFFLINE, true);
+ mRootHints.putBoolean(BrowserRoot.EXTRA_SUGGESTED, true);
+ mBrowserInfo = new RemoteUserInfo(
+ getInstrumentation().getTargetContext().getPackageName(),
+ Process.myPid(),
+ Process.myUid());
+ mOnChildrenLoadedLatch.reset();
+ mOnChildrenLoadedWithOptionsLatch.reset();
+ mOnItemLoadedLatch.reset();
+
+ final CountDownLatch onConnectedLatch = new CountDownLatch(1);
+ getInstrumentation().runOnMainSync(()-> {
+ mMediaBrowser = new MediaBrowser(getInstrumentation().getTargetContext(),
+ TEST_BROWSER_SERVICE, new MediaBrowser.ConnectionCallback() {
+ @Override
+ public void onConnected() {
+ mMediaBrowserService = StubMediaBrowserService.sInstance;
+ onConnectedLatch.countDown();
+ }
+ }, mRootHints);
mMediaBrowser.connect();
- mWaitLock.wait(TIME_OUT_MS);
- }
+ });
+ assertTrue(onConnectedLatch.await(TIME_OUT_MS, TimeUnit.MILLISECONDS));
assertNotNull(mMediaBrowserService);
}
@Override
public void tearDown() {
- if (mMediaBrowser != null) {
- mMediaBrowser.disconnect();
- mMediaBrowser = null;
- }
+ getInstrumentation().runOnMainSync(()-> {
+ if (mMediaBrowser != null) {
+ mMediaBrowser.disconnect();
+ mMediaBrowser = null;
+ }
+ });
}
public void testGetSessionToken() {
@@ -151,16 +141,14 @@
}
public void testNotifyChildrenChanged() throws Exception {
- synchronized (mWaitLock) {
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoaded);
+ });
+ assertTrue(mOnChildrenLoadedLatch.await(TIME_OUT_MS));
- mOnChildrenLoaded = false;
- mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoaded);
- }
+ mOnChildrenLoadedLatch.reset();
+ mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
+ assertTrue(mOnChildrenLoadedLatch.await(TIME_OUT_MS));
}
public void testNotifyChildrenChangedWithNullOptionsThrowsIAE() {
@@ -173,103 +161,91 @@
}
}
- public void testNotifyChildrenChangedWithPagination() throws Exception {
- synchronized (mWaitLock) {
- final int pageSize = 5;
- final int page = 2;
- Bundle options = new Bundle();
- options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
- options.putInt(MediaBrowser.EXTRA_PAGE, page);
+ public void testNotifyChildrenChangedWithPagination() {
+ final int pageSize = 5;
+ final int page = 2;
+ Bundle options = new Bundle();
+ options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+ options.putInt(MediaBrowser.EXTRA_PAGE, page);
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
mSubscriptionCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoadedWithOptions);
+ });
+ assertTrue(mOnChildrenLoadedWithOptionsLatch.await(TIME_OUT_MS));
- mOnChildrenLoadedWithOptions = false;
- mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoadedWithOptions);
+ mOnChildrenLoadedWithOptionsLatch.reset();
+ mMediaBrowserService.notifyChildrenChanged(StubMediaBrowserService.MEDIA_ID_ROOT);
+ assertTrue(mOnChildrenLoadedWithOptionsLatch.await(TIME_OUT_MS));
- // Notify that the items overlapping with the given options are changed.
- mOnChildrenLoadedWithOptions = false;
- final int newPageSize = 3;
- final int overlappingNewPage = pageSize * page / newPageSize;
- Bundle overlappingOptions = new Bundle();
- overlappingOptions.putInt(MediaBrowser.EXTRA_PAGE_SIZE, newPageSize);
- overlappingOptions.putInt(MediaBrowser.EXTRA_PAGE, overlappingNewPage);
- mMediaBrowserService.notifyChildrenChanged(
- StubMediaBrowserService.MEDIA_ID_ROOT, overlappingOptions);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoadedWithOptions);
+ // Notify that the items overlapping with the given options are changed.
+ mOnChildrenLoadedWithOptionsLatch.reset();
+ final int newPageSize = 3;
+ final int overlappingNewPage = pageSize * page / newPageSize;
+ Bundle overlappingOptions = new Bundle();
+ overlappingOptions.putInt(MediaBrowser.EXTRA_PAGE_SIZE, newPageSize);
+ overlappingOptions.putInt(MediaBrowser.EXTRA_PAGE, overlappingNewPage);
+ mMediaBrowserService.notifyChildrenChanged(
+ StubMediaBrowserService.MEDIA_ID_ROOT, overlappingOptions);
+ assertTrue(mOnChildrenLoadedWithOptionsLatch.await(TIME_OUT_MS));
- // Notify that the items non-overlapping with the given options are changed.
- mOnChildrenLoadedWithOptions = false;
- Bundle nonOverlappingOptions = new Bundle();
- nonOverlappingOptions.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
- nonOverlappingOptions.putInt(MediaBrowser.EXTRA_PAGE, page + 1);
- mMediaBrowserService.notifyChildrenChanged(
- StubMediaBrowserService.MEDIA_ID_ROOT, nonOverlappingOptions);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mOnChildrenLoadedWithOptions);
- }
+ // Notify that the items non-overlapping with the given options are changed.
+ mOnChildrenLoadedWithOptionsLatch.reset();
+ Bundle nonOverlappingOptions = new Bundle();
+ nonOverlappingOptions.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
+ nonOverlappingOptions.putInt(MediaBrowser.EXTRA_PAGE, page + 1);
+ mMediaBrowserService.notifyChildrenChanged(
+ StubMediaBrowserService.MEDIA_ID_ROOT, nonOverlappingOptions);
+ assertFalse(mOnChildrenLoadedWithOptionsLatch.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
}
public void testDelayedNotifyChildrenChanged() throws Exception {
- synchronized (mWaitLock) {
- mOnChildrenLoaded = false;
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
mSubscriptionCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mOnChildrenLoaded);
+ });
+ assertFalse(mOnChildrenLoadedLatch.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
- mMediaBrowserService.sendDelayedNotifyChildrenChanged();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoaded);
+ mMediaBrowserService.sendDelayedNotifyChildrenChanged();
+ assertTrue(mOnChildrenLoadedLatch.await(TIME_OUT_MS));
- mOnChildrenLoaded = false;
- mMediaBrowserService.notifyChildrenChanged(
- StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mOnChildrenLoaded);
+ mOnChildrenLoadedLatch.reset();
+ mMediaBrowserService.notifyChildrenChanged(
+ StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED);
+ assertFalse(mOnChildrenLoadedLatch.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
- mMediaBrowserService.sendDelayedNotifyChildrenChanged();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoaded);
- }
+ mMediaBrowserService.sendDelayedNotifyChildrenChanged();
+ assertTrue(mOnChildrenLoadedLatch.await(TIME_OUT_MS));
}
public void testDelayedItem() throws Exception {
- synchronized (mWaitLock) {
- mOnItemLoaded = false;
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN_DELAYED,
mItemCallback);
- mWaitLock.wait(WAIT_TIME_FOR_NO_RESPONSE_MS);
- assertFalse(mOnItemLoaded);
+ });
+ assertFalse(mOnItemLoadedLatch.await(WAIT_TIME_FOR_NO_RESPONSE_MS));
- mMediaBrowserService.sendDelayedItemLoaded();
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnItemLoaded);
- }
+ mMediaBrowserService.sendDelayedItemLoaded();
+ assertTrue(mOnItemLoadedLatch.await(TIME_OUT_MS));
}
public void testGetBrowserInfo() throws Exception {
- synchronized (mWaitLock) {
- // StubMediaBrowserService stores the browser info in its onGetRoot().
- assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
+ // StubMediaBrowserService stores the browser info in its onGetRoot().
+ assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
- StubMediaBrowserService.clearBrowserInfo();
+ StubMediaBrowserService.clearBrowserInfo();
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnChildrenLoaded);
- assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
+ });
+ assertTrue(mOnChildrenLoadedLatch.await(TIME_OUT_MS));
+ assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
- StubMediaBrowserService.clearBrowserInfo();
+ StubMediaBrowserService.clearBrowserInfo();
+ getInstrumentation().runOnMainSync(()-> {
mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
- mWaitLock.wait(TIME_OUT_MS);
- assertTrue(mOnItemLoaded);
- assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
- }
+ });
+ assertTrue(mOnItemLoadedLatch.await(TIME_OUT_MS));
+ assertTrue(compareRemoteUserInfo(mBrowserInfo, StubMediaBrowserService.sBrowserInfo));
}
public void testBrowserRoot() {
@@ -329,4 +305,28 @@
assertEquals(mRootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED),
rootHints.getBoolean(BrowserRoot.EXTRA_SUGGESTED));
}
+
+ private static class TestCountDownLatch {
+ private CountDownLatch mLatch;
+
+ TestCountDownLatch() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ void reset() {
+ mLatch = new CountDownLatch(1);
+ }
+
+ void countDown() {
+ mLatch.countDown();
+ }
+
+ boolean await(long timeoutMs) {
+ try {
+ return mLatch.await(timeoutMs, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ return false;
+ }
+ }
+ }
}
diff --git a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
index fc832fb..8f3d299 100644
--- a/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaBrowserTest.java
@@ -25,6 +25,7 @@
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
/**
* Test {@link android.media.browse.MediaBrowser}.
@@ -57,86 +58,107 @@
@Override
public void tearDown() {
if (mMediaBrowser != null) {
- mMediaBrowser.disconnect();
+ try {
+ disconnectMediaBrowser();
+ } catch (Throwable t) {
+ // Ignore.
+ }
mMediaBrowser = null;
}
}
- public void testMediaBrowser() {
+ public void testMediaBrowser() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
- assertEquals(false, mMediaBrowser.isConnected());
+ runOnMainThread(() -> {
+ assertEquals(false, mMediaBrowser.isConnected());
+ });
connectMediaBrowserService();
- assertEquals(true, mMediaBrowser.isConnected());
+ runOnMainThread(() -> {
+ assertEquals(true, mMediaBrowser.isConnected());
+ });
- assertEquals(TEST_BROWSER_SERVICE, mMediaBrowser.getServiceComponent());
- assertEquals(StubMediaBrowserService.MEDIA_ID_ROOT, mMediaBrowser.getRoot());
- assertEquals(StubMediaBrowserService.EXTRAS_VALUE,
- mMediaBrowser.getExtras().getString(StubMediaBrowserService.EXTRAS_KEY));
- assertEquals(StubMediaBrowserService.sSession.getSessionToken(),
- mMediaBrowser.getSessionToken());
+ runOnMainThread(() -> {
+ assertEquals(TEST_BROWSER_SERVICE, mMediaBrowser.getServiceComponent());
+ assertEquals(StubMediaBrowserService.MEDIA_ID_ROOT, mMediaBrowser.getRoot());
+ assertEquals(StubMediaBrowserService.EXTRAS_VALUE,
+ mMediaBrowser.getExtras().getString(StubMediaBrowserService.EXTRAS_KEY));
+ assertEquals(StubMediaBrowserService.sSession.getSessionToken(),
+ mMediaBrowser.getSessionToken());
+ });
- mMediaBrowser.disconnect();
- new PollingCheck(TIME_OUT_MS) {
- @Override
- protected boolean check() {
- return !mMediaBrowser.isConnected();
+ disconnectMediaBrowser();
+ runOnMainThread(() -> {
+ new PollingCheck(TIME_OUT_MS) {
+ @Override
+ protected boolean check() {
+ return !mMediaBrowser.isConnected();
+ }
+ }.run();
+ });
+ }
+
+ public void testThrowingISEWhileNotConnected() throws Throwable {
+ resetCallbacks();
+ createMediaBrowser(TEST_BROWSER_SERVICE);
+ runOnMainThread(() -> {
+ assertEquals(false, mMediaBrowser.isConnected());
+ });
+
+ runOnMainThread(() -> {
+ try {
+ mMediaBrowser.getExtras();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
}
- }.run();
+
+ try {
+ mMediaBrowser.getRoot();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ try {
+ mMediaBrowser.getServiceComponent();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+
+ try {
+ mMediaBrowser.getSessionToken();
+ fail();
+ } catch (IllegalStateException e) {
+ // Expected
+ }
+ });
}
- public void testThrowingISEWhileNotConnected() {
- resetCallbacks();
- createMediaBrowser(TEST_BROWSER_SERVICE);
- assertEquals(false, mMediaBrowser.isConnected());
-
- try {
- mMediaBrowser.getExtras();
- fail();
- } catch (IllegalStateException e) {
- // Expected
- }
-
- try {
- mMediaBrowser.getRoot();
- fail();
- } catch (IllegalStateException e) {
- // Expected
- }
-
- try {
- mMediaBrowser.getServiceComponent();
- fail();
- } catch (IllegalStateException e) {
- // Expected
- }
-
- try {
- mMediaBrowser.getSessionToken();
- fail();
- } catch (IllegalStateException e) {
- // Expected
- }
- }
-
- public void testConnectTwice() {
+ public void testConnectTwice() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- try {
- mMediaBrowser.connect();
- fail();
- } catch (IllegalStateException e) {
- // expected
- }
+ runOnMainThread(() -> {
+ try {
+ mMediaBrowser.connect();
+ fail();
+ } catch (IllegalStateException e) {
+ // expected
+ }
+ });
}
- public void testConnectionFailed() {
+ public void testConnectionFailed() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_INVALID_BROWSER_SERVICE);
- mMediaBrowser.connect();
+ runOnMainThread(() -> {
+ mMediaBrowser.connect();
+ });
+
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -147,18 +169,22 @@
}.run();
}
- public void testReconnection() {
+ public void testReconnection() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
- // Reconnect before the first connection was established.
- mMediaBrowser.connect();
- mMediaBrowser.disconnect();
+ runOnMainThread(() -> {
+ // Reconnect before the first connection was established.
+ mMediaBrowser.connect();
+ mMediaBrowser.disconnect();
+ });
resetCallbacks();
connectMediaBrowserService();
// Test subscribe.
resetCallbacks();
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -168,7 +194,9 @@
// Test getItem.
resetCallbacks();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -177,13 +205,15 @@
}.run();
// Reconnect after connection was established.
- mMediaBrowser.disconnect();
+ disconnectMediaBrowser();
resetCallbacks();
connectMediaBrowserService();
// Test getItem.
resetCallbacks();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -192,10 +222,12 @@
}.run();
}
- public void testConnectionCallbackNotCalledAfterDisconnect() {
+ public void testConnectionCallbackNotCalledAfterDisconnect() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
- mMediaBrowser.connect();
- mMediaBrowser.disconnect();
+ runOnMainThread(() -> {
+ mMediaBrowser.connect();
+ mMediaBrowser.disconnect();
+ });
resetCallbacks();
try {
Thread.sleep(SLEEP_MS);
@@ -207,11 +239,13 @@
assertEquals(0, mConnectionCallback.mConnectionSuspendedCount);
}
- public void testSubscribe() {
+ public void testSubscribe() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -229,7 +263,9 @@
// Test unsubscribe.
resetCallbacks();
- mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+ runOnMainThread(() -> {
+ mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+ });
// After unsubscribing, make StubMediaBrowserService notify that the children are changed.
StubMediaBrowserService.sInstance.notifyChildrenChanged(
@@ -243,44 +279,46 @@
assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
}
- public void testSubscribeWithIllegalArguments() {
+ public void testSubscribeWithIllegalArguments() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
- try {
- final String nullMediaId = null;
- mMediaBrowser.subscribe(nullMediaId, mSubscriptionCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ runOnMainThread(() -> {
+ try {
+ final String nullMediaId = null;
+ mMediaBrowser.subscribe(nullMediaId, mSubscriptionCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- final String emptyMediaId = "";
- mMediaBrowser.subscribe(emptyMediaId, mSubscriptionCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ final String emptyMediaId = "";
+ mMediaBrowser.subscribe(emptyMediaId, mSubscriptionCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- final MediaBrowser.SubscriptionCallback nullCallback = null;
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ final MediaBrowser.SubscriptionCallback nullCallback = null;
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- final Bundle nullOptions = null;
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullOptions,
- mSubscriptionCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ final Bundle nullOptions = null;
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullOptions,
+ mSubscriptionCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ });
}
- public void testSubscribeWithOptions() {
+ public void testSubscribeWithOptions() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
final int pageSize = 3;
@@ -290,8 +328,10 @@
for (int page = 0; page <= lastPage; ++page) {
resetCallbacks();
options.putInt(MediaBrowser.EXTRA_PAGE, page);
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
- mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options,
+ mSubscriptionCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -315,7 +355,9 @@
// Test unsubscribe with callback argument.
resetCallbacks();
- mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ });
// After unsubscribing, make StubMediaBrowserService notify that the children are changed.
StubMediaBrowserService.sInstance.notifyChildrenChanged(
@@ -329,11 +371,14 @@
assertEquals(0, mSubscriptionCallback.mChildrenLoadedCount);
}
- public void testSubscribeInvalidItem() {
+ public void testSubscribeInvalidItem() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_INVALID, mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(
+ StubMediaBrowserService.MEDIA_ID_INVALID, mSubscriptionCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -344,7 +389,7 @@
assertEquals(StubMediaBrowserService.MEDIA_ID_INVALID, mSubscriptionCallback.mLastErrorId);
}
- public void testSubscribeInvalidItemWithOptions() {
+ public void testSubscribeInvalidItemWithOptions() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
@@ -354,8 +399,10 @@
Bundle options = new Bundle();
options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
options.putInt(MediaBrowser.EXTRA_PAGE, page);
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_INVALID, options,
- mSubscriptionCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_INVALID, options,
+ mSubscriptionCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -369,11 +416,13 @@
mSubscriptionCallback.mLastOptions.getInt(MediaBrowser.EXTRA_PAGE_SIZE));
}
- public void testSubscriptionCallbackNotCalledAfterDisconnect() {
+ public void testSubscriptionCallbackNotCalledAfterDisconnect() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
- mMediaBrowser.disconnect();
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, mSubscriptionCallback);
+ mMediaBrowser.disconnect();
+ });
resetCallbacks();
StubMediaBrowserService.sInstance.notifyChildrenChanged(
StubMediaBrowserService.MEDIA_ID_ROOT);
@@ -387,35 +436,36 @@
assertNull(mSubscriptionCallback.mLastParentId);
}
- public void testUnsubscribeWithIllegalArguments() {
+ public void testUnsubscribeWithIllegalArguments() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
+ runOnMainThread(() -> {
+ try {
+ final String nullMediaId = null;
+ mMediaBrowser.unsubscribe(nullMediaId);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- final String nullMediaId = null;
- mMediaBrowser.unsubscribe(nullMediaId);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ final String emptyMediaId = "";
+ mMediaBrowser.unsubscribe(emptyMediaId);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- final String emptyMediaId = "";
- mMediaBrowser.unsubscribe(emptyMediaId);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
-
- try {
- final MediaBrowser.SubscriptionCallback nullCallback = null;
- mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ final MediaBrowser.SubscriptionCallback nullCallback = null;
+ mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT, nullCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ });
}
- public void testUnsubscribeForMultipleSubscriptions() {
+ public void testUnsubscribeForMultipleSubscriptions() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
@@ -429,7 +479,9 @@
Bundle options = new Bundle();
options.putInt(MediaBrowser.EXTRA_PAGE, page);
options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+ });
// Each onChildrenLoaded() must be called.
new PollingCheck(TIME_OUT_MS) {
@@ -444,7 +496,9 @@
for (StubSubscriptionCallback callback : subscriptionCallbacks) {
callback.reset();
}
- mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+ runOnMainThread(() -> {
+ mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT);
+ });
// After unsubscribing, make StubMediaBrowserService notify that the children are changed.
StubMediaBrowserService.sInstance.notifyChildrenChanged(
@@ -461,7 +515,7 @@
}
}
- public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() {
+ public void testUnsubscribeWithSubscriptionCallbackForMultipleSubscriptions() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
final List<StubSubscriptionCallback> subscriptionCallbacks = new ArrayList<>();
@@ -475,7 +529,9 @@
Bundle options = new Bundle();
options.putInt(MediaBrowser.EXTRA_PAGE, page);
options.putInt(MediaBrowser.EXTRA_PAGE_SIZE, pageSize);
- mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+ runOnMainThread(() -> {
+ mMediaBrowser.subscribe(StubMediaBrowserService.MEDIA_ID_ROOT, options, callback);
+ });
// Each onChildrenLoaded() must be called.
new PollingCheck(TIME_OUT_MS) {
@@ -494,9 +550,12 @@
callback.reset();
}
- // Remove one subscription
- mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT,
- subscriptionCallbacks.get(orderOfRemovingCallbacks[i]));
+ final int index = i;
+ runOnMainThread(() -> {
+ // Remove one subscription
+ mMediaBrowser.unsubscribe(StubMediaBrowserService.MEDIA_ID_ROOT,
+ subscriptionCallbacks.get(orderOfRemovingCallbacks[index]));
+ });
// Make StubMediaBrowserService notify that the children are changed.
StubMediaBrowserService.sInstance.notifyChildrenChanged(
@@ -520,11 +579,14 @@
}
}
- public void testGetItem() {
+ public void testGetItem() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -536,41 +598,45 @@
mItemCallback.mLastMediaItem.getMediaId());
}
- public void testGetItemThrowsIAE() {
+ public void testGetItemThrowsIAE() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
- try {
- // Calling getItem() with empty mediaId will throw IAE.
- mMediaBrowser.getItem("", mItemCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ runOnMainThread(() -> {
+ try {
+ // Calling getItem() with empty mediaId will throw IAE.
+ mMediaBrowser.getItem("", mItemCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- // Calling getItem() with null mediaId will throw IAE.
- mMediaBrowser.getItem(null, mItemCallback);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ // Calling getItem() with null mediaId will throw IAE.
+ mMediaBrowser.getItem(null, mItemCallback);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
- try {
- // Calling getItem() with null itemCallback will throw IAE.
- mMediaBrowser.getItem("media_id", null);
- fail();
- } catch (IllegalArgumentException e) {
- // Expected
- }
+ try {
+ // Calling getItem() with null itemCallback will throw IAE.
+ mMediaBrowser.getItem("media_id", null);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // Expected
+ }
+ });
}
- public void testGetItemWhileNotConnected() {
+ public void testGetItemWhileNotConnected() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
final String mediaId = "test_media_id";
- mMediaBrowser.getItem(mediaId, mItemCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(mediaId, mItemCallback);
+ });
// Calling getItem while not connected will invoke ItemCallback.onError().
new PollingCheck(TIME_OUT_MS) {
@@ -583,11 +649,13 @@
assertEquals(mItemCallback.mLastErrorId, mediaId);
}
- public void testGetItemFailure() {
+ public void testGetItemFailure() throws Throwable {
resetCallbacks();
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_INVALID, mItemCallback);
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_INVALID, mItemCallback);
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -598,11 +666,13 @@
assertEquals(StubMediaBrowserService.MEDIA_ID_INVALID, mItemCallback.mLastErrorId);
}
- public void testItemCallbackNotCalledAfterDisconnect() {
+ public void testItemCallbackNotCalledAfterDisconnect() throws Throwable {
createMediaBrowser(TEST_BROWSER_SERVICE);
connectMediaBrowserService();
- mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
- mMediaBrowser.disconnect();
+ runOnMainThread(() -> {
+ mMediaBrowser.getItem(StubMediaBrowserService.MEDIA_ID_CHILDREN[0], mItemCallback);
+ mMediaBrowser.disconnect();
+ });
resetCallbacks();
try {
Thread.sleep(SLEEP_MS);
@@ -613,18 +683,17 @@
assertNull(mItemCallback.mLastErrorId);
}
- private void createMediaBrowser(final ComponentName component) {
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mMediaBrowser = new MediaBrowser(getInstrumentation().getTargetContext(),
- component, mConnectionCallback, null);
- }
+ private void createMediaBrowser(final ComponentName component) throws Throwable {
+ runOnMainThread(() -> {
+ mMediaBrowser = new MediaBrowser(getInstrumentation().getTargetContext(),
+ component, mConnectionCallback, null);
});
}
- private void connectMediaBrowserService() {
- mMediaBrowser.connect();
+ private void connectMediaBrowserService() throws Throwable {
+ runOnMainThread(() -> {
+ mMediaBrowser.connect();
+ });
new PollingCheck(TIME_OUT_MS) {
@Override
protected boolean check() {
@@ -633,12 +702,35 @@
}.run();
}
+ private void disconnectMediaBrowser() throws Throwable {
+ runOnMainThread(() -> {
+ mMediaBrowser.disconnect();
+ });
+ }
+
private void resetCallbacks() {
mConnectionCallback.reset();
mSubscriptionCallback.reset();
mItemCallback.reset();
}
+ private void runOnMainThread(Runnable runnable) throws Throwable {
+ AtomicReference<Throwable> throwableRef = new AtomicReference<>();
+
+ getInstrumentation().runOnMainSync(() -> {
+ try {
+ runnable.run();
+ } catch (Throwable t) {
+ throwableRef.set(t);
+ }
+ });
+
+ Throwable t = throwableRef.get();
+ if (t != null) {
+ throw t;
+ }
+ }
+
private static class StubConnectionCallback extends MediaBrowser.ConnectionCallback {
volatile int mConnectedCount;
volatile int mConnectionFailedCount;
diff --git a/tests/tests/media/src/android/media/cts/MediaMetadataTest.java b/tests/tests/media/src/android/media/cts/MediaMetadataTest.java
index 0483c9d..ed7e0a3 100644
--- a/tests/tests/media/src/android/media/cts/MediaMetadataTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaMetadataTest.java
@@ -21,7 +21,11 @@
import static org.junit.Assert.fail;
import android.graphics.Bitmap;
+import android.media.MediaDescription;
import android.media.MediaMetadata;
+import android.media.Rating;
+import android.os.Parcel;
+import android.text.TextUtils;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
@@ -29,16 +33,246 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.Set;
+
/**
* Tests {@link MediaMetadata}.
*/
-// TODO(b/168668505): Add tests for other methods.
@SmallTest
@RunWith(AndroidJUnit4.class)
@NonMediaMainlineTest
public class MediaMetadataTest {
@Test
+ public void builder_defaultConstructor_hasNoData() {
+ MediaMetadata metadata = new MediaMetadata.Builder().build();
+
+ assertEquals(0, metadata.size());
+ assertTrue(metadata.keySet().isEmpty());
+ }
+
+ @Test
+ public void builder_putText() {
+ String testTitle = "test_title";
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putText(MediaMetadata.METADATA_KEY_TITLE, testTitle)
+ .build();
+
+ assertTrue(metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE));
+ CharSequence titleOut = metadata.getText(MediaMetadata.METADATA_KEY_TITLE);
+ assertTrue(TextUtils.equals(testTitle, titleOut));
+ }
+
+ @Test
+ public void builder_putString() {
+ String testTitle = "test_title";
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_TITLE, testTitle)
+ .build();
+
+ assertTrue(metadata.containsKey(MediaMetadata.METADATA_KEY_TITLE));
+ String titleOut = metadata.getString(MediaMetadata.METADATA_KEY_TITLE);
+ assertTrue(TextUtils.equals(testTitle, titleOut));
+ }
+
+ @Test
+ public void builder_putLong() {
+ long testYear = 2021;
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+
+ assertTrue(metadata.containsKey(MediaMetadata.METADATA_KEY_YEAR));
+ long yearOut = metadata.getLong(MediaMetadata.METADATA_KEY_YEAR);
+ assertEquals(testYear, yearOut);
+ }
+
+ @Test
+ public void builder_putRating() {
+ Rating testHeartRating = Rating.newHeartRating(/*hasHeart=*/ true);
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putRating(MediaMetadata.METADATA_KEY_RATING, testHeartRating)
+ .build();
+
+ assertTrue(metadata.containsKey(MediaMetadata.METADATA_KEY_RATING));
+ Rating ratingOut = metadata.getRating(MediaMetadata.METADATA_KEY_RATING);
+ assertEquals(testHeartRating, ratingOut);
+ }
+
+ @Test
+ public void builder_putText_throwsIAE_withNonTextKey() {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ try {
+ builder.putText(MediaMetadata.METADATA_KEY_YEAR, "test");
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void builder_putString_throwsIAE_withNonTextKey() {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ try {
+ builder.putString(MediaMetadata.METADATA_KEY_YEAR, "test");
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void builder_putLong_throwsIAE_withNonLongKey() {
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ try {
+ builder.putLong(MediaMetadata.METADATA_KEY_TITLE, 2021);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void builder_putRating_throwsIAE_withNonRatingKey() {
+ Rating testHeartRating = Rating.newHeartRating(/*hasHeart=*/ true);
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ try {
+ builder.putRating(MediaMetadata.METADATA_KEY_TITLE, testHeartRating);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void builder_putBitmap_throwsIAE_withNonBitmapKey() {
+ Bitmap testBitmap = Bitmap.createBitmap(/*width=*/ 16, /*height=*/16,
+ Bitmap.Config.ARGB_8888);
+ MediaMetadata.Builder builder = new MediaMetadata.Builder();
+ try {
+ builder.putBitmap(MediaMetadata.METADATA_KEY_TITLE, testBitmap);
+ fail();
+ } catch (IllegalArgumentException e) {
+ // expected
+ }
+ }
+
+ @Test
+ public void builder_copyConstructor() {
+ long testYear = 2021;
+ MediaMetadata originalMetadata = new MediaMetadata.Builder()
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+
+ MediaMetadata copiedMetadata = new MediaMetadata.Builder(originalMetadata).build();
+ assertEquals(originalMetadata, copiedMetadata);
+ }
+
+ @Test
+ public void equalsAndHashCode() {
+ String testTitle = "test_title";
+ long testYear = 2021;
+ MediaMetadata originalMetadata = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_TITLE, testTitle)
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+ MediaMetadata metadataToCompare = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_TITLE, testTitle)
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+
+ assertEquals(originalMetadata, metadataToCompare);
+ assertEquals(originalMetadata.hashCode(), metadataToCompare.hashCode());
+ }
+
+ @Test
+ public void equalsAndHashCode_ignoreRatingAndBitmap() {
+ Rating testHeartRating = Rating.newHeartRating(/*hasHeart=*/ true);
+ Bitmap testBitmap = Bitmap.createBitmap(/*width=*/ 16, /*height=*/16,
+ Bitmap.Config.ARGB_8888);
+ MediaMetadata originalMetadata = new MediaMetadata.Builder()
+ .putRating(MediaMetadata.METADATA_KEY_RATING, testHeartRating)
+ .putBitmap(MediaMetadata.METADATA_KEY_ART, testBitmap)
+ .build();
+ MediaMetadata emptyMetadata = new MediaMetadata.Builder().build();
+
+ assertEquals(originalMetadata, emptyMetadata);
+ assertEquals(originalMetadata.hashCode(), emptyMetadata.hashCode());
+ }
+
+ @Test
+ public void sizeAndKeySet() {
+ Rating testHeartRating = Rating.newHeartRating(/*hasHeart=*/ true);
+ Bitmap testBitmap = Bitmap.createBitmap(/*width=*/ 16, /*height=*/16,
+ Bitmap.Config.ARGB_8888);
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putRating(MediaMetadata.METADATA_KEY_RATING, testHeartRating)
+ .putBitmap(MediaMetadata.METADATA_KEY_ART, testBitmap)
+ .build();
+
+ assertEquals(2, metadata.size());
+ Set<String> keySet = metadata.keySet();
+ assertEquals(2, keySet.size());
+ assertTrue(keySet.contains(MediaMetadata.METADATA_KEY_RATING));
+ assertTrue(keySet.contains(MediaMetadata.METADATA_KEY_ART));
+ }
+
+ @Test
+ public void describeContents() {
+ long testYear = 2021;
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+
+ assertEquals(0, metadata.describeContents());
+ }
+
+ @Test
+ public void writeToParcel() {
+ String testTitle = "test_title";
+ long testYear = 2021;
+ MediaMetadata originalMetadata = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_TITLE, testTitle)
+ .putLong(MediaMetadata.METADATA_KEY_YEAR, testYear)
+ .build();
+
+ Parcel parcel = Parcel.obtain();
+ originalMetadata.writeToParcel(parcel, 0 /* flags */);
+ parcel.setDataPosition(0);
+ MediaMetadata metadataOut = MediaMetadata.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ assertEquals(originalMetadata, metadataOut);
+ }
+
+ @Test
+ public void getDescription() {
+ String testMediaId = "media_id";
+ String testTitle = "test_title";
+ String testSubtitle = "test_subtitle";
+ String testDescription = "test_description";
+ Bitmap testIcon = Bitmap.createBitmap(/*width=*/ 16, /*height=*/16,
+ Bitmap.Config.ARGB_8888);
+ String testMediaUri = "https://www.google.com";
+ MediaMetadata metadata = new MediaMetadata.Builder()
+ .putString(MediaMetadata.METADATA_KEY_MEDIA_ID, testMediaId)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_TITLE, testTitle)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_SUBTITLE, testSubtitle)
+ .putString(MediaMetadata.METADATA_KEY_DISPLAY_DESCRIPTION, testDescription)
+ .putBitmap(MediaMetadata.METADATA_KEY_ALBUM_ART, testIcon)
+ .putString(MediaMetadata.METADATA_KEY_MEDIA_URI, testMediaUri)
+ .build();
+
+ MediaDescription mediaDescription = metadata.getDescription();
+ assertTrue(TextUtils.equals(testMediaId, mediaDescription.getMediaId()));
+ assertTrue(TextUtils.equals(testTitle, mediaDescription.getTitle()));
+ assertTrue(TextUtils.equals(testSubtitle, mediaDescription.getSubtitle()));
+ assertTrue(TextUtils.equals(testDescription, mediaDescription.getDescription()));
+ assertNotNull(mediaDescription.getIconBitmap());
+ assertTrue(TextUtils.equals(testMediaUri, mediaDescription.getMediaUri().toString()));
+ }
+
+ @Test
public void getBitmapDimensionLimit_returnsIntegerMaxWhenNotSet() {
MediaMetadata metadata = new MediaMetadata.Builder().build();
assertEquals(Integer.MAX_VALUE, metadata.getBitmapDimensionLimit());
@@ -97,7 +331,7 @@
.build();
assertEquals(testBitmapDimensionLimit, metadata.getBitmapDimensionLimit());
- // Using copy constructor, unset the limit by passing zero to the limit.
+ // Using copy constructor, unset the limit by passing Integer.MAX_VALUE to the limit.
MediaMetadata copiedMetadataWithLimitUnset = new MediaMetadata.Builder()
.setBitmapDimensionLimit(Integer.MAX_VALUE)
.build();
diff --git a/tests/tests/media/src/android/media/cts/MediaScannerTest.java b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
index eb85c42..f984381 100644
--- a/tests/tests/media/src/android/media/cts/MediaScannerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaScannerTest.java
@@ -613,17 +613,24 @@
c.close();
// also test with the MediaMetadataRetriever API
- MediaMetadataRetriever woodly = new MediaMetadataRetriever();
- AssetFileDescriptor afd = getAssetFileDescriptorFor(entry.fileName);
- woodly.setDataSource(afd.getFileDescriptor(),
- afd.getStartOffset(), afd.getDeclaredLength());
+ String[] actual;
+ try (MediaMetadataRetriever metadataRetriever = new MediaMetadataRetriever()) {
+ AssetFileDescriptor afd = getAssetFileDescriptorFor(entry.fileName);
+ metadataRetriever.setDataSource(afd.getFileDescriptor(),
+ afd.getStartOffset(), afd.getDeclaredLength());
- String[] actual = new String[5];
- actual[0] = woodly.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);
- actual[1] = woodly.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);
- actual[2] = woodly.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
- actual[3] = woodly.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);
- actual[4] = woodly.extractMetadata(MediaMetadataRetriever.METADATA_KEY_COMPOSER);
+ actual = new String[5];
+ actual[0] = metadataRetriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_ARTIST);
+ actual[1] = metadataRetriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_ALBUM);
+ actual[2] = metadataRetriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);
+ actual[3] = metadataRetriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_TITLE);
+ actual[4] = metadataRetriever.extractMetadata(
+ MediaMetadataRetriever.METADATA_KEY_COMPOSER);
+ }
for (int j = 0; j < 5; j++) {
if ("".equals(entry.tags[j])) {
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
index 6065a0e..3349206 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionManagerTest.java
@@ -35,8 +35,10 @@
import android.os.Looper;
import android.os.Process;
import android.platform.test.annotations.AppModeFull;
+import android.provider.Settings;
import android.test.InstrumentationTestCase;
import android.test.UiThreadTest;
+import android.text.TextUtils;
import android.view.KeyEvent;
import com.android.compatibility.common.util.ApiLevelUtil;
@@ -56,7 +58,9 @@
private static final String TAG = "MediaSessionManagerTest";
private static final int TIMEOUT_MS = 3000;
private static final int WAIT_MS = 500;
+ private static final String ENABLED_NOTIFICATION_LISTENERS = "enabled_notification_listeners";
+ private Context mContext;
private AudioManager mAudioManager;
private MediaSessionManager mSessionManager;
@@ -66,6 +70,7 @@
@Override
protected void setUp() throws Exception {
super.setUp();
+ mContext = getInstrumentation().getTargetContext();
mAudioManager = (AudioManager) getInstrumentation().getTargetContext()
.getSystemService(Context.AUDIO_SERVICE);
mSessionManager = (MediaSessionManager) getInstrumentation().getTargetContext()
@@ -564,6 +569,27 @@
}
}
+ public void testIsTrustedForMediaControl_withEnabledNotificationListener() throws Exception {
+ List<String> packageNames = getEnabledNotificationListenerPackages();
+ for (String packageName : packageNames) {
+ int packageUid =
+ mContext.getPackageManager().getPackageUid(packageName, /* flags= */ 0);
+ MediaSessionManager.RemoteUserInfo info =
+ new MediaSessionManager.RemoteUserInfo(packageName, /* pid= */ 0, packageUid);
+ assertTrue(mSessionManager.isTrustedForMediaControl(info));
+ }
+ }
+
+ public void testIsTrustedForMediaControl_withInvalidUid() throws Exception {
+ List<String> packageNames = getEnabledNotificationListenerPackages();
+ for (String packageName : packageNames) {
+ MediaSessionManager.RemoteUserInfo info =
+ new MediaSessionManager.RemoteUserInfo(
+ packageName, /* pid= */ 0, Process.myUid());
+ assertFalse(mSessionManager.isTrustedForMediaControl(info));
+ }
+ }
+
private boolean listContainsToken(List<Session2Token> tokens, Session2Token token) {
for (int i = 0; i < tokens.size(); i++) {
if (tokens.get(i).equals(token)) {
@@ -596,6 +622,24 @@
new KeyEvent(downTime, System.currentTimeMillis(), KeyEvent.ACTION_UP, keyCode, 0));
}
+ private List<String> getEnabledNotificationListenerPackages() {
+ List<String> listeners = new ArrayList<>();
+ String enabledNotificationListeners =
+ Settings.Secure.getString(
+ mContext.getContentResolver(),
+ ENABLED_NOTIFICATION_LISTENERS);
+ if (!TextUtils.isEmpty(enabledNotificationListeners)) {
+ String[] components = enabledNotificationListeners.split(":");
+ for (String componentString : components) {
+ ComponentName component = ComponentName.unflattenFromString(componentString);
+ if (component != null) {
+ listeners.add(component.getPackageName());
+ }
+ }
+ }
+ return listeners;
+ }
+
private class VolumeKeyLongPressListener
implements MediaSessionManager.OnVolumeKeyLongPressListener {
private final List<KeyEvent> mKeyEvents = new ArrayList<>();
diff --git a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
index 7c3445d..7ec3e18 100644
--- a/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
+++ b/tests/tests/media/src/android/media/cts/NativeDecoderTest.java
@@ -72,7 +72,6 @@
import java.util.UUID;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import java.util.zip.Adler32;
@SmallTest
@RequiresDevice
@@ -105,94 +104,6 @@
super.tearDown();
}
- // check that native extractor behavior matches java extractor
-
- private void compareArrays(String message, int[] a1, int[] a2) {
- if (a1 == a2) {
- return;
- }
-
- assertNotNull(message + ": array 1 is null", a1);
- assertNotNull(message + ": array 2 is null", a2);
-
- assertEquals(message + ": arraylengths differ", a1.length, a2.length);
- int length = a1.length;
-
- for (int i = 0; i < length; i++)
- if (a1[i] != a2[i]) {
- Log.i("@@@@", Arrays.toString(a1));
- Log.i("@@@@", Arrays.toString(a2));
- fail(message + ": at index " + i);
- }
- }
-
- @Ignore
- @Test
- public void SKIP_testExtractor() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest#testExtract where
- // checksum is computed over track format attributes, track buffer and buffer
- // info in both SDK and NDK side and checked for equality
- testExtractor("sinesweepogg.ogg");
- testExtractor("sinesweepoggmkv.mkv");
- testExtractor("sinesweepoggmp4.mp4");
- testExtractor("sinesweepmp3lame.mp3");
- testExtractor("sinesweepmp3smpb.mp3");
- testExtractor("sinesweepopus.mkv");
- testExtractor("sinesweepopusmp4.mp4");
- testExtractor("sinesweepm4a.m4a");
- testExtractor("sinesweepflacmkv.mkv");
- testExtractor("sinesweepflac.flac");
- testExtractor("sinesweepflacmp4.mp4");
- testExtractor("sinesweepwav.wav");
-
- testExtractor("video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- testExtractor("bbb_s3_1280x720_webm_vp8_8mbps_60fps_opus_6ch_384kbps_48000hz.webm");
- testExtractor("bbb_s4_1280x720_webm_vp9_0p31_4mbps_30fps_opus_stereo_128kbps_48000hz.webm");
- testExtractor("video_1280x720_webm_av1_2000kbps_30fps_vorbis_stereo_128kbps_48000hz.webm");
- testExtractor("video_176x144_3gp_h263_300kbps_12fps_aac_mono_24kbps_11025hz.3gp");
- testExtractor("video_480x360_mp4_mpeg2_1500kbps_30fps_aac_stereo_128kbps_48000hz.mp4");
- testExtractor("video_480x360_mp4_mpeg4_860kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
-
- CtsTestServer foo = new CtsTestServer(mContext);
- testExtractor(foo.getAssetUrl("noiseandchirps.ogg"), null, null);
- testExtractor(foo.getAssetUrl("ringer.mp3"), null, null);
- testExtractor(foo.getRedirectingAssetUrl("ringer.mp3"), null, null);
-
- String[] keys = new String[] {"header0", "header1"};
- String[] values = new String[] {"value0", "value1"};
- testExtractor(foo.getAssetUrl("noiseandchirps.ogg"), keys, values);
- HttpRequest req = foo.getLastRequest("noiseandchirps.ogg");
- for (int i = 0; i < keys.length; i++) {
- String key = keys[i];
- String value = values[i];
- Header[] header = req.getHeaders(key);
- assertTrue("expecting " + key + ":" + value + ", saw " + Arrays.toString(header),
- header.length == 1 && header[0].getValue().equals(value));
- }
-
- String[] emptyArray = new String[0];
- testExtractor(foo.getAssetUrl("noiseandchirps.ogg"), emptyArray, emptyArray);
- }
-
- /**
- * |keys| and |values| should be arrays of the same length.
- *
- * If keys or values is null, test {@link MediaExtractor#setDataSource(String)}
- * and NDK counter part, i.e. set data source without headers.
- *
- * If keys or values is zero length, test {@link MediaExtractor#setDataSource(String, Map))}
- * and NDK counter part with null headers.
- *
- */
- private void testExtractor(String path, String[] keys, String[] values) throws Exception {
- int[] jsizes = getSampleSizes(path, keys, values);
- int[] nsizes = getSampleSizesNativePath(path, keys, values, /* testNativeSource = */ false);
- int[] nsizes2 = getSampleSizesNativePath(path, keys, values, /* testNativeSource = */ true);
-
- compareArrays("different samplesizes", jsizes, nsizes);
- compareArrays("different samplesizes native source", jsizes, nsizes2);
- }
-
protected static AssetFileDescriptor getAssetFileDescriptorFor(final String res)
throws FileNotFoundException {
Preconditions.assertTestFileExists(mInpPrefix + res);
@@ -202,160 +113,6 @@
return new AssetFileDescriptor(parcelFD, 0, parcelFD.getStatSize());
}
- private void testExtractor(final String res) throws Exception {
- AssetFileDescriptor fd = getAssetFileDescriptorFor(res);
-
- int[] jsizes = getSampleSizes(
- fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
- int[] nsizes = getSampleSizesNative(
- fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
-
- fd.close();
- compareArrays("different samples", jsizes, nsizes);
- }
-
- private static int[] getSampleSizes(String path, String[] keys, String[] values) throws IOException {
- MediaExtractor ex = new MediaExtractor();
- if (keys == null || values == null) {
- ex.setDataSource(path);
- } else {
- Map<String, String> headers = null;
- int numheaders = Math.min(keys.length, values.length);
- for (int i = 0; i < numheaders; i++) {
- if (headers == null) {
- headers = new HashMap<>();
- }
- String key = keys[i];
- String value = values[i];
- headers.put(key, value);
- }
- ex.setDataSource(path, headers);
- }
-
- return getSampleSizes(ex);
- }
-
- private static int[] getSampleSizes(FileDescriptor fd, long offset, long size)
- throws IOException {
- MediaExtractor ex = new MediaExtractor();
- ex.setDataSource(fd, offset, size);
- return getSampleSizes(ex);
- }
-
- private static int[] getSampleSizes(MediaExtractor ex) {
- ArrayList<Integer> foo = new ArrayList<Integer>();
- ByteBuffer buf = ByteBuffer.allocate(1024*1024);
- int numtracks = ex.getTrackCount();
- assertTrue("no tracks", numtracks > 0);
- foo.add(numtracks);
- for (int i = 0; i < numtracks; i++) {
- MediaFormat format = ex.getTrackFormat(i);
- String mime = format.getString(MediaFormat.KEY_MIME);
- if (mime.startsWith("audio/")) {
- foo.add(0);
- foo.add(format.getInteger(MediaFormat.KEY_SAMPLE_RATE));
- foo.add(format.getInteger(MediaFormat.KEY_CHANNEL_COUNT));
- foo.add((int)format.getLong(MediaFormat.KEY_DURATION));
- } else if (mime.startsWith("video/")) {
- foo.add(1);
- foo.add(format.getInteger(MediaFormat.KEY_WIDTH));
- foo.add(format.getInteger(MediaFormat.KEY_HEIGHT));
- foo.add((int)format.getLong(MediaFormat.KEY_DURATION));
- } else {
- fail("unexpected mime type: " + mime);
- }
- ex.selectTrack(i);
- }
- while(true) {
- int n = ex.readSampleData(buf, 0);
- if (n < 0) {
- break;
- }
- foo.add(n);
- foo.add(ex.getSampleTrackIndex());
- foo.add(ex.getSampleFlags());
- foo.add((int)ex.getSampleTime()); // just the low bits should be OK
- byte[] foobar = new byte[n];
- buf.get(foobar, 0, n);
- foo.add(adler32(foobar));
- ex.advance();
- }
-
- int [] ret = new int[foo.size()];
- for (int i = 0; i < ret.length; i++) {
- ret[i] = foo.get(i);
- }
- return ret;
- }
-
- private static native int[] getSampleSizesNative(int fd, long offset, long size);
- private static native int[] getSampleSizesNativePath(
- String path, String[] keys, String[] values, boolean testNativeSource);
-
- @Presubmit
- @Ignore
- @Test
- public void SKIP_testExtractorFileDurationNative() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$FunctionalityTest#testExtract where
- // checksum is computed over track format attributes, track buffer and buffer
- // info in both SDK and NDK side and checked for equality. KEY_DURATION for each track is
- // part of the checksum.
- testExtractorFileDurationNative(
- "video_1280x720_mp4_h264_1000kbps_25fps_aac_stereo_128kbps_44100hz.mp4");
- }
-
- private void testExtractorFileDurationNative(final String res) throws Exception {
- AssetFileDescriptor fd = getAssetFileDescriptorFor(res);
- long durationUs = getExtractorFileDurationNative(
- fd.getParcelFileDescriptor().getFd(), fd.getStartOffset(), fd.getLength());
-
- MediaExtractor ex = new MediaExtractor();
- ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
-
- int numtracks = ex.getTrackCount();
- long aDurationUs = -1, vDurationUs = -1;
- for (int i = 0; i < numtracks; i++) {
- MediaFormat format = ex.getTrackFormat(i);
- String mime = format.getString(MediaFormat.KEY_MIME);
- if (mime.startsWith("audio/")) {
- aDurationUs = format.getLong(MediaFormat.KEY_DURATION);
- } else if (mime.startsWith("video/")) {
- vDurationUs = format.getLong(MediaFormat.KEY_DURATION);
- }
- }
-
- assertTrue("duration inconsistency",
- durationUs < 0 || durationUs >= aDurationUs && durationUs >= vDurationUs);
-
- }
-
- private static native long getExtractorFileDurationNative(int fd, long offset, long size);
-
- @Presubmit
- public void SKIP_testExtractorCachedDurationNative() throws Exception {
- // duplicate of CtsMediaV2TestCases:ExtractorTest$SetDataSourceTest#testDataSourceNative
- CtsTestServer foo = new CtsTestServer(mContext);
- String url = foo.getAssetUrl("ringer.mp3");
- long cachedDurationUs = getExtractorCachedDurationNative(url, /* testNativeSource = */ false);
- assertTrue("cached duration negative", cachedDurationUs >= 0);
- cachedDurationUs = getExtractorCachedDurationNative(url, /* testNativeSource = */ true);
- assertTrue("cached duration negative native source", cachedDurationUs >= 0);
- }
-
- private static native long getExtractorCachedDurationNative(String uri, boolean testNativeSource);
-
-
-
- private final static Adler32 checksummer = new Adler32();
- // simple checksum computed over every decoded buffer
- static int adler32(byte[] input) {
- checksummer.reset();
- checksummer.update(input);
- int ret = (int) checksummer.getValue();
- Log.i("@@@", "adler " + input.length + "/" + ret);
- return ret;
- }
-
@Presubmit
@Test
public void testFormat() throws Exception {
diff --git a/tests/tests/media/src/android/media/cts/VideoEditorTest.java b/tests/tests/media/src/android/media/cts/VideoEditorTest.java
deleted file mode 100644
index b95431e..0000000
--- a/tests/tests/media/src/android/media/cts/VideoEditorTest.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.media.cts;
-
-import android.media.cts.R;
-
-import android.platform.test.annotations.AppModeFull;
-import android.test.ActivityInstrumentationTestCase2;
-
-@AppModeFull(reason = "TODO: evaluate and port to instant")
-public class VideoEditorTest extends ActivityInstrumentationTestCase2<MediaStubActivity> {
-
- public VideoEditorTest() {
- super(MediaStubActivity.class);
- }
-
- @Override
- protected void setUp() throws Exception {
- //setup for each test case.
- super.setUp();
- }
-
- @Override
- protected void tearDown() throws Exception {
- //Test case clean up.
- super.tearDown();
- }
-}
diff --git a/tests/tests/mediastress/src/android/mediastress/cts/CodecTest.java b/tests/tests/mediastress/src/android/mediastress/cts/CodecTest.java
index b33259f..fbf5cd9 100644
--- a/tests/tests/mediastress/src/android/mediastress/cts/CodecTest.java
+++ b/tests/tests/mediastress/src/android/mediastress/cts/CodecTest.java
@@ -507,14 +507,16 @@
try {
BitmapFactory mBitmapFactory = new BitmapFactory();
- MediaMetadataRetriever mMediaMetadataRetriever = new MediaMetadataRetriever();
- try {
- mMediaMetadataRetriever.setDataSource(filePath);
- } catch(Exception e) {
- e.printStackTrace();
- return false;
+ Bitmap outThumbnail;
+ try (MediaMetadataRetriever mediaMetadataRetriever = new MediaMetadataRetriever()) {
+ try {
+ mediaMetadataRetriever.setDataSource(filePath);
+ } catch (Exception e) {
+ e.printStackTrace();
+ return false;
+ }
+ outThumbnail = mediaMetadataRetriever.getFrameAtTime(-1);
}
- Bitmap outThumbnail = mMediaMetadataRetriever.getFrameAtTime(-1);
//Verify the thumbnail
Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath);
diff --git a/tests/tests/net/OWNERS b/tests/tests/net/OWNERS
new file mode 100644
index 0000000..8dfa455
--- /dev/null
+++ b/tests/tests/net/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 31808
+set noparent
+file:platform/packages/modules/Connectivity:master:/OWNERS_core_networking_xts
diff --git a/tests/tests/net/native/Android.bp b/tests/tests/net/native/Android.bp
new file mode 100644
index 0000000..06ae4d2
--- /dev/null
+++ b/tests/tests/net/native/Android.bp
@@ -0,0 +1,63 @@
+// Copyright (C) 2022 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+// Build the unit tests.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_test {
+ name: "CtsNativeNetPlatformTestCases",
+
+ compile_multilib: "both",
+ multilib: {
+ lib32: {
+ suffix: "32",
+ },
+ lib64: {
+ suffix: "64",
+ },
+ },
+
+ srcs: [
+ "src/TagSocketTest.cpp",
+ ],
+
+ header_libs: [
+ "bpf_headers",
+ ],
+
+ static_libs: [
+ "libbase",
+ "libutils",
+ "libnettestutils",
+ ],
+
+ shared_libs: [
+ "libandroid_net",
+ "libbinder",
+ "liblog",
+ ],
+
+ test_suites: [
+ "cts",
+ "general-tests",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/tests/tests/net/native/AndroidTest.xml b/tests/tests/net/native/AndroidTest.xml
new file mode 100644
index 0000000..8dde2cd
--- /dev/null
+++ b/tests/tests/net/native/AndroidTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright 2022 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<!-- Soong does not autogenerate test config files for tests tagged with "cts". -->
+<configuration description="Config for CTS Native Network Platform test cases">
+ <option name="test-suite-tag" value="cts" />
+ <option name="config-descriptor:metadata" key="component" value="networking" />
+ <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+ <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
+ <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
+ <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher">
+ <option name="cleanup" value="true" />
+ <option name="push" value="CtsNativeNetPlatformTestCases->/data/local/tmp/CtsNativeNetPlatformTestCases" />
+ <option name="append-bitness" value="true" />
+ </target_preparer>
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="CtsNativeNetPlatformTestCases" />
+ <option name="runtime-hint" value="1m" />
+ </test>
+</configuration>
diff --git a/tests/tests/net/native/src/TagSocketTest.cpp b/tests/tests/net/native/src/TagSocketTest.cpp
new file mode 100644
index 0000000..9826747
--- /dev/null
+++ b/tests/tests/net/native/src/TagSocketTest.cpp
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless requied by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include <android-base/format.h>
+#include <android/multinetwork.h>
+#include <binder/IServiceManager.h>
+#include <bpf/BpfUtils.h>
+#include <gtest/gtest.h>
+#include <nettestutils/DumpService.h>
+
+using android::IBinder;
+using android::IServiceManager;
+using android::bpf::getSocketCookie;
+using android::bpf::NONEXISTENT_COOKIE;
+using android::sp;
+using android::String16;
+using android::Vector;
+
+class TagSocketTest : public ::testing::Test {
+ public:
+ TagSocketTest() {
+ sp<IServiceManager> sm = android::defaultServiceManager();
+ mBinder = sm->getService(String16("connectivity"));
+ }
+
+ void SetUp() override { ASSERT_NE(nullptr, mBinder.get()); }
+
+ protected:
+ sp<IBinder> mBinder;
+};
+
+namespace {
+
+constexpr uid_t TEST_UID = 10086;
+constexpr uint32_t TEST_TAG = 42;
+
+[[maybe_unused]] void dumpBpfMaps(const sp<IBinder>& binder,
+ std::vector<std::string>& output) {
+ Vector<String16> vec;
+ android::status_t ret = dumpService(binder, {"trafficcontroller"}, output);
+ ASSERT_EQ(android::OK, ret)
+ << "Error dumping service: " << android::statusToString(ret);
+}
+
+[[maybe_unused]] bool socketIsTagged(const sp<IBinder>& binder, uint64_t cookie,
+ uid_t uid, uint32_t tag) {
+ std::string match =
+ fmt::format("cookie={} tag={:#x} uid={}", cookie, tag, uid);
+ std::vector<std::string> lines = {};
+ dumpBpfMaps(binder, lines);
+ for (const auto& line : lines) {
+ if (std::string::npos != line.find(match)) return true;
+ }
+ return false;
+}
+
+[[maybe_unused]] bool socketIsNotTagged(const sp<IBinder>& binder,
+ uint64_t cookie) {
+ std::string match = fmt::format("cookie={}", cookie);
+ std::vector<std::string> lines = {};
+ dumpBpfMaps(binder, lines);
+ for (const auto& line : lines) {
+ if (std::string::npos != line.find(match)) return false;
+ }
+ return true;
+}
+
+} // namespace
+
+TEST_F(TagSocketTest, TagSocket) {
+ int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_LE(0, sock);
+ uint64_t cookie = getSocketCookie(sock);
+ EXPECT_NE(NONEXISTENT_COOKIE, cookie);
+
+ // TODO(b/214338829): Uncomment lines that check tagging result from BPF map when the
+ // connectivity service is in charge of dumping BPF maps. Currently, it
+ // doesn't work because BPF maps are dumped by netd. The shell does not have
+ // permission to find netd service in user build. So, it only verify API
+ // return codes for now.
+ // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+
+ EXPECT_EQ(0, android_tag_socket(sock, TEST_TAG));
+ // EXPECT_TRUE(socketIsTagged(mBinder, cookie, geteuid(), TEST_TAG));
+ EXPECT_EQ(0, android_untag_socket(sock));
+ // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+
+ EXPECT_EQ(0, android_tag_socket_with_uid(sock, TEST_TAG, TEST_UID));
+ // EXPECT_TRUE(socketIsTagged(mBinder, cookie, TEST_UID, TEST_TAG));
+ EXPECT_EQ(0, android_untag_socket(sock));
+ // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+}
+
+TEST_F(TagSocketTest, TagSocketErrors) {
+ int sock = socket(AF_INET6, SOCK_STREAM | SOCK_CLOEXEC, 0);
+ ASSERT_LE(0, sock);
+ uint64_t cookie = getSocketCookie(sock);
+ EXPECT_NE(NONEXISTENT_COOKIE, cookie);
+
+ // Untag an untagged socket.
+ EXPECT_EQ(-ENOENT, android_untag_socket(sock));
+ // EXPECT_TRUE(socketIsNotTagged(mBinder, cookie));
+
+ // Untag a closed socket.
+ close(sock);
+ EXPECT_EQ(-EBADF, android_untag_socket(sock));
+}
diff --git a/tests/tests/neuralnetworks/Android.bp b/tests/tests/neuralnetworks/Android.bp
index a4a508f..00298e6 100644
--- a/tests/tests/neuralnetworks/Android.bp
+++ b/tests/tests/neuralnetworks/Android.bp
@@ -19,6 +19,7 @@
cc_test {
name: "CtsNNAPITestCases",
+ host_supported: true,
compile_multilib: "both",
multilib: {
lib32: {
@@ -30,23 +31,40 @@
},
whole_static_libs: ["CtsNNAPITests_static"],
shared_libs: [
- "libandroid",
"liblog",
"libneuralnetworks",
- "libvulkan",
],
- static_libs: [
- "libbase_ndk",
- "libgtest_ndk_c++",
- "libgmock_ndk",
- ],
- // Tag this module as a cts test artifact
test_suites: [
- "cts",
- "mts",
- "mts-neuralnetworks",
"general-tests",
],
+ target: {
+ android: {
+ shared_libs: [
+ "libandroid",
+ "libvulkan",
+ ],
+ static_libs: [
+ "libbase_ndk",
+ "libgtest_ndk_c++",
+ "libgmock_ndk",
+ ],
+ // Tag this module as a cts test artifact
+ test_suites: [
+ "cts",
+ "mts",
+ "mts-neuralnetworks",
+ ],
+ test_config: "AndroidTestDevice.xml",
+ },
+ host: {
+ static_libs: [
+ "libbase",
+ "libgmock",
+ "libgtest",
+ ],
+ test_config: "AndroidTestHost.xml",
+ },
+ },
sdk_version: "current",
stl: "c++_static",
min_sdk_version: "30",
diff --git a/tests/tests/neuralnetworks/AndroidTest.xml b/tests/tests/neuralnetworks/AndroidTestDevice.xml
similarity index 100%
rename from tests/tests/neuralnetworks/AndroidTest.xml
rename to tests/tests/neuralnetworks/AndroidTestDevice.xml
diff --git a/tests/tests/media/recorder/DynamicConfig.xml b/tests/tests/neuralnetworks/AndroidTestHost.xml
similarity index 61%
rename from tests/tests/media/recorder/DynamicConfig.xml
rename to tests/tests/neuralnetworks/AndroidTestHost.xml
index 53528de..60a34fa 100644
--- a/tests/tests/media/recorder/DynamicConfig.xml
+++ b/tests/tests/neuralnetworks/AndroidTestHost.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2021 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -12,9 +13,10 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
+<configuration description="Runs CtsNNAPITestCases.">
+ <test class="com.android.tradefed.testtype.HostGTest" >
+ <option name="module-name" value="CtsNNAPITestCases" />
+ <option name="native-test-timeout" value="10m" />
+ </test>
+</configuration>
-<dynamicConfig>
- <entry key="media_files_url">
- <value>https://storage.googleapis.com/android_media/cts/tests/tests/media/CtsMediaTestCases-1.4.zip</value>
- </entry>
-</dynamicConfig>
diff --git a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
index 1851b36..6b31091 100644
--- a/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
+++ b/tests/tests/neuralnetworks/benchmark/src/com/android/nn/benchmark/cts/NNAccuracyTest.java
@@ -19,6 +19,7 @@
import static junit.framework.TestCase.assertFalse;
import android.app.Activity;
+import android.util.Log;
import android.util.Pair;
import androidx.test.filters.LargeTest;
@@ -49,6 +50,7 @@
*/
@RunWith(Parameterized.class)
public class NNAccuracyTest {
+ protected static final String TAG = NNAccuracyTest.class.getSimpleName();
@Rule
public ActivityTestRule<NNAccuracyActivity> mActivityRule =
@@ -105,7 +107,12 @@
try (NNTestBase test = mModel.createNNTestBase(/*useNNAPI=*/true,
/*enableIntermediateTensorsDump=*/false)) {
test.setNNApiDeviceName(accelerator);
- test.setupModel(mActivity);
+ if (!test.setupModel(mActivity)) {
+ Log.d(TAG, String.format(
+ "Cannot initialise test '%s' on accelerator %s, skipping",
+ mModel.mModelName, accelerator));
+ continue;
+ }
Pair<List<InferenceInOutSequence>, List<InferenceResult>> inferenceResults =
test.runBenchmarkCompleteInputSet(/*setRepeat=*/1, /*timeoutSec=*/3600);
BenchmarkResult benchmarkResult =
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index edaf643..1effbb7 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -2704,6 +2704,10 @@
<permission android:name="android.permission.CONFIGURE_INTERACT_ACROSS_PROFILES"
android:protectionLevel="signature" />
+ <!-- @SystemApi @hide Allows starting activities across profiles in the same profile group. -->
+ <permission android:name="android.permission.START_CROSS_PROFILE_ACTIVITIES"
+ android:protectionLevel="signature|role" />
+
<!-- @SystemApi @hide Allows an application to call APIs that allow it to query and manage
users on the device. This permission is not available to
third party applications. -->
diff --git a/tests/tests/telecom/src/android/telecom/cts/AdhocConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/AdhocConferenceTest.java
index 6e8acd1..9e8c150 100644
--- a/tests/tests/telecom/src/android/telecom/cts/AdhocConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/AdhocConferenceTest.java
@@ -26,6 +26,7 @@
import android.telecom.Connection;
import android.telecom.ConnectionRequest;
import android.telecom.DisconnectCause;
+import android.telecom.TelecomManager;
import android.telecom.VideoProfile;
import android.util.Log;
import android.util.Pair;
@@ -65,6 +66,8 @@
return;
}
Bundle extra = new Bundle();
+ extra.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
mTelecomManager.startConference(PARTICIPANTS, extra);
ConnectionRequest request = verifyAdhocConferenceCall().second;
assertTrue(request.isAdhocConferenceCall());
diff --git a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
index dd4a9ac..205cb5b 100644
--- a/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/RemoteConnectionTest.java
@@ -239,7 +239,10 @@
}
try {
- mTelecomManager.startConference(PARTICIPANTS, null);
+ Bundle extra = new Bundle();
+ extra.putParcelable(TelecomManager.EXTRA_PHONE_ACCOUNT_HANDLE,
+ TestUtils.TEST_PHONE_ACCOUNT_HANDLE);
+ mTelecomManager.startConference(PARTICIPANTS, extra);
MockConference conference = verifyConference(2);
MockConference remoteConference = verifyConferenceOnRemoteCS(2);
RemoteConferenceTest.verifyRemoteConferenceObject(conference.getRemoteConference(),
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java
index a41aff5..86a2c8f7 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/IRadioConfigImpl.java
@@ -23,10 +23,11 @@
import android.hardware.radio.config.IRadioConfigIndication;
import android.hardware.radio.config.IRadioConfigResponse;
import android.hardware.radio.config.PhoneCapability;
-import android.hardware.radio.config.SimPortInfo;
import android.hardware.radio.config.SimSlotStatus;
import android.hardware.radio.config.SlotPortMapping;
-import android.hardware.radio.sim.CardStatus;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -34,18 +35,88 @@
private static final String TAG = "MRCFG";
private final MockModemService mService;
- private byte mNumOfLiveModems = 1;
private IRadioConfigResponse mRadioConfigResponse;
private IRadioConfigIndication mRadioConfigIndication;
+ private static MockModemConfigInterface[] sMockModemConfigInterfaces;
+ private Object mCacheUpdateMutex;
+ private final Handler mHandler;
+ private int mSubId;
+ // ***** Events
+ static final int EVENT_NUM_OF_LIVE_MODEM_CHANGED = 1;
+ static final int EVENT_PHONE_CAPABILITY_CHANGED = 2;
+ static final int EVENT_SIM_SLOT_STATUS_CHANGED = 3;
+
+ // ***** Cache of modem attributes/status
private int mSlotNum = 1;
- private boolean mSimStatePresent = false;
+ private byte mNumOfLiveModems = 1;
+ private PhoneCapability mPhoneCapability = new PhoneCapability();
+ private SimSlotStatus[] mSimSlotStatus;
- public IRadioConfigImpl(MockModemService service) {
+ public IRadioConfigImpl(
+ MockModemService service, MockModemConfigInterface[] interfaces, int instanceId) {
Log.d(TAG, "Instantiated");
this.mService = service;
+ sMockModemConfigInterfaces = interfaces;
mSlotNum = mService.getNumPhysicalSlots();
+ mSimSlotStatus = new SimSlotStatus[mSlotNum];
+ mCacheUpdateMutex = new Object();
+ mHandler = new IRadioConfigHandler();
+ mSubId = instanceId;
+
+ // Register events
+ sMockModemConfigInterfaces[mSubId].registerForNumOfLiveModemChanged(
+ mHandler, EVENT_NUM_OF_LIVE_MODEM_CHANGED, null);
+ sMockModemConfigInterfaces[mSubId].registerForPhoneCapabilityChanged(
+ mHandler, EVENT_PHONE_CAPABILITY_CHANGED, null);
+ sMockModemConfigInterfaces[mSubId].registerForSimSlotStatusChanged(
+ mHandler, EVENT_SIM_SLOT_STATUS_CHANGED, null);
+ }
+
+ /** Handler class to handle callbacks */
+ private final class IRadioConfigHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ synchronized (mCacheUpdateMutex) {
+ switch (msg.what) {
+ case EVENT_NUM_OF_LIVE_MODEM_CHANGED:
+ Log.d(TAG, "Received EVENT_NUM_OF_LIVE_MODEM_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mNumOfLiveModems = (byte) ar.result;
+ Log.i(TAG, "Number of live modem: " + mNumOfLiveModems);
+ } else {
+ Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+ }
+ break;
+ case EVENT_PHONE_CAPABILITY_CHANGED:
+ Log.d(TAG, "Received EVENT_PHONE_CAPABILITY_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mPhoneCapability = (PhoneCapability) ar.result;
+ Log.i(TAG, "Phone capability: " + mPhoneCapability);
+ } else {
+ Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+ }
+ break;
+ case EVENT_SIM_SLOT_STATUS_CHANGED:
+ Log.d(TAG, "Received EVENT_SIM_SLOT_STATUS_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mSimSlotStatus = (SimSlotStatus[]) ar.result;
+ for (int i = 0; i < mSlotNum; i++) {
+ Log.i(TAG, "Sim slot status: " + mSimSlotStatus[i]);
+ }
+ unsolSimSlotsStatusChanged();
+ } else {
+ Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+ }
+ break;
+ }
+ }
+ }
}
// Implementation of IRadioConfig functions
@@ -68,10 +139,15 @@
@Override
public void getNumOfLiveModems(int serial) {
Log.d(TAG, "getNumOfLiveModems");
+ byte numoflivemodem;
+
+ synchronized (mCacheUpdateMutex) {
+ numoflivemodem = mNumOfLiveModems;
+ }
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
- mRadioConfigResponse.getNumOfLiveModemsResponse(rsp, mNumOfLiveModems);
+ mRadioConfigResponse.getNumOfLiveModemsResponse(rsp, numoflivemodem);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to invoke getNumOfLiveModemsResponse from AIDL. Exception" + ex);
}
@@ -80,10 +156,11 @@
@Override
public void getPhoneCapability(int serial) {
Log.d(TAG, "getPhoneCapability");
+ PhoneCapability phoneCapability;
- PhoneCapability phoneCapability = new PhoneCapability();
- phoneCapability.logicalModemIds = new byte[2];
- convertMockPhoneCapToHal(phoneCapability);
+ synchronized (mCacheUpdateMutex) {
+ phoneCapability = mPhoneCapability;
+ }
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
@@ -98,14 +175,13 @@
Log.d(TAG, "getSimSlotsStatus");
SimSlotStatus[] slotStatus;
- if (mSlotNum < 1) {
- Log.d(TAG, "No slot information is retured.");
- slotStatus = null;
- } else {
- slotStatus = new SimSlotStatus[mSlotNum];
-
- for (int i = 0; i < mSlotNum; i++) slotStatus[i] = new SimSlotStatus();
- convertMockSimSlotStatusToHal(slotStatus);
+ synchronized (mCacheUpdateMutex) {
+ if (mSlotNum < 1) {
+ Log.d(TAG, "No slot information is retured.");
+ slotStatus = null;
+ } else {
+ slotStatus = mSimSlotStatus;
+ }
}
RadioResponseInfo rsp = mService.makeSolRsp(serial);
@@ -170,15 +246,13 @@
SimSlotStatus[] slotStatus;
if (mRadioConfigIndication != null) {
-
- if (mSlotNum < 1) {
- Log.d(TAG, "No slot information is retured.");
- slotStatus = null;
- } else {
- slotStatus = new SimSlotStatus[mSlotNum];
-
- for (int i = 0; i < mSlotNum; i++) slotStatus[i] = new SimSlotStatus();
- convertMockSimSlotStatusToHal(slotStatus);
+ synchronized (mCacheUpdateMutex) {
+ if (mSlotNum < 1) {
+ Log.d(TAG, "No slot information is retured.");
+ slotStatus = null;
+ } else {
+ slotStatus = mSimSlotStatus;
+ }
}
try {
@@ -191,64 +265,4 @@
Log.e(TAG, "null mRadioConfigIndication");
}
}
-
- private void convertMockSimSlotStatusToHal(SimSlotStatus[] slotStatus) {
-
- int portInfoListLen = 1;
-
- if (mSlotNum >= 1) {
- if (mSimStatePresent) {
- slotStatus[0].cardState = CardStatus.STATE_PRESENT;
- } else {
- slotStatus[0].cardState = CardStatus.STATE_ABSENT;
- }
- slotStatus[0].atr = "";
- slotStatus[0].eid = "";
- SimPortInfo[] portInfoList0 = new SimPortInfo[portInfoListLen];
- for (int i = 0; i < portInfoListLen; i++) portInfoList0[i] = new SimPortInfo();
- portInfoList0[0].portActive = true;
- portInfoList0[0].logicalSlotId = 0;
- portInfoList0[0].iccId = "";
- slotStatus[0].portInfo = portInfoList0;
- }
-
- if (mSlotNum >= 2) {
- slotStatus[1].cardState = CardStatus.STATE_PRESENT;
- slotStatus[1].atr = "3B9F97C00A3FC6828031E073FE211F65D002341512810F51";
- slotStatus[1].eid = "89033023426200000000005430099507";
- SimPortInfo[] portInfoList1 = new SimPortInfo[portInfoListLen];
- for (int i = 0; i < portInfoListLen; i++) portInfoList1[i] = new SimPortInfo();
- portInfoList1[0].portActive = false;
- portInfoList1[0].logicalSlotId = -1;
- portInfoList1[0].iccId = "";
- slotStatus[1].portInfo = portInfoList1;
- }
-
- if (mSlotNum >= 3) {
- slotStatus[2].cardState = CardStatus.STATE_ABSENT;
- slotStatus[2].atr = "";
- slotStatus[2].eid = "";
- SimPortInfo[] portInfoList2 = new SimPortInfo[portInfoListLen];
- for (int i = 0; i < portInfoListLen; i++) portInfoList2[i] = new SimPortInfo();
- portInfoList2[0].portActive = false;
- portInfoList2[0].logicalSlotId = -1;
- portInfoList2[0].iccId = "";
- slotStatus[2].portInfo = portInfoList2;
- }
- }
-
- private void convertMockPhoneCapToHal(PhoneCapability phoneCapability) {
-
- phoneCapability.maxActiveData = 2;
- phoneCapability.maxActiveInternetData = 1;
- phoneCapability.isInternetLingeringSupported = false;
- phoneCapability.logicalModemIds[0] = 0;
- phoneCapability.logicalModemIds[1] = 1;
- }
-
- // TODO: use helper function to handle
- public void setSimPresent(int slotId) {
- // TODO: check slotId and Phone ID
- mSimStatePresent = true;
- }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java
index 44a7ee5..4cca64b 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/IRadioModemImpl.java
@@ -16,6 +16,8 @@
package android.telephony.cts;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
+
import android.hardware.radio.RadioError;
import android.hardware.radio.RadioIndicationType;
import android.hardware.radio.RadioResponseInfo;
@@ -23,26 +25,119 @@
import android.hardware.radio.modem.IRadioModemIndication;
import android.hardware.radio.modem.IRadioModemResponse;
import android.hardware.radio.modem.RadioState;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
public class IRadioModemImpl extends IRadioModem.Stub {
private static final String TAG = "MRMDM";
- private static final String BASEBAND_VERSION = "mock-modem-service-1.0";
- private static final String DEFAULT_IMEI = "123456789012345";
- private static final String DEFAULT_IMEISV = "01";
- private static final String DEFAULT_ESN = "123456789";
- private static final String DEFAULT_MEID = "123456789012345";
-
private final MockModemService mService;
private IRadioModemResponse mRadioModemResponse;
private IRadioModemIndication mRadioModemIndication;
- public IRadioModemImpl(MockModemService service) {
+ private int mForceRadioPowerError = -1;
+
+ private static MockModemConfigInterface[] sMockModemConfigInterfaces;
+ private Object mCacheUpdateMutex;
+ private final Handler mHandler;
+ private int mSubId;
+
+ // ***** Events
+ static final int EVENT_BASEBAND_VERSION_CHANGED = 1;
+ static final int EVENT_DEVICE_IDENTITY_CHANGED = 2;
+ static final int EVENT_RADIO_STATE_CHANGED = 3;
+
+ // ***** Cache of modem attributes/status
+ private String mBasebandVer;
+ private String mImei;
+ private String mImeiSv;
+ private String mEsn;
+ private String mMeid;
+ private int mRadioState;
+
+ public IRadioModemImpl(
+ MockModemService service, MockModemConfigInterface[] interfaces, int instanceId) {
Log.d(TAG, "Instantiated");
this.mService = service;
+ sMockModemConfigInterfaces = interfaces;
+ mCacheUpdateMutex = new Object();
+ mHandler = new IRadioModemHandler();
+ mSubId = instanceId;
+
+ // Register events
+ sMockModemConfigInterfaces[mSubId].registerForBasebandVersionChanged(
+ mHandler, EVENT_BASEBAND_VERSION_CHANGED, null);
+ sMockModemConfigInterfaces[mSubId].registerForDeviceIdentityChanged(
+ mHandler, EVENT_DEVICE_IDENTITY_CHANGED, null);
+ sMockModemConfigInterfaces[mSubId].registerForRadioStateChanged(
+ mHandler, EVENT_RADIO_STATE_CHANGED, null);
+ }
+
+ /** Handler class to handle callbacks */
+ private final class IRadioModemHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ synchronized (mCacheUpdateMutex) {
+ switch (msg.what) {
+ case EVENT_BASEBAND_VERSION_CHANGED:
+ Log.d(TAG, "Received EVENT_BASEBAND_VERSION_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mBasebandVer = (String) ar.result;
+ Log.i(TAG, "Basedband version = " + mBasebandVer);
+ } else {
+ Log.e(
+ TAG,
+ msg.what
+ + " failure. Not update baseband version."
+ + ar.exception);
+ }
+ break;
+ case EVENT_DEVICE_IDENTITY_CHANGED:
+ Log.d(TAG, "Received EVENT_DEVICE_IDENTITY_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ String[] deviceIdentity = (String[]) ar.result;
+ mImei = deviceIdentity[0];
+ mImeiSv = deviceIdentity[1];
+ mEsn = deviceIdentity[2];
+ mMeid = deviceIdentity[3];
+ Log.i(
+ TAG,
+ "Device identity: IMEI = "
+ + mImei
+ + " IMEISV = "
+ + mImeiSv
+ + " ESN = "
+ + mEsn
+ + " MEID ="
+ + mMeid);
+ } else {
+ Log.e(
+ TAG,
+ msg.what
+ + " failure. Not update device identity."
+ + ar.exception);
+ }
+ break;
+ case EVENT_RADIO_STATE_CHANGED:
+ Log.d(TAG, "Received EVENT_RADIO_STATE_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mRadioState = (int) ar.result;
+ Log.i(TAG, "Radio state: " + mRadioState);
+ } else {
+ Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+ }
+ break;
+ }
+ }
+ }
}
// Implementation of IRadioModem functions
@@ -72,7 +167,11 @@
public void getBasebandVersion(int serial) {
Log.d(TAG, "getBasebandVersion");
- String baseband = BASEBAND_VERSION;
+ String baseband;
+
+ synchronized (mCacheUpdateMutex) {
+ baseband = mBasebandVer;
+ }
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
@@ -86,10 +185,14 @@
public void getDeviceIdentity(int serial) {
Log.d(TAG, "getDeviceIdentity");
- String imei = DEFAULT_IMEI;
- String imeisv = DEFAULT_IMEISV;
- String esn = DEFAULT_ESN;
- String meid = DEFAULT_MEID;
+ String imei, imeisv, esn, meid;
+
+ synchronized (mCacheUpdateMutex) {
+ imei = mImei;
+ imeisv = mImeiSv;
+ esn = mEsn;
+ meid = mMeid;
+ }
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
@@ -268,23 +371,35 @@
boolean forEmergencyCall,
boolean preferredForEmergencyCall) {
Log.d(TAG, "setRadioPower");
+ RadioResponseInfo rsp = null;
- // TODO: cache value
+ // Check if the error response needs to be modified
+ if (mForceRadioPowerError != -1) {
+ rsp = mService.makeSolRsp(serial, mForceRadioPowerError);
+ } else {
+ synchronized (mCacheUpdateMutex) {
+ if (powerOn) {
+ mRadioState = MockModemConfigInterface.RADIO_STATE_ON;
+ } else {
+ mRadioState = MockModemConfigInterface.RADIO_STATE_OFF;
+ }
+ sMockModemConfigInterfaces[mSubId].setRadioState(mRadioState, TAG);
+ }
+ rsp = mService.makeSolRsp(serial);
+ }
- RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
mRadioModemResponse.setRadioPowerResponse(rsp);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to setRadioPower from AIDL. Exception" + ex);
}
- // TODO: The below should be handled by Helper function
- if (powerOn) {
- radioStateChanged(RadioState.ON);
- mService.countDownLatch(MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_ON);
- } else {
- radioStateChanged(RadioState.OFF);
- mService.countDownLatch(MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_OFF);
+ if (rsp.error == RadioError.NONE) {
+ if (powerOn) {
+ radioStateChanged(RadioState.ON);
+ } else {
+ radioStateChanged(RadioState.OFF);
+ }
}
}
@@ -347,4 +462,14 @@
Log.e(TAG, "null mRadioModemIndication");
}
}
+
+ public void forceErrorResponse(int requestId, int error) {
+ switch (requestId) {
+ case RIL_REQUEST_RADIO_POWER:
+ mForceRadioPowerError = error;
+ break;
+ default:
+ break;
+ }
+ }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java
index 02ca850..c914f79 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/IRadioNetworkImpl.java
@@ -131,8 +131,7 @@
new android.hardware.radio.network.RegStateResult();
dataRegResponse.accessTechnologySpecificInfo =
android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
- dataRegResponse.cellIdentity =
- android.hardware.radio.network.CellIdentity.noinit(true);
+ dataRegResponse.cellIdentity = android.hardware.radio.network.CellIdentity.noinit(true);
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
@@ -230,8 +229,7 @@
new android.hardware.radio.network.RegStateResult();
voiceRegResponse.accessTechnologySpecificInfo =
android.hardware.radio.network.AccessTechnologySpecificInfo.noinit(true);
- voiceRegResponse.cellIdentity =
- android.hardware.radio.network.CellIdentity.noinit(true);
+ voiceRegResponse.cellIdentity = android.hardware.radio.network.CellIdentity.noinit(true);
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java b/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
index 7879841..8a9f241 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/IRadioSimImpl.java
@@ -23,6 +23,9 @@
import android.hardware.radio.sim.IRadioSim;
import android.hardware.radio.sim.IRadioSimIndication;
import android.hardware.radio.sim.IRadioSimResponse;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
import android.os.RemoteException;
import android.util.Log;
@@ -32,14 +35,56 @@
private final MockModemService mService;
private IRadioSimResponse mRadioSimResponse;
private IRadioSimIndication mRadioSimIndication;
- private CardStatus mCardStatus = null;
- private boolean mSimStatePresent = false;
+ private static MockModemConfigInterface[] sMockModemConfigInterfaces;
+ private Object mCacheUpdateMutex;
+ private final Handler mHandler;
+ private int mSubId;
- public IRadioSimImpl(MockModemService service) {
+ // ***** Events
+ static final int EVENT_SIM_CARD_STATUS_CHANGED = 1;
+
+ // ***** Cache of modem attributes/status
+ private int mNumOfLogicalSim;
+ private CardStatus mCardStatus;
+
+ public IRadioSimImpl(
+ MockModemService service, MockModemConfigInterface[] interfaces, int instanceId) {
Log.d(TAG, "Instantiated");
this.mService = service;
- mCardStatus = setCardAbsent();
+ sMockModemConfigInterfaces = interfaces;
+ mSubId = instanceId;
+ mCardStatus = new CardStatus();
+ mCacheUpdateMutex = new Object();
+ mHandler = new IRadioSimHandler();
+ mNumOfLogicalSim = sMockModemConfigInterfaces.length;
+
+ // Register events
+ sMockModemConfigInterfaces[mSubId].registerForCardStatusChanged(
+ mHandler, EVENT_SIM_CARD_STATUS_CHANGED, null);
+ }
+
+ /** Handler class to handle callbacks */
+ private final class IRadioSimHandler extends Handler {
+ @Override
+ public void handleMessage(Message msg) {
+ AsyncResult ar;
+ synchronized (mCacheUpdateMutex) {
+ switch (msg.what) {
+ case EVENT_SIM_CARD_STATUS_CHANGED:
+ Log.d(TAG, "Received EVENT_SIM_CARD_STATUS_CHANGED");
+ ar = (AsyncResult) msg.obj;
+ if (ar != null && ar.exception == null) {
+ mCardStatus = (CardStatus) ar.result;
+ Log.i(TAG, "Sim card status: " + mCardStatus);
+ simStatusChanged();
+ } else {
+ Log.e(TAG, msg.what + " failure. Exception: " + ar.exception);
+ }
+ break;
+ }
+ }
+ }
}
// Implementation of IRadioSim functions
@@ -183,18 +228,18 @@
@Override
public void getIccCardStatus(int serial) {
Log.d(TAG, "getIccCardStatus");
+ CardStatus cardStatus;
- // TODO: use helper function to handle
- if (mSimStatePresent) mCardStatus.cardState = CardStatus.STATE_PRESENT;
+ synchronized (mCacheUpdateMutex) {
+ cardStatus = mCardStatus;
+ }
RadioResponseInfo rsp = mService.makeSolRsp(serial);
try {
- mRadioSimResponse.getIccCardStatusResponse(rsp, mCardStatus);
+ mRadioSimResponse.getIccCardStatusResponse(rsp, cardStatus);
} catch (RemoteException ex) {
Log.e(TAG, "Failed to getIccCardStatus from AIDL. Exception" + ex);
}
-
- mService.countDownLatch(MockModemService.LATCH_MOCK_MODEM_SIM_READY);
}
@Override
@@ -718,28 +763,4 @@
Log.e(TAG, "null mRadioSimIndication");
}
}
-
- private CardStatus setCardAbsent() {
- CardStatus cardStatus = new CardStatus();
- cardStatus.cardState = CardStatus.STATE_ABSENT;
- cardStatus.universalPinState = 0;
- cardStatus.gsmUmtsSubscriptionAppIndex = -1;
- cardStatus.cdmaSubscriptionAppIndex = -1;
- cardStatus.imsSubscriptionAppIndex = -1;
- cardStatus.applications = new android.hardware.radio.sim.AppStatus[0];
- cardStatus.atr = "";
- cardStatus.iccid = "";
- cardStatus.eid = "";
- cardStatus.slotMap = new android.hardware.radio.config.SlotPortMapping();
- cardStatus.slotMap.physicalSlotId = 0;
- cardStatus.slotMap.portId = 0;
-
- return cardStatus;
- }
-
- // TODO: use helper function to handle
- public void setSimPresent(int slotId) {
- // TODO: check slotId and Phone ID
- mSimStatePresent = true;
- }
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
new file mode 100644
index 0000000..6a8731d
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigBase.java
@@ -0,0 +1,369 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telephony.cts;
+
+import android.content.Context;
+import android.hardware.radio.config.PhoneCapability;
+import android.hardware.radio.config.SimPortInfo;
+import android.hardware.radio.config.SimSlotStatus;
+import android.hardware.radio.sim.CardStatus;
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RegistrantList;
+import android.util.Log;
+
+public class MockModemConfigBase implements MockModemConfigInterface {
+ // ***** Instance Variables
+ private static final int DEFAULT_SUB_ID = 0;
+ private String mTAG = "MockModemConfigBase";
+ private final Handler mHandler;
+ private Context mContext;
+ private int mSubId;
+ private int mSimPhyicalId;
+ private Object mConfigAccess;
+ private int mNumOfSim = MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT;
+ private int mNumOfPhone = MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM;
+
+ // ***** Events
+ static final int EVENT_SET_RADIO_POWER = 1;
+ static final int EVENT_SET_SIM_PRESENT = 2;
+
+ // ***** Modem config values
+ private String mBasebandVersion = MockModemConfigInterface.DEFAULT_BASEBAND_VERSION;
+ private String mImei = MockModemConfigInterface.DEFAULT_IMEI;
+ private String mImeiSv = MockModemConfigInterface.DEFAULT_IMEISV;
+ private String mEsn = MockModemConfigInterface.DEFAULT_ESN;
+ private String mMeid = MockModemConfigInterface.DEFAULT_MEID;
+ private int mRadioState = MockModemConfigInterface.DEFAULT_RADIO_STATE;
+ private byte mNumOfLiveModem = MockModemConfigInterface.DEFAULT_NUM_OF_LIVE_MODEM;
+ private SimSlotStatus[] mSimSlotStatus;
+ private CardStatus mCardStatus;
+ private MockSimCard[] mSIMCard;
+ private PhoneCapability mPhoneCapability = new PhoneCapability();
+
+ // ***** RegistrantLists
+ // ***** IRadioConfig RegistrantLists
+ private RegistrantList mNumOfLiveModemChangedRegistrants = new RegistrantList();
+ private RegistrantList mPhoneCapabilityChangedRegistrants = new RegistrantList();
+ private RegistrantList mSimSlotStatusChangedRegistrants = new RegistrantList();
+
+ // ***** IRadioModem RegistrantLists
+ private RegistrantList mBasebandVersionChangedRegistrants = new RegistrantList();
+ private RegistrantList mDeviceIdentityChangedRegistrants = new RegistrantList();
+ private RegistrantList mRadioStateChangedRegistrants = new RegistrantList();
+
+ // ***** IRadioSim RegistrantLists
+ private RegistrantList mCardStatusChangedRegistrants = new RegistrantList();
+
+ public MockModemConfigBase(Context context, int instanceId, int numOfSim, int numOfPhone) {
+ mContext = context;
+ mSubId = instanceId;
+ mNumOfSim =
+ (numOfSim > MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT)
+ ? MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT
+ : numOfSim;
+ mNumOfPhone =
+ (numOfPhone > MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM)
+ ? MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM
+ : numOfPhone;
+ mTAG = mTAG + "[" + mSubId + "]";
+ mConfigAccess = new Object();
+ mHandler = new MockModemConfigHandler();
+ mSimSlotStatus = new SimSlotStatus[mNumOfSim];
+ mCardStatus = new CardStatus();
+ mSIMCard = new MockSimCard[mNumOfSim];
+ mSimPhyicalId = mSubId; // for default mapping
+ createSIMCards();
+ setDefaultConfigValue();
+ }
+
+ public class MockModemConfigHandler extends Handler {
+ // ***** Handler implementation
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mConfigAccess) {
+ switch (msg.what) {
+ case EVENT_SET_RADIO_POWER:
+ int state = msg.arg1;
+ if (state >= RADIO_STATE_UNAVAILABLE && state <= RADIO_STATE_ON) {
+ Log.d(
+ mTAG,
+ "EVENT_SET_RADIO_POWER: old("
+ + mRadioState
+ + "), new("
+ + state
+ + ")");
+ if (mRadioState != state) {
+ mRadioState = state;
+ mRadioStateChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mRadioState, null));
+ }
+ } else {
+ Log.e(mTAG, "EVENT_SET_RADIO_POWER: invalid state(" + state + ")");
+ mRadioStateChangedRegistrants.notifyRegistrants(null);
+ }
+ break;
+ case EVENT_SET_SIM_PRESENT:
+ boolean isPresent = msg.getData().getBoolean("isPresent", false);
+ Log.d(mTAG, "EVENT_SET_SIM_PRESENT: " + (isPresent ? "Present" : "Absent"));
+ int newCardState =
+ isPresent ? CardStatus.STATE_PRESENT : CardStatus.STATE_ABSENT;
+ if (mSubId == DEFAULT_SUB_ID
+ && mSimSlotStatus[mSimPhyicalId].cardState != newCardState) {
+ mSimSlotStatus[mSimPhyicalId].cardState = newCardState;
+ mSimSlotStatusChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mSimSlotStatus, null));
+ }
+ if (mCardStatus.cardState != newCardState) {
+ mCardStatus.cardState = newCardState;
+ mCardStatusChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mCardStatus, null));
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ private void setDefaultConfigValue() {
+ synchronized (mConfigAccess) {
+ mBasebandVersion = MockModemConfigInterface.DEFAULT_BASEBAND_VERSION;
+ mImei = MockModemConfigInterface.DEFAULT_IMEI;
+ mImeiSv = MockModemConfigInterface.DEFAULT_IMEISV;
+ mEsn = MockModemConfigInterface.DEFAULT_ESN;
+ mMeid = MockModemConfigInterface.DEFAULT_MEID;
+ mRadioState = MockModemConfigInterface.DEFAULT_RADIO_STATE;
+ mNumOfLiveModem = MockModemConfigInterface.DEFAULT_NUM_OF_LIVE_MODEM;
+ setDefaultPhoneCapability(mPhoneCapability);
+ if (mSubId == DEFAULT_SUB_ID) {
+ setDefaultSimSlotStatus();
+ }
+ setDefaultCardStatus();
+ }
+ }
+
+ private void setDefaultPhoneCapability(PhoneCapability phoneCapability) {
+ phoneCapability.logicalModemIds =
+ new byte[MockModemConfigInterface.MAX_NUM_OF_LOGICAL_MODEM];
+ phoneCapability.maxActiveData = MockModemConfigInterface.DEFAULT_MAX_ACTIVE_DATA;
+ phoneCapability.maxActiveInternetData =
+ MockModemConfigInterface.DEFAULT_MAX_ACTIVE_INTERNAL_DATA;
+ phoneCapability.isInternetLingeringSupported =
+ MockModemConfigInterface.DEFAULT_IS_INTERNAL_LINGERING_SUPPORTED;
+ phoneCapability.logicalModemIds[0] = MockModemConfigInterface.DEFAULT_LOGICAL_MODEM1_ID;
+ phoneCapability.logicalModemIds[1] = MockModemConfigInterface.DEFAULT_LOGICAL_MODEM2_ID;
+ }
+
+ private void createSIMCards() {
+ for (int i = 0; i < mNumOfSim; i++) {
+ mSIMCard[i] = new MockSimCard(i);
+ }
+ }
+
+ private void setDefaultSimSlotStatus() {
+ if (mSubId != DEFAULT_SUB_ID) {
+ // Only sub 0 needs to response SimSlotStatus
+ return;
+ }
+
+ for (int i = 0; i < mNumOfSim; i++) {
+ int portInfoListLen = mSIMCard[i].getNumOfSimPortInfo();
+ mSimSlotStatus[i] = new SimSlotStatus();
+ mSimSlotStatus[i].cardState =
+ mSIMCard[i].isCardPresent()
+ ? CardStatus.STATE_PRESENT
+ : CardStatus.STATE_ABSENT;
+ mSimSlotStatus[i].atr = mSIMCard[i].getATR();
+ mSimSlotStatus[i].eid = mSIMCard[i].getEID();
+ // Current only support one Sim port in MockSimCard
+ SimPortInfo[] portInfoList0 = new SimPortInfo[portInfoListLen];
+ portInfoList0[0] = new SimPortInfo();
+ portInfoList0[0].portActive = mSIMCard[i].isSlotPortActive();
+ portInfoList0[0].logicalSlotId = mSIMCard[i].getLogicalSlotId();
+ portInfoList0[0].iccId = mSIMCard[i].getICCID();
+ mSimSlotStatus[i].portInfo = portInfoList0;
+ }
+ }
+
+ private void setDefaultCardStatus() {
+ if (mSimPhyicalId != -1) {
+ int numbOfSimApp = mSIMCard[mSimPhyicalId].getNumOfSimApp();
+ mCardStatus = new CardStatus();
+ mCardStatus.cardState =
+ mSIMCard[mSimPhyicalId].isCardPresent()
+ ? CardStatus.STATE_PRESENT
+ : CardStatus.STATE_ABSENT;
+ mCardStatus.universalPinState = mSIMCard[mSimPhyicalId].getUniversalPinState();
+ mCardStatus.gsmUmtsSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getGsmAppIndex();
+ mCardStatus.cdmaSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getCdmaAppIndex();
+ mCardStatus.imsSubscriptionAppIndex = mSIMCard[mSimPhyicalId].getImsAppIndex();
+ mCardStatus.applications = new android.hardware.radio.sim.AppStatus[numbOfSimApp];
+ mCardStatus.atr = mSIMCard[mSimPhyicalId].getATR();
+ mCardStatus.iccid = mSIMCard[mSimPhyicalId].getICCID();
+ mCardStatus.eid = mSIMCard[mSimPhyicalId].getEID();
+ mCardStatus.slotMap = new android.hardware.radio.config.SlotPortMapping();
+ mCardStatus.slotMap.physicalSlotId = mSIMCard[mSimPhyicalId].getPhysicalSlotId();
+ mCardStatus.slotMap.portId = mSIMCard[mSimPhyicalId].getSlotPortId();
+ } else {
+ Log.e(mTAG, "Invalid Sim physical id");
+ }
+ }
+
+ private void notifyDeviceIdentityChangedRegistrants() {
+ String[] deviceIdentity = new String[4];
+ synchronized (mConfigAccess) {
+ deviceIdentity[0] = mImei;
+ deviceIdentity[1] = mImeiSv;
+ deviceIdentity[2] = mEsn;
+ deviceIdentity[3] = mMeid;
+ }
+ AsyncResult ar = new AsyncResult(null, deviceIdentity, null);
+ mDeviceIdentityChangedRegistrants.notifyRegistrants(ar);
+ }
+
+ // ***** MockModemConfigInterface implementation
+ @Override
+ public void notifyAllRegistrantNotifications() {
+ Log.d(mTAG, "notifyAllRegistrantNotifications");
+ synchronized (mConfigAccess) {
+ // IRadioConfig
+ mNumOfLiveModemChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mNumOfLiveModem, null));
+ mPhoneCapabilityChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mPhoneCapability, null));
+ mSimSlotStatusChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mSimSlotStatus, null));
+
+ // IRadioModem
+ mBasebandVersionChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mBasebandVersion, null));
+ notifyDeviceIdentityChangedRegistrants();
+ mRadioStateChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mRadioState, null));
+
+ // IRadioSim
+ mCardStatusChangedRegistrants.notifyRegistrants(
+ new AsyncResult(null, mCardStatus, null));
+ }
+ }
+
+ // ***** IRadioConfig notification implementation
+ @Override
+ public void registerForNumOfLiveModemChanged(Handler h, int what, Object obj) {
+ mNumOfLiveModemChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForNumOfLiveModemChanged(Handler h) {
+ mNumOfLiveModemChangedRegistrants.remove(h);
+ }
+
+ @Override
+ public void registerForPhoneCapabilityChanged(Handler h, int what, Object obj) {
+ mPhoneCapabilityChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForPhoneCapabilityChanged(Handler h) {
+ mPhoneCapabilityChangedRegistrants.remove(h);
+ }
+
+ @Override
+ public void registerForSimSlotStatusChanged(Handler h, int what, Object obj) {
+ mSimSlotStatusChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForSimSlotStatusChanged(Handler h) {
+ mSimSlotStatusChangedRegistrants.remove(h);
+ }
+
+ // ***** IRadioModem notification implementation
+ @Override
+ public void registerForBasebandVersionChanged(Handler h, int what, Object obj) {
+ mBasebandVersionChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForBasebandVersionChanged(Handler h) {
+ mBasebandVersionChangedRegistrants.remove(h);
+ }
+
+ @Override
+ public void registerForDeviceIdentityChanged(Handler h, int what, Object obj) {
+ mDeviceIdentityChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForDeviceIdentityChanged(Handler h) {
+ mDeviceIdentityChangedRegistrants.remove(h);
+ }
+
+ @Override
+ public void registerForRadioStateChanged(Handler h, int what, Object obj) {
+ mRadioStateChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForRadioStateChanged(Handler h) {
+ mRadioStateChangedRegistrants.remove(h);
+ }
+
+ // ***** IRadioSim notification implementation
+ @Override
+ public void registerForCardStatusChanged(Handler h, int what, Object obj) {
+ mCardStatusChangedRegistrants.addUnique(h, what, obj);
+ }
+
+ @Override
+ public void unregisterForCardStatusChanged(Handler h) {
+ mCardStatusChangedRegistrants.remove(h);
+ }
+
+ // ***** IRadioConfig set APIs implementation
+
+ // ***** IRadioModem set APIs implementation
+ @Override
+ public void setRadioState(int state, String client) {
+ Log.d(mTAG, "setRadioState (" + state + ") from " + client);
+
+ Message msg = mHandler.obtainMessage(EVENT_SET_RADIO_POWER);
+ msg.arg1 = state;
+ mHandler.sendMessage(msg);
+ }
+
+ // ***** IRadioSim set APIs implementation
+
+ // ***** IRadioNetwork set APIs implementation
+
+ // ***** IRadioVoice set APIs implementation
+
+ // ***** IRadioData set APIs implementation
+
+ // ***** IRadioMessaging set APIs implementation
+
+ // ***** Helper APIs implementation
+ @Override
+ public void setSimPresent(boolean isPresent, String client) {
+ Log.d(mTAG, "setSimPresent (" + (isPresent ? "Present" : "Absent") + ") from: " + client);
+
+ Message msg = mHandler.obtainMessage(EVENT_SET_SIM_PRESENT);
+ msg.getData().putBoolean("isPresent", isPresent);
+ mHandler.sendMessage(msg);
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
new file mode 100644
index 0000000..5632255
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemConfigInterface.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telephony.cts;
+
+import android.os.Handler;
+
+public interface MockModemConfigInterface {
+
+ // ***** Constants
+ int MAX_NUM_OF_SIM_SLOT = 3; // Change this needs to add more SIM SLOT NVs.
+ int MAX_NUM_OF_LOGICAL_MODEM = 2; // Change this needs to add more MODEM NVs.
+ int RADIO_STATE_UNAVAILABLE = 0;
+ int RADIO_STATE_OFF = 1;
+ int RADIO_STATE_ON = 2;
+
+ // Default config value
+ String DEFAULT_BASEBAND_VERSION = "mock-modem-service-1.0";
+ String DEFAULT_IMEI = "123456789012345";
+ String DEFAULT_IMEISV = "01";
+ String DEFAULT_ESN = "123456789";
+ String DEFAULT_MEID = "123456789012345";
+ int DEFAULT_RADIO_STATE = RADIO_STATE_UNAVAILABLE;
+ int DEFAULT_NUM_OF_LIVE_MODEM = 1; // Should <= MAX_NUM_OF_MODEM
+ int DEFAULT_MAX_ACTIVE_DATA = 2;
+ int DEFAULT_MAX_ACTIVE_INTERNAL_DATA = 1;
+ boolean DEFAULT_IS_INTERNAL_LINGERING_SUPPORTED = false;
+ int DEFAULT_LOGICAL_MODEM1_ID = 0;
+ int DEFAULT_LOGICAL_MODEM2_ID = 1;
+
+ // ***** Methods
+
+ /** Broadcast all notifications */
+ void notifyAllRegistrantNotifications();
+
+ // ***** IRadioConfig
+ /** Register/unregister notification handler for number of modem changed */
+ void registerForNumOfLiveModemChanged(Handler h, int what, Object obj);
+
+ void unregisterForNumOfLiveModemChanged(Handler h);
+
+ /** Register/unregister notification handler for sim slot status changed */
+ void registerForPhoneCapabilityChanged(Handler h, int what, Object obj);
+
+ void unregisterForPhoneCapabilityChanged(Handler h);
+
+ /** Register/unregister notification handler for sim slot status changed */
+ void registerForSimSlotStatusChanged(Handler h, int what, Object obj);
+
+ void unregisterForSimSlotStatusChanged(Handler h);
+
+ // ***** IRadioModem
+ /** Register/unregister notification handler for baseband version changed */
+ void registerForBasebandVersionChanged(Handler h, int what, Object obj);
+
+ void unregisterForBasebandVersionChanged(Handler h);
+
+ /** Register/unregister notification handler for device identity changed */
+ void registerForDeviceIdentityChanged(Handler h, int what, Object obj);
+
+ void unregisterForDeviceIdentityChanged(Handler h);
+
+ /** Register/unregister notification handler for radio state changed */
+ void registerForRadioStateChanged(Handler h, int what, Object obj);
+
+ void unregisterForRadioStateChanged(Handler h);
+
+ // ***** IRadioSim
+ /** Register/unregister notification handler for card status changed */
+ void registerForCardStatusChanged(Handler h, int what, Object obj);
+
+ void unregisterForCardStatusChanged(Handler h);
+
+ /**
+ * Sets the latest radio power state of modem
+ *
+ * @param state 0 means "unavailable", 1 means "off", 2 means "on".
+ * @param client for tracking calling client
+ */
+ void setRadioState(int state, String client);
+
+ /**
+ * Sets a specific logical SIM state to absent or present
+ *
+ * @param isPresent true means "present", false means "absent".
+ * @param client for tracking calling client
+ */
+ void setSimPresent(boolean isPresent, String client);
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
new file mode 100644
index 0000000..24eaa7a
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemManager.java
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telephony.cts;
+
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
+
+import android.content.Context;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+
+import java.util.concurrent.TimeUnit;
+
+public class MockModemManager {
+ private static final String TAG = "MockModemManager";
+
+ private static Context sContext;
+ private static MockModemServiceConnector sServiceConnector;
+ private MockModemService mMockModemService;
+
+ public MockModemManager() {
+ sContext = InstrumentationRegistry.getInstrumentation().getContext();
+ }
+
+ private void waitForTelephonyFrameworkDone(int delayInSec) throws Exception {
+ TimeUnit.SECONDS.sleep(delayInSec);
+ }
+
+ /* Public APIs */
+
+ /**
+ * Bring up Mock Modem Service and connect to it.
+ *
+ * @return boolean true if the operation is successful, otherwise false.
+ */
+ public boolean connectMockModemService() throws Exception {
+ boolean result = false;
+
+ if (sServiceConnector == null) {
+ sServiceConnector =
+ new MockModemServiceConnector(InstrumentationRegistry.getInstrumentation());
+ }
+
+ if (sServiceConnector != null) {
+ result = sServiceConnector.connectMockModemService();
+
+ if (result) {
+ mMockModemService = sServiceConnector.getMockModemService();
+
+ if (mMockModemService != null) {
+ /*
+ It needs to have a delay to wait for Telephony Framework to bind with
+ MockModemService and set radio power as a desired state for initial condition
+ even get SIM card state. Currently, 1 sec is enough for now.
+ */
+ waitForTelephonyFrameworkDone(1);
+ } else {
+ Log.e(TAG, "MockModemService get failed!");
+ result = false;
+ }
+ }
+ } else {
+ Log.e(TAG, "Create MockModemServiceConnector failed!");
+ }
+
+ return result;
+ }
+
+ /**
+ * Disconnect from Mock Modem Service.
+ *
+ * @return boolean true if the operation is successful, otherwise false.
+ */
+ public boolean disconnectMockModemService() throws Exception {
+ boolean result = false;
+
+ if (sServiceConnector != null) {
+ result = sServiceConnector.disconnectMockModemService();
+
+ if (result) {
+ mMockModemService = null;
+ } else {
+ Log.e(TAG, "MockModemService disconnected failed!");
+ }
+ } else {
+ Log.e(TAG, "No MockModemServiceConnector exist!");
+ }
+
+ return result;
+ }
+
+ /**
+ * Set SIM card status as present.
+ *
+ * @param subId which sub needs to be set.
+ * @return boolean true if the operation is successful, otherwise false.
+ */
+ public boolean setSimPresent(int subId) throws Exception {
+ Log.d(TAG, "setSimPresent[" + subId + "]");
+ boolean result = true;
+
+ MockModemConfigInterface[] configInterfaces =
+ mMockModemService.getMockModemConfigInterfaces();
+ configInterfaces[subId].setSimPresent(true, TAG);
+ waitForTelephonyFrameworkDone(1);
+ return result;
+ }
+
+ /**
+ * Force the response error return for a specific RIL request
+ *
+ * @param subId which sub needs to be set.
+ * @param requestId the request/response message ID
+ * @param error RIL_Errno and -1 means to disable the modified mechanism, back to original mock
+ * modem behavior
+ * @return boolean true if the operation is successful, otherwise false.
+ */
+ public boolean forceErrorResponse(int subId, int requestId, int error) throws Exception {
+ Log.d(
+ TAG,
+ "forceErrorResponse[" + subId + "] for request:" + requestId + " ,error:" + error);
+ boolean result = true;
+
+ // TODO: support DSDS
+ switch (requestId) {
+ case RIL_REQUEST_RADIO_POWER:
+ mMockModemService.getIRadioModem().forceErrorResponse(requestId, error);
+ break;
+ default:
+ Log.e(TAG, "request:" + requestId + " not support to change the response error");
+ result = false;
+ break;
+ }
+ return result;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
index 4b09895..38e7086 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemService.java
@@ -24,7 +24,7 @@
import android.hardware.radio.RadioResponseType;
import android.os.Binder;
import android.os.IBinder;
-import android.sysprop.TelephonyProperties;
+import android.telephony.TelephonyManager;
import android.util.Log;
import androidx.test.platform.app.InstrumentationRegistry;
@@ -46,6 +46,7 @@
public static final String PHONE_ID = "phone_id";
private static Context sContext;
+ private static MockModemConfigInterface[] sMockModemConfigInterfaces;
private static IRadioConfigImpl sIRadioConfigImpl;
private static IRadioModemImpl sIRadioModemImpl;
private static IRadioSimImpl sIRadioSimImpl;
@@ -58,19 +59,16 @@
public static final byte PHONE_ID_1 = 0x01;
public static final int LATCH_MOCK_MODEM_SERVICE_READY = 0;
- public static final int LATCH_MOCK_MODEM_RADIO_POWR_ON = 1;
- public static final int LATCH_MOCK_MODEM_RADIO_POWR_OFF = 2;
- public static final int LATCH_MOCK_MODEM_SIM_READY = 3;
- public static final int LATCH_MAX = 4;
+ public static final int LATCH_RADIO_INTERFACES_READY = 1;
+ public static final int LATCH_MAX = 2;
private static final int IRADIO_CONFIG_INTERFACE_NUMBER = 1;
private static final int IRADIO_INTERFACE_NUMBER = 6;
- public static final int LATCH_RADIO_INTERFACES_READY = LATCH_MAX;
- public static final int LATCH_MOCK_MODEM_INITIALIZATION_READY =
- LATCH_RADIO_INTERFACES_READY + 1;
- public static final int TOTAL_LATCH_NUMBER = LATCH_MAX + 2;
- private int mSimNumber;
+ private TelephonyManager mTelephonyManager;
+ private int mNumOfSim;
+ private int mNumOfPhone;
+ private static final int DEFAULT_SUB_ID = 0;
private Object mLock;
protected static CountDownLatch[] sLatches;
@@ -87,24 +85,36 @@
public void onCreate() {
Log.d(TAG, "Mock Modem Service Created");
- mSimNumber = 1; // TODO: Read property to know the device is single SIM or DSDS
+ sContext = InstrumentationRegistry.getInstrumentation().getContext();
+ mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
+ mNumOfSim = getNumPhysicalSlots();
+ mNumOfPhone = mTelephonyManager.getActiveModemCount();
+ Log.d(TAG, "Support number of phone = " + mNumOfPhone + ", number of SIM = " + mNumOfSim);
mLock = new Object();
- sLatches = new CountDownLatch[TOTAL_LATCH_NUMBER];
+ sLatches = new CountDownLatch[LATCH_MAX];
for (int i = 0; i < LATCH_MAX; i++) {
sLatches[i] = new CountDownLatch(1);
+ if (i == LATCH_RADIO_INTERFACES_READY) {
+ int radioInterfaceNumber =
+ IRADIO_CONFIG_INTERFACE_NUMBER + mNumOfPhone * IRADIO_INTERFACE_NUMBER;
+ sLatches[i] = new CountDownLatch(radioInterfaceNumber);
+ } else {
+ sLatches[i] = new CountDownLatch(1);
+ }
}
- int radioInterfaceNumber =
- IRADIO_CONFIG_INTERFACE_NUMBER + mSimNumber * IRADIO_INTERFACE_NUMBER;
- sLatches[LATCH_RADIO_INTERFACES_READY] = new CountDownLatch(radioInterfaceNumber);
- sLatches[LATCH_MOCK_MODEM_INITIALIZATION_READY] = new CountDownLatch(1);
+ sMockModemConfigInterfaces = new MockModemConfigBase[mNumOfPhone];
+ for (int i = 0; i < mNumOfPhone; i++) {
+ sMockModemConfigInterfaces[i] =
+ new MockModemConfigBase(sContext, i, mNumOfSim, mNumOfPhone);
+ }
- sContext = InstrumentationRegistry.getInstrumentation().getContext();
- sIRadioConfigImpl = new IRadioConfigImpl(this);
- sIRadioModemImpl = new IRadioModemImpl(this);
- sIRadioSimImpl = new IRadioSimImpl(this);
+ sIRadioConfigImpl = new IRadioConfigImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
+ // TODO: Support DSDS
+ sIRadioModemImpl = new IRadioModemImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
+ sIRadioSimImpl = new IRadioSimImpl(this, sMockModemConfigInterfaces, DEFAULT_SUB_ID);
sIRadioNetworkImpl = new IRadioNetworkImpl(this);
sIRadioDataImpl = new IRadioDataImpl(this);
sIRadioMessagingImpl = new IRadioMessagingImpl(this);
@@ -181,14 +191,6 @@
return mBinder;
}
- public void resetState() {
- synchronized (mLock) {
- for (int i = 0; i < LATCH_MAX; i++) {
- sLatches[i] = new CountDownLatch(1);
- }
- }
- }
-
public boolean waitForLatchCountdown(int latchIndex) {
boolean complete = false;
try {
@@ -231,7 +233,6 @@
int numPhysicalSlots =
sContext.getResources()
.getInteger(com.android.internal.R.integer.config_num_physical_slots);
- Log.d(TAG, "numPhysicalSlots: " + numPhysicalSlots);
return numPhysicalSlots;
}
@@ -253,61 +254,51 @@
return rspInfo;
}
- private boolean initRadioState() {
- int waitLatch;
+ public boolean initialize() {
+ Log.d(TAG, "initialize");
+ boolean result = true;
- boolean apm = TelephonyProperties.airplane_mode_on().orElse(false);
- Log.d(TAG, "APM setting: " + apm);
-
- if (!apm) {
- waitLatch = LATCH_MOCK_MODEM_RADIO_POWR_ON;
- } else {
- waitLatch = LATCH_MOCK_MODEM_RADIO_POWR_OFF;
+ // Sync mock modem status between modules
+ for (int i = 0; i < mNumOfPhone; i++) {
+ sMockModemConfigInterfaces[i].notifyAllRegistrantNotifications();
}
- sIRadioModemImpl.radioStateChanged(android.hardware.radio.modem.RadioState.OFF);
-
- // Radio Power command is expected.
- return waitForLatchCountdown(waitLatch);
- }
-
- private boolean initSimSlotState() {
-
- // SIM/Slot commands are expected.
- return waitForLatchCountdown(LATCH_MOCK_MODEM_SIM_READY);
- }
-
- public void initialization() {
- Log.d(TAG, "initialization");
-
- boolean status = false;
-
+ // Connect to telephony framework
sIRadioModemImpl.rilConnected();
- status = initRadioState();
- if (!status) {
- Log.e(TAG, "radio state initialization fail");
- return;
- }
-
- status = initSimSlotState();
- if (!status) {
- Log.e(TAG, "sim/slot state initialization fail");
- return;
- }
-
- countDownLatch(LATCH_MOCK_MODEM_INITIALIZATION_READY);
+ return result;
}
- public void unsolSimSlotsStatusChanged() {
- sIRadioConfigImpl.unsolSimSlotsStatusChanged();
- sIRadioSimImpl.simStatusChanged();
+ public MockModemConfigInterface[] getMockModemConfigInterfaces() {
+ return sMockModemConfigInterfaces;
}
- public void setSimPresent(int slotId) {
- Log.d(TAG, "setSimPresent");
+ // TODO: Support DSDS
+ public IRadioConfigImpl getIRadioConfig() {
+ return sIRadioConfigImpl;
+ }
- sIRadioSimImpl.setSimPresent(slotId);
- sIRadioConfigImpl.setSimPresent(slotId);
+ public IRadioModemImpl getIRadioModem() {
+ return sIRadioModemImpl;
+ }
+
+ public IRadioSimImpl getIRadioSim() {
+ return sIRadioSimImpl;
+ }
+
+ public IRadioNetworkImpl getIRadioNetwork() {
+ return sIRadioNetworkImpl;
+ }
+
+ public IRadioVoiceImpl getIRadioVoice() {
+ return sIRadioVoiceImpl;
+ }
+
+ public IRadioMessagingImpl getIRadioMessaging() {
+ return sIRadioMessagingImpl;
+ }
+
+ public IRadioDataImpl getIRadioData() {
+ return sIRadioDataImpl;
}
}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java b/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
index ebafc81..beeb720 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockModemServiceConnector.java
@@ -33,8 +33,7 @@
private static final String TAG = "MockModemServiceConnector";
- private static final String DEFAULT_SERVICE_NAME =
- MockModemService.class.getClass().getName();
+ private static final String DEFAULT_SERVICE_NAME = MockModemService.class.getClass().getName();
private static final String COMMAND_BASE = "cmd phone ";
private static final String COMMAND_SET_MODEM_SERVICE = "radio set-modem-service ";
private static final String COMMAND_GET_MODEM_SERVICE = "radio get-modem-service ";
@@ -196,10 +195,9 @@
MockModemService.LATCH_RADIO_INTERFACES_READY,
BIND_RADIO_INTERFACE_READY_TIMEOUT_MS);
- mMockModemService.initialization();
- isComplete =
- mMockModemService.waitForLatchCountdown(
- MockModemService.LATCH_MOCK_MODEM_INITIALIZATION_READY);
+ if (isComplete) {
+ isComplete = mMockModemService.initialize();
+ }
}
return isComplete;
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java b/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java
new file mode 100644
index 0000000..280b8d5
--- /dev/null
+++ b/tests/tests/telephony/current/src/android/telephony/cts/MockSimCard.java
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.telephony.cts;
+
+import android.util.Log;
+
+public class MockSimCard {
+ private static final String TAG = "MockSimCard";
+
+ /* Support SIM card identify */
+ public static final int MOCK_SIM_PROFILE_ID_DEFAULT = 0; // SIM Absent
+ public static final int MOCK_SIM_PROFILE_ID_MAX = 1;
+
+ /* Support SIM slot */
+ private static final int MOCK_SIM_SLOT_1 = 0;
+ private static final int MOCK_SIM_SLOT_2 = 1;
+ private static final int MOCK_SIM_SLOT_3 = 2;
+ private static final int MOCK_SIM_SLOT_MAX = 3;
+
+ /* Default value definition */
+ private static final int MOCK_SIM_DEFAULT_SLOTID = MOCK_SIM_SLOT_1;
+ private static final int DEFAULT_NUM_OF_SIM_PORT_INfO = 1;
+ private static final int DEFAULT_NUM_OF_SIM_APP = 0;
+ private static final int DEFAULT_GSM_APP_IDX = -1;
+ private static final int DEFAULT_CDMA_APP_IDX = -1;
+ private static final int DEFAULT_IMS_APP_IDX = -1;
+ // SIM1 slot status
+ private static final int DEFAULT_SIM1_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+ private static final boolean DEFAULT_SIM1_CARD_PRESENT = false;
+ private static final String DEFAULT_SIM1_ATR = "";
+ private static final String DEFAULT_SIM1_EID = "";
+ private static final String DEFAULT_SIM1_ICCID = "";
+ private static final boolean DEFAULT_SIM1_PORT_ACTIVE = true;
+ private static final int DEFAULT_SIM1_PORT_ID = 0;
+ private static final int DEFAULT_SIM1_LOGICAL_SLOT_ID = 0;
+ private static final int DEFAULT_SIM1_PHYSICAL_SLOT_ID = 0;
+ private static final int DEFAULT_SIM1_UNIVERSAL_PIN_STATE = 0;
+ // SIM2 slot status
+ private static final int DEFAULT_SIM2_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+ private static final boolean DEFAULT_SIM2_CARD_PRESENT = false;
+ private static final String DEFAULT_SIM2_ATR =
+ "3B9F97C00A3FC6828031E073FE211F65D002341512810F51";
+ private static final String DEFAULT_SIM2_EID = "89033023426200000000005430099507";
+ private static final String DEFAULT_SIM2_ICCID = "";
+ private static final boolean DEFAULT_SIM2_PORT_ACTIVE = false;
+ private static final int DEFAULT_SIM2_PORT_ID = 0;
+ private static final int DEFAULT_SIM2_LOGICAL_SLOT_ID = -1;
+ private static final int DEFAULT_SIM2_PHYSICAL_SLOT_ID = 0;
+ private static final int DEFAULT_SIM2_UNIVERSAL_PIN_STATE = 0;
+ // SIM3 slot status
+ private static final int DEFAULT_SIM3_PROFILE_ID = MOCK_SIM_PROFILE_ID_DEFAULT;
+ private static final boolean DEFAULT_SIM3_CARD_PRESENT = false;
+ private static final String DEFAULT_SIM3_ATR = "";
+ private static final String DEFAULT_SIM3_EID = "";
+ private static final String DEFAULT_SIM3_ICCID = "";
+ private static final boolean DEFAULT_SIM3_PORT_ACTIVE = false;
+ private static final int DEFAULT_SIM3_PORT_ID = 0;
+ private static final int DEFAULT_SIM3_LOGICAL_SLOT_ID = -1;
+ private static final int DEFAULT_SIM3_PHYSICAL_SLOT_ID = 0;
+ private static final int DEFAULT_SIM3_UNIVERSAL_PIN_STATE = 0;
+
+ // SIM Slot status
+ private int mPhysicalSlotId;
+ private int mLogicalSlotId;
+ private int mSlotPortId;
+ private boolean mIsSlotPortActive;
+ private boolean mIsCardPresent;
+
+ // SIM card data
+ private int mSimProfileId;
+ private String mICCID;
+ private String mEID;
+ private String mATR;
+ private int mUniversalPinState;
+ private int mGsmAppIndex;
+ private int mCdmaAppIndex;
+ private int mImsAppIndex;
+ private int mNumOfSimApp;
+
+ public MockSimCard(int slotId) {
+ int simprofile = DEFAULT_SIM1_PROFILE_ID;
+
+ if (slotId >= MOCK_SIM_SLOT_MAX) {
+ Log.e(
+ TAG,
+ "Invalid slot id("
+ + slotId
+ + "). Using default slot id("
+ + MOCK_SIM_DEFAULT_SLOTID
+ + ").");
+ slotId = MOCK_SIM_DEFAULT_SLOTID;
+ }
+
+ // Init default SIM profile id
+ switch (slotId) {
+ case MOCK_SIM_SLOT_1:
+ simprofile = DEFAULT_SIM1_PROFILE_ID;
+ break;
+ case MOCK_SIM_SLOT_2:
+ simprofile = DEFAULT_SIM2_PROFILE_ID;
+ break;
+ case MOCK_SIM_SLOT_3:
+ simprofile = DEFAULT_SIM3_PROFILE_ID;
+ break;
+ }
+
+ // Initiate SIM card with default profile
+ initMockSimCard(slotId, simprofile);
+ }
+
+ private void initMockSimCard(int slotId, int simProfileId) {
+ if (slotId > MockModemConfigInterface.MAX_NUM_OF_SIM_SLOT) {
+ Log.e(
+ TAG,
+ "Physical slot id("
+ + slotId
+ + ") is invalid. Using default slot id("
+ + MOCK_SIM_DEFAULT_SLOTID
+ + ").");
+ mPhysicalSlotId = MOCK_SIM_DEFAULT_SLOTID;
+ } else {
+ mPhysicalSlotId = slotId;
+ }
+ if (simProfileId >= 0 && simProfileId < MOCK_SIM_PROFILE_ID_MAX) {
+ mSimProfileId = simProfileId;
+ Log.i(
+ TAG,
+ "Load SIM profile ID: "
+ + mSimProfileId
+ + " into physical slot["
+ + mPhysicalSlotId
+ + "]");
+ } else {
+ mSimProfileId = MOCK_SIM_PROFILE_ID_DEFAULT;
+ Log.e(
+ TAG,
+ "SIM Absent on physical slot["
+ + mPhysicalSlotId
+ + "]. Not support SIM card ID: "
+ + mSimProfileId);
+ }
+
+ // Initiate slot status
+ initMockSimSlot();
+
+ // Load SIM profile data
+ loadMockSimCard();
+ }
+
+ private void initMockSimSlot() {
+ switch (mPhysicalSlotId) {
+ case MOCK_SIM_SLOT_1:
+ mLogicalSlotId = DEFAULT_SIM1_LOGICAL_SLOT_ID;
+ mSlotPortId = DEFAULT_SIM1_PORT_ID;
+ mIsSlotPortActive = DEFAULT_SIM1_PORT_ACTIVE;
+ mIsCardPresent = DEFAULT_SIM1_CARD_PRESENT;
+ break;
+ case MOCK_SIM_SLOT_2:
+ mLogicalSlotId = DEFAULT_SIM2_LOGICAL_SLOT_ID;
+ mSlotPortId = DEFAULT_SIM2_PORT_ID;
+ mIsSlotPortActive = DEFAULT_SIM2_PORT_ACTIVE;
+ mIsCardPresent = DEFAULT_SIM2_CARD_PRESENT;
+ break;
+ case MOCK_SIM_SLOT_3:
+ mLogicalSlotId = DEFAULT_SIM3_LOGICAL_SLOT_ID;
+ mSlotPortId = DEFAULT_SIM3_PORT_ID;
+ mIsSlotPortActive = DEFAULT_SIM3_PORT_ACTIVE;
+ mIsCardPresent = DEFAULT_SIM3_CARD_PRESENT;
+ break;
+ }
+ }
+
+ private void loadMockSimCard() {
+ // TODO: Read SIM card data from file
+ switch (mSimProfileId) {
+ default: // SIM absent
+ switch (mPhysicalSlotId) {
+ case MOCK_SIM_SLOT_1:
+ mICCID = DEFAULT_SIM1_ICCID;
+ mATR = DEFAULT_SIM1_ATR;
+ mEID = DEFAULT_SIM1_EID;
+ mUniversalPinState = DEFAULT_SIM1_UNIVERSAL_PIN_STATE;
+ break;
+ case MOCK_SIM_SLOT_2:
+ mICCID = DEFAULT_SIM2_ICCID;
+ mATR = DEFAULT_SIM2_ATR;
+ mEID = DEFAULT_SIM2_EID;
+ mUniversalPinState = DEFAULT_SIM2_UNIVERSAL_PIN_STATE;
+ break;
+ case MOCK_SIM_SLOT_3:
+ mICCID = DEFAULT_SIM3_ICCID;
+ mATR = DEFAULT_SIM3_ATR;
+ mEID = DEFAULT_SIM3_EID;
+ mUniversalPinState = DEFAULT_SIM3_UNIVERSAL_PIN_STATE;
+ break;
+ }
+ mGsmAppIndex = DEFAULT_GSM_APP_IDX;
+ mCdmaAppIndex = DEFAULT_CDMA_APP_IDX;
+ mImsAppIndex = DEFAULT_IMS_APP_IDX;
+ mNumOfSimApp = DEFAULT_NUM_OF_SIM_APP;
+ break;
+ }
+ }
+
+ public boolean isSlotPortActive() {
+ return mIsSlotPortActive;
+ }
+
+ public boolean isCardPresent() {
+ return mIsCardPresent;
+ }
+
+ public int getNumOfSimPortInfo() {
+ return DEFAULT_NUM_OF_SIM_PORT_INfO;
+ }
+
+ public int getPhysicalSlotId() {
+ return mPhysicalSlotId;
+ }
+
+ public int getLogicalSlotId() {
+ return mLogicalSlotId;
+ }
+
+ public int getSlotPortId() {
+ return mSlotPortId;
+ }
+
+ public String getEID() {
+ return mEID;
+ }
+
+ public String getATR() {
+ return mATR;
+ }
+
+ public String getICCID() {
+ return mICCID;
+ }
+
+ public int getUniversalPinState() {
+ return mUniversalPinState;
+ }
+
+ public int getGsmAppIndex() {
+ return mGsmAppIndex;
+ }
+
+ public int getCdmaAppIndex() {
+ return mCdmaAppIndex;
+ }
+
+ public int getImsAppIndex() {
+ return mImsAppIndex;
+ }
+
+ public int getNumOfSimApp() {
+ return mNumOfSimApp;
+ }
+}
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
index 8a970e7..6f0e3f5 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTestOnMockModem.java
@@ -15,12 +15,15 @@
*/
package android.telephony.cts;
+import static com.android.internal.telephony.RILConstants.INTERNAL_ERR;
+import static com.android.internal.telephony.RILConstants.RIL_REQUEST_RADIO_POWER;
+
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import android.content.Context;
-import android.sysprop.TelephonyProperties;
import android.telephony.TelephonyManager;
import android.util.Log;
@@ -38,10 +41,8 @@
/** Test MockModemService interfaces. */
public class TelephonyManagerTestOnMockModem {
private static final String TAG = "TelephonyManagerTestOnMockModem";
- private static MockModemServiceConnector sServiceConnector;
- private static MockModemService sMockModem = null;
-
- TelephonyManager mTelephonyManager =
+ private static MockModemManager sMockModemManager;
+ private TelephonyManager mTelephonyManager =
(TelephonyManager) getContext().getSystemService(Context.TELEPHONY_SERVICE);
@BeforeClass
@@ -49,14 +50,9 @@
Log.d(TAG, "TelephonyManagerTestOnMockModem#beforeAllTests()");
- // Override all interfaces to MockModemService
- sServiceConnector =
- new MockModemServiceConnector(InstrumentationRegistry.getInstrumentation());
-
- assertNotNull(sServiceConnector);
- assertTrue(sServiceConnector.connectMockModemService());
-
- sMockModem = sServiceConnector.getMockModemService();
+ sMockModemManager = new MockModemManager();
+ assertNotNull(sMockModemManager);
+ assertTrue(sMockModemManager.connectMockModemService());
}
@AfterClass
@@ -64,10 +60,9 @@
Log.d(TAG, "TelephonyManagerTestOnMockModem#afterAllTests()");
// Rebind all interfaces which is binding to MockModemService to default.
- assertNotNull(sServiceConnector);
- assertTrue(sServiceConnector.disconnectMockModemService());
- sMockModem = null;
- sServiceConnector = null;
+ assertNotNull(sMockModemManager);
+ assertTrue(sMockModemManager.disconnectMockModemService());
+ sMockModemManager = null;
}
private static Context getContext() {
@@ -86,55 +81,76 @@
.contains(simCardState));
int slotId = 0;
- sMockModem.setSimPresent(slotId);
- sMockModem.resetState();
+ sMockModemManager.setSimPresent(slotId);
- sMockModem.unsolSimSlotsStatusChanged();
- assertTrue(
- sMockModem.waitForLatchCountdown(MockModemService.LATCH_MOCK_MODEM_SIM_READY));
-
- TimeUnit.SECONDS.sleep(1);
simCardState = mTelephonyManager.getSimCardState();
Log.d(TAG, "New SIM card state: " + simCardState);
assertEquals(TelephonyManager.SIM_STATE_PRESENT, simCardState);
}
@Test
- public void testRadioPower() throws Throwable {
- Log.d(TAG, "TelephonyManagerTestOnMockModem#testRadioPower");
+ public void testRadioPowerToggle() throws Throwable {
+ Log.d(TAG, "TelephonyManagerTestOnMockModem#testRadioPowerToggle");
- boolean apm = TelephonyProperties.airplane_mode_on().orElse(false);
- Log.d(TAG, "APM setting: " + apm);
+ int radioState = mTelephonyManager.getRadioPowerState();
+ Log.d(TAG, "Radio state: " + radioState);
- int expectedState;
- int waitLatch;
- if (!apm) {
- expectedState = TelephonyManager.RADIO_POWER_ON;
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_ON;
- } else {
- expectedState = TelephonyManager.RADIO_POWER_OFF;
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_OFF;
+ // Toggle radio power
+ try {
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.toggleRadioOnOff(),
+ SecurityException.class,
+ "android.permission.MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ Log.d(TAG, "TelephonyManager#toggleRadioOnOff should require " + e);
}
- assertEquals(mTelephonyManager.getRadioPowerState(), expectedState);
+ // Wait the radio state update in Framework
+ TimeUnit.SECONDS.sleep(1);
+ int toggleRadioState =
+ radioState == TelephonyManager.RADIO_POWER_ON
+ ? TelephonyManager.RADIO_POWER_OFF
+ : TelephonyManager.RADIO_POWER_ON;
+ assertEquals(mTelephonyManager.getRadioPowerState(), toggleRadioState);
- boolean switchState;
- if (!apm) {
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_OFF;
- switchState = false;
- expectedState = TelephonyManager.RADIO_POWER_OFF;
- } else {
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_ON;
- switchState = true;
- expectedState = TelephonyManager.RADIO_POWER_ON;
+ // Toggle radio power again back to original radio state
+ try {
+ ShellIdentityUtils.invokeThrowableMethodWithShellPermissionsNoReturn(
+ mTelephonyManager,
+ (tm) -> tm.toggleRadioOnOff(),
+ SecurityException.class,
+ "android.permission.MODIFY_PHONE_STATE");
+ } catch (SecurityException e) {
+ Log.d(TAG, "TelephonyManager#toggleRadioOnOff should require " + e);
}
- sMockModem.resetState(); // Reset the latch
- Log.d(TAG, "set Radio Power: " + switchState);
+ // Wait the radio state update in Framework
+ TimeUnit.SECONDS.sleep(1);
+ assertEquals(mTelephonyManager.getRadioPowerState(), radioState);
+
+ Log.d(TAG, "Test Done ");
+ }
+
+ @Test
+ public void testRadioPowerWithFailureResults() throws Throwable {
+ Log.d(TAG, "TelephonyManagerTestOnMockModem#testRadioPowerWithFailureResults");
+
+ int radioState = mTelephonyManager.getRadioPowerState();
+ Log.d(TAG, "Radio state: " + radioState);
+
+ int slotId = 0;
+ int toggleRadioState =
+ radioState == TelephonyManager.RADIO_POWER_ON
+ ? TelephonyManager.RADIO_POWER_OFF
+ : TelephonyManager.RADIO_POWER_ON;
+
+ // Force the returned response of RIL_REQUEST_RADIO_POWER as INTERNAL_ERR
+ sMockModemManager.forceErrorResponse(slotId, RIL_REQUEST_RADIO_POWER, INTERNAL_ERR);
boolean result = false;
try {
- boolean state = switchState;
+ boolean state = (toggleRadioState == TelephonyManager.RADIO_POWER_ON) ? true : false;
result =
ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
mTelephonyManager,
@@ -144,29 +160,18 @@
} catch (SecurityException e) {
Log.d(TAG, "TelephonyManager#setRadioPower should require " + e);
}
+
TimeUnit.SECONDS.sleep(1);
-
assertTrue(result);
- assertTrue(sMockModem.waitForLatchCountdown(waitLatch));
- assertEquals(mTelephonyManager.getRadioPowerState(), expectedState);
+ assertNotEquals(mTelephonyManager.getRadioPowerState(), toggleRadioState);
- // Recovery to APM setting
- if (apm) {
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_OFF;
- switchState = false;
- expectedState = TelephonyManager.RADIO_POWER_OFF;
- } else {
- waitLatch = MockModemService.LATCH_MOCK_MODEM_RADIO_POWR_ON;
- switchState = true;
- expectedState = TelephonyManager.RADIO_POWER_ON;
- }
- sMockModem.resetState(); // Reset the latch
+ // Reset the modified error response of RIL_REQUEST_RADIO_POWER to the original behavior
+ // and -1 means to disable the modifed mechanism in mock modem
+ sMockModemManager.forceErrorResponse(slotId, RIL_REQUEST_RADIO_POWER, -1);
- Log.d(TAG, "Recovery Radio Power: " + switchState);
-
- result = false;
+ // Recovery the power state back to original radio state
try {
- boolean state = switchState;
+ boolean state = (radioState == TelephonyManager.RADIO_POWER_ON) ? true : false;
result =
ShellIdentityUtils.invokeThrowableMethodWithShellPermissions(
mTelephonyManager,
@@ -177,11 +182,7 @@
Log.d(TAG, "TelephonyManager#setRadioPower should require " + e);
}
TimeUnit.SECONDS.sleep(1);
-
assertTrue(result);
- assertTrue(sMockModem.waitForLatchCountdown(waitLatch));
- assertEquals(mTelephonyManager.getRadioPowerState(), expectedState);
-
- Log.d(TAG, "Test Done ");
+ assertEquals(mTelephonyManager.getRadioPowerState(), radioState);
}
}
diff --git a/tests/trust/OWNERS b/tests/trust/OWNERS
new file mode 100644
index 0000000..ad48129
--- /dev/null
+++ b/tests/trust/OWNERS
@@ -0,0 +1,3 @@
+# Bug component: 36824
+
+include platform/frameworks/base:/core/java/android/service/trust/OWNERS
diff --git a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java
index 2e261cf..701e88e 100644
--- a/tests/video/src/android/video/cts/CodecPerformanceTestBase.java
+++ b/tests/video/src/android/video/cts/CodecPerformanceTestBase.java
@@ -106,8 +106,10 @@
EXCLUDE_ENCODER_MAX_RESOLUTION = DEVICE_INITIAL_SDK <= Build.VERSION_CODES.Q;
// Encoders on devices launched on Android R and lower aren't tested when operating rate
- // that is set is > 0 and < 30 for resolution 4k
- EXCLUDE_ENCODER_OPRATE_0_TO_30_FOR_4K = DEVICE_INITIAL_SDK <= Build.VERSION_CODES.R;
+ // that is set is > 0 and < 30 for resolution 4k.
+ // This includes devices launched on Android S with R or lower vendor partition.
+ EXCLUDE_ENCODER_OPRATE_0_TO_30_FOR_4K =
+ !IS_AT_LEAST_VNDK_S || (DEVICE_INITIAL_SDK <= Build.VERSION_CODES.R);
}
@Before
diff --git a/tools/cts-device-info/Android.bp b/tools/cts-device-info/Android.bp
index ff85860..33afc9a 100644
--- a/tools/cts-device-info/Android.bp
+++ b/tools/cts-device-info/Android.bp
@@ -32,6 +32,7 @@
"sts",
"mts",
"vts",
+ "catbox",
],
static_libs: [
"compatibility-device-info",