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&amp;itag=160&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD.702DE9BA7AF96785FD6930AD2DD693A0486C880E&amp;key=ik0</value>
-    </entry>
-    <entry key="media_codec_capabilities_test_avc_baseline30">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=18&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA.7A83031734CB1EDCE06766B6228842F954927960&amp;key=ik0</value>
-    </entry>
-    <entry key="media_codec_capabilities_test_avc_high31">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=22&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=179525311196616BD8E1381759B0E5F81A9E91B5.C4A50E44059FEBCC6BBC78E3B3A4E0E0065777&amp;key=ik0</value>
-    </entry>
-    <entry key="media_codec_capabilities_test_avc_high40">
-        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=137&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=B0976085596DD42DEA3F08307F76587241CB132B.043B719C039E8B92F45391ADC0BE3665E2332930&amp;key=ik0</value>
-    </entry>
     <entry key="streaming_media_player_test_http_h263_amr_video1">
         <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=13&amp;source=youtube&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;sparams=ip,ipbits,expire,id,itag,source&amp;signature=5729247E22691EBB3E804DDD523EC42DC17DD8CE.443B81C1E8E6D64E4E1555F568BA46C206507D78&amp;key=ik0&amp;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&amp;itag=160&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=9EDCA0B395B8A949C511FD5E59B9F805CFF797FD.702DE9BA7AF96785FD6930AD2DD693A0486C880E&amp;key=ik0</value>
+    </entry>
+    <entry key="media_codec_capabilities_test_avc_baseline30">
+        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=18&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=7DCDE3A6594D0B91A27676A3CDC3A87B149F82EA.7A83031734CB1EDCE06766B6228842F954927960&amp;key=ik0</value>
+    </entry>
+    <entry key="media_codec_capabilities_test_avc_high31">
+        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=22&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=179525311196616BD8E1381759B0E5F81A9E91B5.C4A50E44059FEBCC6BBC78E3B3A4E0E0065777&amp;key=ik0</value>
+    </entry>
+    <entry key="media_codec_capabilities_test_avc_high40">
+        <value>http://redirector.gvt1.com/videoplayback?id=271de9756065677e&amp;itag=137&amp;source=youtube&amp;user=android-device-test&amp;sparams=ip,ipbits,expire,id,itag,source,user&amp;ip=0.0.0.0&amp;ipbits=0&amp;expire=19000000000&amp;signature=B0976085596DD42DEA3F08307F76587241CB132B.043B719C039E8B92F45391ADC0BE3665E2332930&amp;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",