Merge "Change MediaProjection CTS directory"
diff --git a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
index 974fc24..7283f20 100644
--- a/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_aspect_ratio_and_crop.py
@@ -234,6 +234,8 @@
       raw_avlb = camera_properties_utils.raw16(props)
       debug = self.debug_mode
 
+      # Converge 3A.
+      cam.do_3a()
       req = capture_request_utils.auto_capture_request()
 
       # If raw available, use as ground truth.
diff --git a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
index de5bfd4..c0d9f39 100644
--- a/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
+++ b/apps/CameraITS/tests/scene4/test_preview_stabilization_fov.py
@@ -38,7 +38,7 @@
 
 _MAX_CENTER_THRESHOLD_PERCENT = 0.075
 _MAX_AREA = 1920 * 1440  # max mandatory preview stream resolution
-_MIN_CENTER_THRESHOLD_PERCENT = 0.02
+_MIN_CENTER_THRESHOLD_PERCENT = 0.03
 _MIN_AREA = 176 * 144  # assume QCIF to be min preview size
 
 
diff --git a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
index 1f09669..844807b 100644
--- a/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
+++ b/apps/CameraITS/tests/scene4/test_video_aspect_ratio_and_crop.py
@@ -162,12 +162,11 @@
 
       if raw_avlb and (fls_physical == fls_logical):
         logging.debug('RAW')
-        raw_bool = True
       else:
         logging.debug('JPEG')
-        raw_bool = False
+
       ref_fov, cc_ct_gt, aspect_ratio_gt = image_fov_utils.find_fov_reference(
-          cam, req, props, raw_bool, ref_img_name_stem)
+          cam, req, props, raw_avlb, ref_img_name_stem)
 
       run_crop_test = full_or_better and raw_avlb
 
diff --git a/apps/CameraITS/tests/sensor_fusion/test_multi_camera_frame_sync.py b/apps/CameraITS/tests/sensor_fusion/test_multi_camera_frame_sync.py
index 93e4f11..834fe9b 100644
--- a/apps/CameraITS/tests/sensor_fusion/test_multi_camera_frame_sync.py
+++ b/apps/CameraITS/tests/sensor_fusion/test_multi_camera_frame_sync.py
@@ -245,10 +245,21 @@
         hidden_physical_id=self.hidden_physical_id) as cam:
       props = cam.get_camera_properties()
       props = cam.override_with_hidden_physical_camera_props(props)
+      unavailable_physical_cameras = cam.get_unavailable_physical_cameras(
+          self.camera_id)
+      unavailable_physical_ids = unavailable_physical_cameras['unavailablePhysicalCamerasArray']
+      # find available physical camera IDs
+      all_physical_ids = camera_properties_utils.logical_multi_camera_physical_ids(
+          props)
+      for i in unavailable_physical_ids:
+        if i in all_physical_ids:
+          all_physical_ids.remove(i)
 
+      logging.debug('available physical ids: %s', all_physical_ids)
       # Check SKIP conditions.
       camera_properties_utils.skip_unless(
-          camera_properties_utils.multi_camera_frame_sync_capable(props))
+          camera_properties_utils.multi_camera_frame_sync_capable(props) and
+          len(all_physical_ids) >= 2)
 
       # Get first API level & multi camera sync type
       first_api_level = its_session_utils.get_first_api_level(self.dut.serial)
diff --git a/apps/CameraITS/utils/its_session_utils.py b/apps/CameraITS/utils/its_session_utils.py
index 480fca3..4e01da0 100644
--- a/apps/CameraITS/utils/its_session_utils.py
+++ b/apps/CameraITS/utils/its_session_utils.py
@@ -453,6 +453,24 @@
     self.sock.settimeout(self.SOCK_TIMEOUT)
     return data['objValue']
 
+  def get_unavailable_physical_cameras(self, camera_id):
+    """Get the unavailable physical cameras ids.
+
+    Args:
+      camera_id: int; device id
+    Returns:
+      List of all physical camera ids which are unavailable.
+    """
+    cmd = {'cmdName': 'doGetUnavailablePhysicalCameras',
+           'cameraId': camera_id}
+    self.sock.send(json.dumps(cmd).encode() + '\n'.encode())
+    timeout = self.SOCK_TIMEOUT + self.EXTRA_SOCK_TIMEOUT
+    self.sock.settimeout(timeout)
+    data, _ = self.__read_response_from_socket()
+    if data['tag'] != 'unavailablePhysicalCameras':
+      raise error_util.CameraItsError('Invalid command response')
+    return data['objValue']
+
   def is_hlg10_recording_supported(self, profile_id):
     """Query whether the camera device supports HLG10 video recording.
 
diff --git a/apps/CameraITS/utils/opencv_processing_utils.py b/apps/CameraITS/utils/opencv_processing_utils.py
index ae71504..ef0c8ac 100644
--- a/apps/CameraITS/utils/opencv_processing_utils.py
+++ b/apps/CameraITS/utils/opencv_processing_utils.py
@@ -42,7 +42,9 @@
 CIRCLISH_LOW_RES_ATOL = 0.15  # loosen for low res images
 CIRCLE_MIN_PTS = 20
 CIRCLE_RADIUS_NUMPTS_THRESH = 2  # contour num_pts/radius: empirically ~3x
+CIRCLE_COLOR_ATOL = 0.01  # circle color fill tolerance
 
+CV2_CONTOUR_LINE_THICKNESS = 3  # for drawing contours if multiple circles found
 CV2_RED = (255, 0, 0)  # color in cv2 to draw lines
 
 FOV_THRESH_TELE25 = 25
@@ -312,6 +314,28 @@
   return shape
 
 
+def find_circle_fill_metric(shape, img_bw, color):
+  """Find the proportion of points matching a desired color on a shape's axes.
+
+  Args:
+    shape: dictionary returned by component_shape(...)
+    img_bw: binarized numpy image array
+    color: int of [0 or 255] 0 is black, 255 is white
+  Returns:
+    float: number of x, y axis points matching color / total x, y axis points
+  """
+  matching = 0
+  total = 0
+  for y in range(shape['top'], shape['bottom']):
+    total += 1
+    matching += 1 if img_bw[y][shape['ctx']] == color else 0
+  for x in range(shape['left'], shape['right']):
+    total += 1
+    matching += 1 if img_bw[shape['cty']][x] == color else 0
+  logging.debug('Found %d matching points out of %d', matching, total)
+  return matching / total
+
+
 def find_circle(img, img_name, min_area, color):
   """Find the circle in the test image.
 
@@ -343,6 +367,7 @@
 
   # Check each contour and find the circle bigger than min_area
   num_circles = 0
+  circle_contours = []
   logging.debug('Initial number of contours: %d', len(contours))
   for contour in contours:
     area = cv2.contourArea(contour)
@@ -354,13 +379,16 @@
       colour = img_bw[shape['cty']][shape['ctx']]
       circlish = (math.pi * radius**2) / area
       aspect_ratio = shape['width'] / shape['height']
+      fill = find_circle_fill_metric(shape, img_bw, color)
       logging.debug('Potential circle found. radius: %.2f, color: %d, '
-                    'circlish: %.3f, ar: %.3f, pts: %d', radius, colour,
-                    circlish, aspect_ratio, num_pts)
+                    'circlish: %.3f, ar: %.3f, pts: %d, fill metric: %.3f',
+                    radius, colour, circlish, aspect_ratio, num_pts, fill)
       if (colour == color and
-          numpy.isclose(1.0, circlish, atol=circlish_atol) and
-          numpy.isclose(1.0, aspect_ratio, atol=CIRCLE_AR_ATOL) and
-          num_pts/radius >= CIRCLE_RADIUS_NUMPTS_THRESH):
+          math.isclose(1.0, circlish, abs_tol=circlish_atol) and
+          math.isclose(1.0, aspect_ratio, abs_tol=CIRCLE_AR_ATOL) and
+          num_pts/radius >= CIRCLE_RADIUS_NUMPTS_THRESH and
+          math.isclose(1.0, fill, abs_tol=CIRCLE_COLOR_ATOL)):
+        circle_contours.append(contour)
 
         # Populate circle dictionary
         circle['x'] = shape['ctx']
@@ -389,6 +417,11 @@
 
   if num_circles > 1:
     image_processing_utils.write_image(img/255, img_name, True)
+    cv2.drawContours(img, circle_contours, -1, CV2_RED,
+                     CV2_CONTOUR_LINE_THICKNESS)
+    img_name_parts = img_name.split('.')
+    image_processing_utils.write_image(
+        img/255, f'{img_name_parts[0]}_contours.{img_name_parts[1]}', True)
     raise AssertionError('More than 1 black circle detected. '
                          'Background of scene may be too complex.')
 
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index b140e56..a6eb237 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -18,7 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.verifier"
           android:versionCode="5"
-          android:versionName="13_r3">
+          android:versionName="13_r4">
 
     <uses-sdk android:minSdkVersion="19" android:targetSdkVersion="33"/>
 
@@ -3049,7 +3049,7 @@
             <meta-data android:name="test_excluded_features"
                        android:value="android.hardware.type.automotive"/>
             <meta-data android:name="display_mode"
-                       android:value="single_display_mode" />
+                       android:value="multi_display_mode" />
         </activity>
 
         <activity android:name=".camera.flashlight.CameraFlashlightActivity"
diff --git a/apps/CtsVerifier/jni/audio_loopback/OWNERS b/apps/CtsVerifier/jni/audio_loopback/OWNERS
new file mode 100644
index 0000000..0f50343
--- /dev/null
+++ b/apps/CtsVerifier/jni/audio_loopback/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48436
+elaurent@google.com
+pmclean@google.com
+philburk@google.com
diff --git a/apps/CtsVerifier/jni/midi/OWNERS b/apps/CtsVerifier/jni/midi/OWNERS
new file mode 100644
index 0000000..0f50343
--- /dev/null
+++ b/apps/CtsVerifier/jni/midi/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48436
+elaurent@google.com
+pmclean@google.com
+philburk@google.com
diff --git a/apps/CtsVerifier/jni/verifier/OWNERS b/apps/CtsVerifier/jni/verifier/OWNERS
new file mode 100644
index 0000000..0f50343
--- /dev/null
+++ b/apps/CtsVerifier/jni/verifier/OWNERS
@@ -0,0 +1,4 @@
+# Bug component: 48436
+elaurent@google.com
+pmclean@google.com
+philburk@google.com
diff --git a/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml b/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
index 24767d2..716b18f 100644
--- a/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
+++ b/apps/CtsVerifier/res/layout/audio_headset_audio_activity.xml
@@ -123,7 +123,8 @@
         <TextView
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:text="@string/analog_headset_keycodes_label"/>
+            android:text="@string/analog_headset_keycodes_label"
+            android:id="@+id/headset_keycodes"/>
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
diff --git a/apps/CtsVerifier/res/layout/logcat_read_logs.xml b/apps/CtsVerifier/res/layout/logcat_read_logs.xml
index e7cf4ab..db48502 100644
--- a/apps/CtsVerifier/res/layout/logcat_read_logs.xml
+++ b/apps/CtsVerifier/res/layout/logcat_read_logs.xml
@@ -14,40 +14,43 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+    style="@style/RootLayoutPadding"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:orientation="vertical"
-    android:padding="10dip"
->
+    android:layout_height="match_parent">
 
-  <TextView
-          android:layout_width="wrap_content"
-          android:layout_height="wrap_content"
-          android:textAppearance="?android:attr/textAppearanceLarge"
-          android:text="Test should be executed at least 2 minutes apart"
-          android:id="@+id/run_read_logs_title"
-          android:layout_margin="2dp"
-          android:textSize="14sp"
-          android:textStyle="bold"
-  />
+    <LinearLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-  <Button android:id="@+id/run_read_logs_fg_allow_btn"
-      android:text="@string/read_logs_fg_allow_text"
-      android:layout_marginBottom="20dp"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content" />
+        <TextView
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="?android:attr/textAppearanceLarge"
+            android:text="Test should be executed at least 2 minutes apart"
+            android:id="@+id/run_read_logs_title"
+            android:layout_margin="2dp"
+            android:textSize="14sp"
+            android:textStyle="bold"
+        />
 
-  <Button android:id="@+id/run_read_logs_fg_deny_btn"
-      android:text="@string/read_logs_fg_deny_text"
-      android:layout_width="match_parent"
-      android:layout_height="wrap_content" />
+        <Button android:id="@+id/run_read_logs_fg_allow_btn"
+                android:text="@string/read_logs_fg_allow_text"
+                android:layout_marginBottom="20dp"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
 
-  <include android:layout_width="match_parent"
-      android:layout_height="wrap_content"
-      android:layout_alignParentBottom="true"
-      layout="@layout/pass_fail_buttons"
-  />
+        <Button android:id="@+id/run_read_logs_fg_deny_btn"
+                android:text="@string/read_logs_fg_deny_text"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"/>
 
-</LinearLayout>
+        <include android:layout_width="match_parent"
+                 android:layout_height="wrap_content"
+                 android:layout_alignParentBottom="true"
+                 layout="@layout/pass_fail_buttons"
+        />
 
+    </LinearLayout>
+</ScrollView>
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index b694e2f..704be2e 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -5419,6 +5419,16 @@
        input jack and BT01 input plug to the USB interface output jack.
        \nThe Virtual MIDI test does not require any MIDI interface hardware.
     </string>
+    <string name="analog_headset_test_info_tv">This test tests the following functionality with respect to wired analog headsets.\n
+        1. Correct audio playback.\n
+        2. Plug intents.\n
+        \nTo execute test:\n
+        1. Plug in an Android-compatible, analog headset. Verify connection/recognition.\n
+        2. Play test tone and verify correct behavior.\n
+        \nTo run this test it is necessary to have an Android device with a 3.5mm analog headset jack and a compatible analog headset.\n
+        \n(see <a href="https://source.android.com/devices/accessories/headset/plug-headset-spec">3.5 mm Headset: Accessory Specification</a> and
+        <a href="https://source.android.com/compatibility/android-cdd#7_8_2_1_analog_audio_ports">Android CDD § 7.8.2.1. Analog Audio Ports</a>)
+    </string>
 
     <string name="midiHasMIDILbl">Has MIDI Support</string>
 
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
index 83b32de..307eb6f 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AnalogHeadsetAudioActivity.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.media.AudioDeviceCallback;
@@ -153,6 +154,14 @@
         mHeadsetVolUpText = (TextView)findViewById(R.id.headset_keycode_volume_up);
         mHeadsetVolDownText = (TextView)findViewById(R.id.headset_keycode_volume_down);
 
+        if (isTelevision()) {
+            mButtonsPromptTxt.setVisibility(View.GONE);
+            mHeadsetHookText.setVisibility(View.GONE);
+            mHeadsetVolUpText.setVisibility(View.GONE);
+            mHeadsetVolDownText.setVisibility(View.GONE);
+            ((TextView) findViewById(R.id.headset_keycodes)).setVisibility(View.GONE);
+        }
+
         mResultsTxt = (TextView)findViewById(R.id.headset_results);
 
         mAudioManager = (AudioManager)getSystemService(AUDIO_SERVICE);
@@ -168,7 +177,8 @@
 
         showKeyMessagesState();
 
-        setInfoResources(R.string.analog_headset_test, R.string.analog_headset_test_info, -1);
+        setInfoResources(R.string.analog_headset_test, isTelevision()
+                ? R.string.analog_headset_test_info_tv : R.string.analog_headset_test_info, -1);
 
         setPassFailButtonClickListeners();
         getPassButton().setEnabled(false);
@@ -182,11 +192,12 @@
             mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass_noheadset));
             return true;
         } else {
-            boolean pass = isReportLogOkToPass()
-                    && mPlugIntentReceived
-                    && mHeadsetDeviceInfo != null
-                    && mPlaybackSuccess
-                    && (mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown;
+            boolean pass = isReportLogOkToPass() &&
+                    mPlugIntentReceived &&
+                    mHeadsetDeviceInfo != null &&
+                    mPlaybackSuccess &&
+                    (isTelevision()
+                    || ((mHasHeadsetHook || mHasPlayPause) && mHasVolUp && mHasVolDown));
             if (pass) {
                 mResultsTxt.setText(getResources().getString(R.string.analog_headset_pass));
             } else if (!isReportLogOkToPass()) {
@@ -488,4 +499,8 @@
         }
         return super.onKeyDown(keyCode, event);
     }
+
+    private boolean isTelevision() {
+        return getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);
+    }
 }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
index 8ff2358..cf09a74 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioTap2ToneActivity.java
@@ -16,6 +16,11 @@
 
 package com.android.cts.verifier.audio;
 
+import static com.android.cts.verifier.TestListActivity.sCurrentDisplayMode;
+import static com.android.cts.verifier.TestListAdapter.setTestNameSuffix;
+
+import android.mediapc.cts.common.PerformanceClassEvaluator;
+
 import android.os.Build;
 import android.os.Bundle;
 import android.util.Log;
@@ -46,6 +51,7 @@
 import org.hyphonate.megaaudio.recorder.AudioSinkProvider;
 import org.hyphonate.megaaudio.recorder.sinks.AppCallback;
 import org.hyphonate.megaaudio.recorder.sinks.AppCallbackAudioSinkProvider;
+import org.junit.rules.TestName;
 
 /**
  * CtsVerifier test to measure tap-to-tone latency.
@@ -144,6 +150,8 @@
     private static final String KEY_LATENCY_AVE = "latency_max_";
     private static final String KEY_LATENCY_NUM_MEASUREMENTS = "latency_num_measurements_";
 
+    public final TestName testName = new TestName();
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         setContentView(R.layout.audio_tap2tone_activity);
@@ -505,6 +513,54 @@
         super.setTestResultAndFinish(passed);
     }
 
+    private void reportTestResultForApi(int api) {
+        CtsVerifierReportLog reportLog = getReportLog();
+        reportLog.addValue(
+                KEY_LATENCY_MIN + api,
+                mLatencyMin[api],
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+        reportLog.addValue(
+                KEY_LATENCY_MAX + api,
+                mLatencyMax[api],
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+        reportLog.addValue(
+                KEY_LATENCY_AVE + api,
+                mLatencyAve[api],
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+        reportLog.addValue(
+                KEY_LATENCY_NUM_MEASUREMENTS + api,
+                mNumMeasurements[api],
+                ResultType.NEUTRAL,
+                ResultUnit.NONE);
+    }
+
+    /** Records perf class results and returns if mpc is met */
+    private void recordPerfClassResults() {
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(testName);
+        PerformanceClassEvaluator.AudioTap2ToneLatencyRequirement r5_6__h_1_1 =
+                pce.addR5_6__H_1_1();
+
+        r5_6__h_1_1.setNativeLatency(mLatencyAve[TEST_API_NATIVE]);
+        r5_6__h_1_1.setJavaLatency(mLatencyAve[TEST_API_JAVA]);
+
+        pce.submitAndVerify();
+    }
+
+    @Override
+    public void recordTestResults() {
+        Log.i(TAG, "recordTestResults()");
+
+        reportTestResultForApi(TEST_API_NATIVE);
+        reportTestResultForApi(TEST_API_JAVA);
+
+        getReportLog().submit();
+
+        recordPerfClassResults();
+    }
+
     //
     // AppCallback overrides
     //
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
index 4ef46fa..8d1d3a0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsService.java
@@ -78,6 +78,7 @@
 import android.os.SystemClock;
 import android.os.Vibrator;
 import android.util.Log;
+import android.util.Pair;
 import android.util.Rational;
 import android.util.Size;
 import android.util.SparseArray;
@@ -123,6 +124,7 @@
 import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
+import java.util.HashSet;
 import java.util.concurrent.BlockingQueue;
 import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingDeque;
@@ -183,6 +185,8 @@
     public static final String EVCOMP_KEY = "evComp";
     public static final String AUTO_FLASH_KEY = "autoFlash";
     public static final String AUDIO_RESTRICTION_MODE_KEY = "mode";
+    public static final int AVAILABILITY_TIMEOUT_MS = 10;
+
 
     private CameraManager mCameraManager = null;
     private HandlerThread mCameraThread = null;
@@ -252,6 +256,8 @@
     private volatile boolean mNeedsLockedAWB = false;
     private volatile boolean mDoAE = true;
     private volatile boolean mDoAF = true;
+    private Set<Pair<String, String>> mUnavailablePhysicalCameras;
+
 
     class MySensorEvent {
         public Sensor sensor;
@@ -469,6 +475,7 @@
         }
 
         try {
+            mUnavailablePhysicalCameras = getUnavailablePhysicalCameras();
             mCamera = mBlockingCameraManager.openCamera(cameraId, mCameraListener, mCameraHandler);
             mCameraCharacteristics = mCameraManager.getCameraCharacteristics(cameraId);
 
@@ -826,6 +833,9 @@
                     doCheckHLG10Support(cameraId, profileId);
                 } else if ("doCaptureWithFlash".equals(cmdObj.getString("cmdName"))) {
                     doCaptureWithFlash(cmdObj);
+                } else if ("doGetUnavailablePhysicalCameras".equals(cmdObj.getString("cmdName"))) {
+                    String cameraId = cmdObj.getString("cameraId");
+                    doGetUnavailablePhysicalCameras(cameraId);
                 } else {
                     throw new ItsException("Unknown command: " + cmd);
                 }
@@ -1184,6 +1194,53 @@
                 hasPrivacySupport ? "true" : "false");
     }
 
+    private void doGetUnavailablePhysicalCameras(String cameraId) throws ItsException {
+        try {
+            JSONArray cameras = new JSONArray();
+            JSONObject jsonObj = new JSONObject();
+            for (Pair<String, String> p : mUnavailablePhysicalCameras) {
+                if (cameraId.equals(p.first)) {
+                    cameras.put(p.second);
+                }
+            }
+            jsonObj.put("unavailablePhysicalCamerasArray", cameras);
+            Log.i(TAG, "unavailablePhysicalCameras : " +
+                    Arrays.asList(mUnavailablePhysicalCameras.toString()));
+            mSocketRunnableObj.sendResponse("unavailablePhysicalCameras", null, jsonObj, null);
+        } catch (org.json.JSONException e) {
+            throw new ItsException("JSON error: ", e);
+        }
+    }
+
+    private Set<Pair<String, String>> getUnavailablePhysicalCameras() throws ItsException {
+        final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+        try {
+            CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
+                @Override
+                public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                    unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+                }
+            };
+            mCameraManager.registerAvailabilityCallback(ac, mCameraHandler);
+            Set<Pair<String, String>> unavailablePhysicalCameras =
+                    new HashSet<Pair<String, String>>();
+            Pair<String, String> candidatePhysicalIds =
+                    unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                    java.util.concurrent.TimeUnit.MILLISECONDS);
+            while (candidatePhysicalIds != null) {
+                unavailablePhysicalCameras.add(candidatePhysicalIds);
+                candidatePhysicalIds =
+                        unavailablePhysicalCamEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                        java.util.concurrent.TimeUnit.MILLISECONDS);
+            }
+            mCameraManager.unregisterAvailabilityCallback(ac);
+            return unavailablePhysicalCameras;
+        } catch (Exception e) {
+            throw new ItsException("Exception: ", e);
+        }
+    }
+
     private void doCheckPrimaryCamera(String cameraId) throws ItsException {
         if (mItsCameraIdList == null) {
             mItsCameraIdList = ItsUtils.getItsCompatibleCameraIds(mCameraManager);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index 33f8f2c..ee505fc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
@@ -391,7 +391,7 @@
 
             // Save MPC info once both front primary and rear primary data are collected.
             if (mExecutedMpcTests.size() == 4) {
-                mPce.submit();
+                mPce.submitAndVerify();
             }
             return true;
         }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
index d23d43b..69580bc 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/ByodFlowTestActivity.java
@@ -116,9 +116,9 @@
     private TestListItem mDisableLocationModeThroughMainSwitchTest;
     private TestListItem mDisableLocationModeThroughWorkSwitchTest;
     private TestListItem mPrimaryLocationWhenWorkDisabledTest;
-    private DialogTestListItem mSelectWorkChallenge;
-    private DialogTestListItem mConfirmWorkCredentials;
-    private DialogTestListItem mPatternWorkChallenge;
+//    private DialogTestListItem mSelectWorkChallenge;
+//    private DialogTestListItem mConfirmWorkCredentials;
+//    private DialogTestListItem mPatternWorkChallenge;
     private DialogTestListItem mParentProfilePassword;
     private DialogTestListItem mPersonalRingtonesTest;
     private TestListItem mVpnTest;
@@ -291,19 +291,20 @@
                     R.string.provisioning_byod_workapps_visible_instruction,
                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME),
                     R.drawable.badged_icon);
-
+            /* Disabling due to b/259890166
             mConfirmWorkCredentials = new DialogTestListItem(this,
                     R.string.provisioning_byod_confirm_work_credentials,
                     "BYOD_ConfirmWorkCredentials",
                     R.string.provisioning_byod_confirm_work_credentials_description,
                     new Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_HOME));
-
+            */
+            /* Disable due to  b/242477777
             mPatternWorkChallenge = new DialogTestListItem(this,
                     R.string.provisioning_byod_pattern_work_challenge,
                     "BYOD_PatternWorkChallenge",
                     R.string.provisioning_byod_pattern_work_challenge_description,
                     new Intent(ByodHelperActivity.ACTION_TEST_PATTERN_WORK_CHALLENGE));
-
+            */
             mWiFiDataUsageSettingsVisibleTest = new DialogTestListItem(this,
                     R.string.provisioning_byod_wifi_data_usage_settings,
                     "BYOD_WiFiDataUsageSettingsVisibleTest",
@@ -471,13 +472,13 @@
                 "BYOD_PermissionLockdownTest",
                 R.string.profile_owner_permission_lockdown_test_info,
                 permissionCheckIntent);
-
+        /* Disable due to b/241498104
         mSelectWorkChallenge = new DialogTestListItem(this,
                 R.string.provisioning_byod_select_work_challenge,
                 "BYOD_SelectWorkChallenge",
                 R.string.provisioning_byod_select_work_challenge_description,
                 new Intent(ByodHelperActivity.ACTION_TEST_SELECT_WORK_CHALLENGE));
-
+        */
         mRecentsTest = TestListItem.newTest(this,
                 R.string.provisioning_byod_recents,
                 RecentsRedactionActivity.class.getName(),
@@ -560,11 +561,11 @@
         adapter.add(mVpnTest);
         adapter.add(mAlwaysOnVpnSettingsTest);
         adapter.add(mTurnOffWorkFeaturesTest);
-        adapter.add(mSelectWorkChallenge);
-        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
-            adapter.add(mConfirmWorkCredentials);
-            adapter.add(mPatternWorkChallenge);
-        }
+//        adapter.add(mSelectWorkChallenge);
+//        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)) {
+//            adapter.add(mConfirmWorkCredentials);
+//            adapter.add(mPatternWorkChallenge);
+//        }
         adapter.add(mRecentsTest);
         adapter.add(mOrganizationInfoTest);
         adapter.add(mParentProfilePassword);
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/OWNERS b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/OWNERS
index ea76354..5a93fd0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/OWNERS
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/OWNERS
@@ -1,2 +1,6 @@
 # Bug component: 48448
-alisher@google.com
\ No newline at end of file
+alisher@google.com
+jackcwyu@google.com
+georgekgchang@google.com
+sattiraju@google.com
+henrichataing@google.com
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
index b804b45..a0f5bd0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/security/FingerprintBoundKeysTest.java
@@ -24,6 +24,8 @@
 import android.content.Context;
 import android.content.DialogInterface;
 import android.content.pm.PackageManager;
+import android.hardware.biometrics.BiometricManager;
+import android.hardware.biometrics.BiometricManager.Authenticators;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.Bundle;
 import android.os.CancellationSignal;
@@ -70,6 +72,8 @@
 
     protected boolean useStrongBox;
 
+    private BiometricManager mBiometricManager;
+
     private FingerprintManager mFingerprintManager;
     private KeyguardManager mKeyguardManager;
     private FingerprintAuthDialogFragment mFingerprintDialog;
@@ -92,6 +96,10 @@
         getPassButton().setEnabled(false);
         requestPermissions(new String[]{Manifest.permission.USE_BIOMETRIC},
                 BIOMETRIC_REQUEST_PERMISSION_CODE);
+
+        mBiometricManager = getSystemService(BiometricManager.class);
+
+        checkBiometricStrength();
     }
 
     @Override
@@ -134,6 +142,28 @@
         }
     }
 
+    private void checkBiometricStrength()
+    {
+        if (!hasStrongBiometrics())
+        {
+            // Disable the start button
+            Button startTestButton = findViewById(R.id.sec_start_test_button);
+            startTestButton.setEnabled(false);
+
+            // Show a message that STRONG Biometrics is not supported and user can
+            // pass the test.
+            showToast("Device does not support STRONG Biometric level of authentication.");
+
+            // Allow to pass the test
+            getPassButton().setEnabled(true);
+        }
+    }
+
+    private boolean hasStrongBiometrics() {
+        return mBiometricManager.canAuthenticate(Authenticators.BIOMETRIC_STRONG)
+                != BiometricManager.BIOMETRIC_ERROR_NO_HARDWARE;
+    }
+
     protected void startTest() {
         createKey(false /* hasValidityDuration */);
         prepareEncrypt();
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
index a3f5007..86e2d4f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/BlockingIntentSender.java
@@ -69,6 +69,7 @@
 
         Intent intent = new Intent(mAction);
         intent.setPackage(mTestApis.context().instrumentedContext().getPackageName());
+        intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         PendingIntent pendingIntent = PendingIntent.getBroadcast(
                 mTestApis.context().instrumentedContext(),
                 /* requestCode= */ 0,
diff --git a/common/device-side/util-axt/Android.bp b/common/device-side/util-axt/Android.bp
index 11f851b..d07fe3d 100644
--- a/common/device-side/util-axt/Android.bp
+++ b/common/device-side/util-axt/Android.bp
@@ -16,8 +16,8 @@
     default_applicable_licenses: ["Android-Apache-2.0"],
 }
 
-java_library_static {
-    name: "compatibility-device-util-axt",
+java_defaults {
+    name: "compatibility-device-util-axt-default",
     sdk_version: "test_current",
 
     srcs: [
@@ -31,23 +31,39 @@
         "androidx.test.rules",
         "androidx.test.ext.junit",
         "ub-uiautomator",
-        "mockito-target-minus-junit4",
         "androidx.annotation_annotation",
         "truth-prebuilt",
         "modules-utils-build_system",
     ],
 
     libs: [
-        "android.test.runner",
-        "android.test.base",
+        "android.test.runner.stubs",
+        "android.test.base.stubs",
     ],
 
     jarjar_rules: "protobuf-jarjar-rules.txt",
 }
 
+java_library_static {
+    name: "compatibility-device-util-axt",
+    defaults: ["compatibility-device-util-axt-default"],
+    static_libs: [
+        "mockito-target-minus-junit4",
+    ],
+}
+
+// This target can be used with ExtendedMockito
+java_library {
+    name: "compatibility-device-util-axt-minus-dexmaker",
+    defaults: ["compatibility-device-util-axt-default"],
+    static_libs: [
+        "mockito",
+    ],
+}
+
 filegroup {
     name: "compatibility-device-util-nodeps",
     srcs: [
-         "src/com/android/compatibility/common/util/IBinderParcelable.java",
+        "src/com/android/compatibility/common/util/IBinderParcelable.java",
     ],
 }
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/CtsMouseUtil.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/CtsMouseUtil.java
index e53eb08..5cabd64 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/CtsMouseUtil.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/CtsMouseUtil.java
@@ -126,8 +126,8 @@
         @Override
         public boolean matches(MotionEvent actual) {
             return super.matches(actual)
-                    && ((int) actual.getX()) == mX
-                    && ((int) actual.getY()) == mY;
+                    && Math.round(actual.getX()) == mX
+                    && Math.round(actual.getY()) == mY;
         }
 
         @Override
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
index 06b8cc2..ad78975 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/MediaPerfUtils.java
@@ -16,6 +16,7 @@
 package com.android.compatibility.common.util;
 
 import android.media.MediaFormat;
+import android.util.Log;
 import android.util.Range;
 
 import com.android.compatibility.common.util.DeviceReportLog;
@@ -23,7 +24,6 @@
 import com.android.compatibility.common.util.ResultUnit;
 
 import java.util.Arrays;
-import android.util.Log;
 
 public class MediaPerfUtils {
     private static final String TAG = "MediaPerfUtils";
@@ -36,6 +36,8 @@
     // a limit for the size of the published rates (e.g. upper-limit / lower-limit <= tolerance).
     private static final double FRAMERATE_TOLERANCE = 2.0 * 1.1;
 
+    // Allow extra tolerance when B frames are enabled
+    private static final double EXTRA_TOLERANCE_BFRAMES = 1.25;
     /*
      *  ------------------ HELPER METHODS FOR ACHIEVABLE FRAME RATES ------------------
      */
@@ -146,18 +148,31 @@
     /** Verifies |measuredFps| against reported achievable rates. Returns null if at least
      *  one measurement falls within the margins of the reported range. Otherwise, returns
      *  an error message to display.*/
-    public static String verifyAchievableFrameRates(
-            String name, String mime, int w, int h, boolean fasterIsOk, double... measuredFps) {
+    public static String verifyAchievableFrameRates(String name, String mime, int w,
+            int h, boolean fasterIsOk, double... measuredFps) {
+        return verifyAchievableFrameRates(
+                name, mime, w, h, fasterIsOk, /* bFramesEnabled */ false, measuredFps);
+    }
+
+    /** Verifies |measuredFps| against reported achievable rates allowing extra tolerance when
+     *  B frames are enabled. Returns null if at least one measurement falls within the margins
+     *  of the reported range. Otherwise, returns an error message to display.*/
+    public static String verifyAchievableFrameRates(String name, String mime, int w, int h,
+            boolean fasterIsOk, boolean bFramesEnabled, double... measuredFps) {
         Range<Double> reported =
             MediaUtils.getVideoCapabilities(name, mime).getAchievableFrameRatesFor(w, h);
         String kind = "achievable frame rates for " + name + " " + mime + " " + w + "x" + h;
         if (reported == null) {
             return "Failed to get " + kind;
         }
-        double lowerBoundary1 = reported.getLower() / FRAMERATE_TOLERANCE;
-        double upperBoundary1 = reported.getUpper() * FRAMERATE_TOLERANCE;
-        double lowerBoundary2 = reported.getUpper() / Math.pow(FRAMERATE_TOLERANCE, 2);
-        double upperBoundary2 = reported.getLower() * Math.pow(FRAMERATE_TOLERANCE, 2);
+        double tolerance = FRAMERATE_TOLERANCE;
+        if (bFramesEnabled) {
+            tolerance *= EXTRA_TOLERANCE_BFRAMES;
+        }
+        double lowerBoundary1 = reported.getLower() / tolerance;
+        double upperBoundary1 = reported.getUpper() * tolerance;
+        double lowerBoundary2 = reported.getUpper() / Math.pow(tolerance, 2);
+        double upperBoundary2 = reported.getLower() * Math.pow(tolerance, 2);
         Log.d(TAG, name + " " + mime + " " + w + "x" + h +
                 " lowerBoundary1 " + lowerBoundary1 + " upperBoundary1 " + upperBoundary1 +
                 " lowerBoundary2 " + lowerBoundary2 + " upperBoundary2 " + upperBoundary2 +
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/OWNERS b/common/device-side/util-axt/src/com/android/compatibility/common/util/OWNERS
index b85bed9..56a053b 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/OWNERS
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/OWNERS
@@ -1,2 +1,3 @@
+per-file AnrMonitor.java = file:platform/frameworks/base:/services/core/java/com/android/server/am/OWNERS
 per-file BaseDefaultPermissionGrantPolicyTest.java = file:platform/frameworks/base:/core/java/android/permission/DEFAULT_PERMISSION_GRANT_POLICY_OWNERS
 per-file ReadElf.java = enh@google.com
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
index a9543c2..1611e13 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/UiAutomatorUtils.java
@@ -42,7 +42,13 @@
     private static final String LOG_TAG = "UiAutomatorUtils";
 
     /** Default swipe deadzone percentage. See {@link UiScrollable}. */
-    private static final double DEFAULT_SWIPE_DEADZONE_PCT = 0.1;
+    private static final double DEFAULT_SWIPE_DEADZONE_PCT_TV       = 0.1f;
+    private static final double DEFAULT_SWIPE_DEADZONE_PCT_ALL      = 0.25f;
+    /**
+     * On Wear, some cts tests like CtsPermission3TestCases that run on
+     * low performance device. Keep 0.05 to have better matching.
+     */
+    private static final double DEFAULT_SWIPE_DEADZONE_PCT_WEAR     = 0.05f;
 
     /** Minimum view height accepted (before needing to scroll more). */
     private static final float MIN_VIEW_HEIGHT_DP = 8;
@@ -78,6 +84,16 @@
                 ApplicationProvider.getApplicationContext().getResources().getDisplayMetrics()));
     }
 
+    private static double getSwipeDeadZonePct() {
+        if (FeatureUtil.isTV()) {
+            return DEFAULT_SWIPE_DEADZONE_PCT_TV;
+        } else if (FeatureUtil.isWatch()) {
+            return DEFAULT_SWIPE_DEADZONE_PCT_WEAR;
+        } else {
+            return DEFAULT_SWIPE_DEADZONE_PCT_ALL;
+        }
+    }
+
     public static UiObject2 waitFindObjectOrNull(BySelector selector, long timeoutMs)
             throws UiObjectNotFoundException {
         UiObject2 view = null;
@@ -101,8 +117,7 @@
             }
 
             if (view == null || view.getVisibleBounds().height() < minViewHeightPx) {
-                final double deadZone = !(FeatureUtil.isWatch() || FeatureUtil.isTV())
-                        ? 0.25 : DEFAULT_SWIPE_DEADZONE_PCT;
+                final double deadZone = getSwipeDeadZonePct();
                 UiScrollable scrollable = new UiScrollable(new UiSelector().scrollable(true));
                 scrollable.setSwipeDeadZonePercentage(deadZone);
                 if (scrollable.exists()) {
diff --git a/hostsidetests/appsearch/Android.bp b/hostsidetests/appsearch/Android.bp
index cb2762ca..17e1022 100644
--- a/hostsidetests/appsearch/Android.bp
+++ b/hostsidetests/appsearch/Android.bp
@@ -64,6 +64,7 @@
     manifest: "test-apps/AppSearchHostTestHelperA/AndroidManifest.xml",
     certificate: ":cts-appsearch-hosttest-helper-cert-a",
     sdk_version: "test_current",
+    min_sdk_version: "31",
 }
 
 android_test_helper_app {
@@ -87,4 +88,5 @@
     manifest: "test-apps/AppSearchHostTestHelperB/AndroidManifest.xml",
     certificate: ":cts-appsearch-hosttest-helper-cert-b",
     sdk_version: "test_current",
+    min_sdk_version: "31",
 }
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp
index 134b231..2423476 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "CtsExternalStorageApp",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     target_sdk_version: "29",
     sdk_version: "30",
     static_libs: [
diff --git a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
index a110ce0..e83bcd8e 100644
--- a/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/MediaStorageApp/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "CtsMediaStorageApp",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     sdk_version: "test_current",
     static_libs: [
         "compatibility-device-util-axt",
@@ -37,6 +38,7 @@
 android_test_helper_app {
     name: "CtsMediaStorageApp28",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "28",
     sdk_version: "test_current",
     static_libs: [
         "compatibility-device-util-axt",
@@ -56,6 +58,7 @@
 android_test_helper_app {
     name: "CtsMediaStorageApp29",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     sdk_version: "test_current",
     static_libs: [
         "compatibility-device-util-axt",
diff --git a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp
index 0ec98cb..da3f96e 100644
--- a/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/MultiUserStorageApp/Android.bp
@@ -20,6 +20,7 @@
     name: "CtsMultiUserStorageApp",
     defaults: ["cts_support_defaults"],
     sdk_version: "current",
+    min_sdk_version: "29",
     target_sdk_version: "29",
     static_libs: [
         "androidx.test.rules",
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp
index 4893590..f1eb155 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "CtsReadExternalStorageApp",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     target_sdk_version: "29",
     sdk_version: "30",
     static_libs: [
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp
index 2744c6f..27b2310 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "CtsWriteExternalStorageApp",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     sdk_version: "test_current",
     static_libs: [
         "CtsWriteExternalStorageWriteGiftLib",
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp
index 94742eb..e28c0f0 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp2/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "CtsWriteExternalStorageApp2",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     sdk_version: "test_current",
     static_libs: [
         "CtsWriteExternalStorageWriteGiftLib",
diff --git a/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java b/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
index 5a3e46f..17db439 100644
--- a/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
+++ b/hostsidetests/car/src/android/car/cts/powerpolicy/SilentModeInfo.java
@@ -71,11 +71,7 @@
         boolean[] attrs = new boolean[ATTR_HEADERS.length];
         String[] lines = cmdOutput.split("\n");
 
-        if (lines.length != SilentModeInfo.ATTR_HEADERS.length) {
-            throw new IllegalArgumentException(
-                    "SilentModeQueryResult.parse(): malformatted cmd output: " + cmdOutput);
-        }
-        for (int idx = 0; idx < ATTR_HEADERS.length; idx++) {
+        for (int idx = 0; idx < lines.length; idx++) {
             String[] tokens = lines[idx].trim().split(":");
             if (tokens.length != 2) {
                 throw new IllegalArgumentException(
@@ -90,8 +86,7 @@
                 }
             }
             if (hdrIdx == ATTR_HEADERS.length) {
-                throw new IllegalArgumentException(
-                        "SilentModeQueryResult.parse(): unknown header: " + hdr);
+                continue;
             }
             attrs[hdrIdx] = Boolean.parseBoolean(val.trim());
         }
diff --git a/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTest.java b/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTest.java
index af0d156..6b79ac1 100644
--- a/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTest.java
+++ b/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTest.java
@@ -134,20 +134,30 @@
         if (!SurfaceFlingerProperties.enable_frame_rate_override().orElse(false)) {
             return modesToTest;
         }
+
+        List<Display.Mode> modesWithSameResolution = new ArrayList<>();
+        Display.Mode currentMode = mActivityRule.getActivity().getDisplay().getMode();
+        final long currentDisplayHeight = currentMode.getPhysicalHeight();
+        final long currentDisplayWidth = currentMode.getPhysicalWidth();
+
         Display.Mode[] modes = mActivityRule.getActivity().getDisplay().getSupportedModes();
         for (Display.Mode mode : modes) {
-            for (Display.Mode otherMode : modes) {
+            if (mode.getPhysicalHeight() == currentDisplayHeight
+                    && mode.getPhysicalWidth() == currentDisplayWidth) {
+                modesWithSameResolution.add(mode);
+            }
+        }
+
+        for (Display.Mode mode : modesWithSameResolution) {
+            for (Display.Mode otherMode : modesWithSameResolution) {
                 if (mode.getModeId() == otherMode.getModeId()) {
                     continue;
                 }
 
-                if (mode.getPhysicalHeight() != otherMode.getPhysicalHeight()
-                        || mode.getPhysicalWidth() != otherMode.getPhysicalWidth()) {
-                    continue;
-                }
-
+                // only add if this refresh rate is a multiple of the other
                 if (areEqual(mode.getRefreshRate(), 2 * otherMode.getRefreshRate())) {
                     modesToTest.add(mode);
+                    continue;
                 }
             }
         }
diff --git a/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTestActivity.java b/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTestActivity.java
index c54ae79..3c218b9 100644
--- a/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTestActivity.java
+++ b/hostsidetests/graphics/framerateoverride/app/src/com/android/cts/graphics/framerateoverride/FrameRateOverrideTestActivity.java
@@ -429,7 +429,7 @@
         @Override
         public void testFrameRateOverrideBehavior(FrameRateObserver frameRateObserver,
                 float initialRefreshRate) throws InterruptedException {
-            Log.i(TAG, "Staring testFrameRateOverride");
+            Log.i(TAG, "Starting testFrameRateOverride");
             float halfFrameRate = initialRefreshRate / 2;
 
             waitForRefreshRateChange(initialRefreshRate);
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index ad8e506..5f445d4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -795,7 +795,7 @@
         throw new CecClientWrapperException(ErrorCodes.CecMessageNotFound, expectedMessage.name());
     }
 
-    public void checkNoMessagesSentFromDevice(int timeoutMillis)
+    public void checkNoMessagesSentFromDevice(int timeoutMillis, List<CecOperand> excludeOperands)
             throws CecClientWrapperException {
         checkCecClient();
         long startTime = System.currentTimeMillis();
@@ -810,6 +810,10 @@
                 if (mInputConsole.ready()) {
                     String line = mInputConsole.readLine();
                     if (pattern.matcher(line).matches()) {
+                        CecOperand operand = CecMessage.getOperand(line);
+                        if(excludeOperands.contains(operand)){
+                            continue;
+                        }
                         CLog.v("Found unexpected message in " + line);
                         throw new CecClientWrapperException(
                                 ErrorCodes.CecMessageFound,
@@ -827,6 +831,12 @@
         }
     }
 
+    public void checkNoMessagesSentFromDevice(int timeoutMillis)
+            throws CecClientWrapperException {
+        List<CecOperand> excludeOperands = new ArrayList<>();
+        checkNoMessagesSentFromDevice(timeoutMillis, excludeOperands);
+    }
+
     /**
      * Looks for the CEC message incorrectMessage sent to CEC device toDevice on the cec-client
      * communication channel and throws an CecClientWrapperException if it finds the line that
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
index c62ce8f..19d2c75 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
@@ -33,6 +33,9 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /** HDMI CEC 2.0 general protocol tests */
 @RunWith(DeviceJUnit4ClassRunner.class)
 public final class HdmiCecGeneralProtocolTest extends BaseHdmiCecCtsTest {
@@ -52,30 +55,34 @@
     @Test
     public void cect_4_2_2_ignoreMessagesFromAddressF() throws Exception {
         setCec20();
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_TUNER_DEVICE_STATUS, "01");
+        // get cec reinit messages
+        hdmiCecClient.getAllMessages(mDutLogicalAddresses,
+                HdmiCecConstants.TIMEOUT_CEC_REINIT_SECONDS);
+
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_TUNER_DEVICE_STATUS, ":01");
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.RECORD_ON);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.RECORD_OFF);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.RECORD_TV_SCREEN);
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_DECK_STATUS, "01");
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_DECK_STATUS, ":01");
         sendMessageAndVerifyNoMessageSentFromDevice(
-                CecOperand.CLEAR_ANALOG_TIMER, "02:02:02:02:02:02:00:00:00:02:00");
+                CecOperand.CLEAR_ANALOG_TIMER, ":02:02:02:02:02:02:00:00:00:02:00");
         sendMessageAndVerifyNoMessageSentFromDevice(
-                CecOperand.SET_ANALOG_TIMER, "02:02:02:02:02:02:00:00:00:02:00");
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.PLAY, "05");
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.DECK_CONTROL, "01");
+                CecOperand.SET_ANALOG_TIMER, ":02:02:02:02:02:02:00:00:00:02:00");
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.PLAY, ":05");
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.DECK_CONTROL, ":01");
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_OSD_NAME);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_AUDIO_STATUS);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_SYSTEM_AUDIO_MODE_STATUS);
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.VENDOR_COMMAND, "00:01");
-        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.MENU_REQUEST, "00");
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.VENDOR_COMMAND, ":00:01");
+        sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.MENU_REQUEST, ":00");
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GIVE_POWER_STATUS);
         sendMessageAndVerifyNoMessageSentFromDevice(
-                CecOperand.SET_DIGITAL_TIMER, "02:02:02:02:02:02:00:00:00:02:00");
+                CecOperand.SET_DIGITAL_TIMER, ":02:02:02:02:02:02:00:00:00:02:00");
         sendMessageAndVerifyNoMessageSentFromDevice(
-                CecOperand.CLEAR_DIGITAL_TIMER, "02:02:02:02:02:02:00:00:00:02:00");
+                CecOperand.CLEAR_DIGITAL_TIMER, ":02:02:02:02:02:02:00:00:00:02:00");
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.GET_CEC_VERSION);
         sendMessageAndVerifyNoMessageSentFromDevice(
-                CecOperand.CLEAR_EXTERNAL_TIMER, "02:02:02:02:02:02:00:10:02");
+                CecOperand.CLEAR_EXTERNAL_TIMER, ":02:02:02:02:02:02:00:10:02");
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.REQUEST_SHORT_AUDIO_DESCRIPTOR);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.INITIATE_ARC);
         sendMessageAndVerifyNoMessageSentFromDevice(CecOperand.REQUEST_ARC_INITIATION);
@@ -86,10 +93,17 @@
 
     public void sendMessageAndVerifyNoMessageSentFromDevice(CecOperand message, String params)
             throws Exception {
+        // DeviceDiscoveryAction will send GIVE_OSD_NAME and GIVE_DEVICE_VENDOR_ID
+        // HotplugDetectionAction will send GIVE_PHYSICAL_ADDRESS
+        List<CecOperand> excludeOperands = new ArrayList<>();
+        excludeOperands.add(CecOperand.GIVE_PHYSICAL_ADDRESS);
+        excludeOperands.add(CecOperand.GIVE_DEVICE_VENDOR_ID);
+        excludeOperands.add(CecOperand.GIVE_OSD_NAME);
+
         hdmiCecClient.sendCecMessage(message, params);
         // Default timeout for the incoming command to arrive in response to a request is 2 secs
         // Thus test ensures no messages are sent from DUT for a spacing of 3 secs
-        hdmiCecClient.checkNoMessagesSentFromDevice(3000);
+        hdmiCecClient.checkNoMessagesSentFromDevice(3000, excludeOperands);
     }
 
     public void sendMessageAndVerifyNoMessageSentFromDevice(CecOperand message) throws Exception {
diff --git a/hostsidetests/media/Android.bp b/hostsidetests/media/Android.bp
index 7f174a2..d6367d9 100644
--- a/hostsidetests/media/Android.bp
+++ b/hostsidetests/media/Android.bp
@@ -23,27 +23,25 @@
     defaults: ["cts_defaults"],
     srcs: [
         "src/**/*.java",
-        ":CtsMediaSessionTestCommon",
     ],
     // tag this module as a cts test artifact
     test_suites: [
         "cts",
         "general-tests",
     ],
-
     libs: [
         "cts-tradefed",
         "tradefed",
         "compatibility-host-util",
+        "CtsMediaHostTestCommon",
     ],
-
     static_libs: [
         "cts-host-utils",
         "cts-statsd-atom-host-test-utils",
     ],
-}
-
-filegroup {
-    name: "CtsMediaSessionTestCommon",
-    srcs: ["common/**/*.java"],
+    data: [
+        ":CtsMediaMetricsHostTestApp",
+        ":CtsMediaSessionHostTestApp",
+        ":CtsMediaSessionTestHelper",
+    ],
 }
diff --git a/hostsidetests/media/app/MediaMetricsTest/Android.bp b/hostsidetests/media/app/MediaMetricsTest/Android.bp
index ebab6b4..6278f36 100644
--- a/hostsidetests/media/app/MediaMetricsTest/Android.bp
+++ b/hostsidetests/media/app/MediaMetricsTest/Android.bp
@@ -50,6 +50,7 @@
     ],
     static_libs: [
         "androidx.test.rules",
+        "collector-device-lib",
         "compatibility-device-util-axt",
         "truth-prebuilt",
     ],
diff --git a/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java b/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
index 8c91c5b..3d0edfc 100644
--- a/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
+++ b/hostsidetests/media/app/MediaMetricsTest/src/android/media/metrics/cts/MediaMetricsAtomHostSideTests.java
@@ -19,6 +19,7 @@
 import static com.google.common.truth.Truth.assertThat;
 
 import android.content.Context;
+import android.device.collectors.util.SendToInstrumentation;
 import android.media.metrics.BundleSession;
 import android.media.metrics.EditingSession;
 import android.media.metrics.LogSessionId;
@@ -44,10 +45,6 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-
 @RunWith(AndroidJUnit4.class)
 public class MediaMetricsAtomHostSideTests {
     private static final String TAG = "MediaMetricsAtomHostSideTests";
@@ -300,7 +297,7 @@
                         .setNetworkBytesRead(102400)
                         .setLocalBytesRead(2000)
                         .setNetworkTransferDurationMillis(6000)
-                        .setDrmSessionId(new byte[] {2, 3, 3, 10})
+                        .setDrmSessionId(new byte[]{2, 3, 3, 10})
                         .setMetricsBundle(new Bundle())
                         .addExperimentId(123)
                         .build();
@@ -443,7 +440,7 @@
                         .setNetworkBytesRead(102400)
                         .setLocalBytesRead(2000)
                         .setNetworkTransferDurationMillis(6000)
-                        .setDrmSessionId(new byte[] {2, 3, 3, 10})
+                        .setDrmSessionId(new byte[]{2, 3, 3, 10})
                         .setMetricsBundle(new Bundle())
                         .addExperimentId(123)
                         .build();
@@ -507,7 +504,7 @@
                         .setNetworkBytesRead(102400)
                         .setLocalBytesRead(2000)
                         .setNetworkTransferDurationMillis(6000)
-                        .setDrmSessionId(new byte[] {2, 3, 3, 10})
+                        .setDrmSessionId(new byte[]{2, 3, 3, 10})
                         .setMetricsBundle(new Bundle())
                         .addExperimentId(123)
                         .build();
@@ -540,16 +537,11 @@
     @Test
     public native void testAAudioLegacyInputStream();
 
-    private void writeSessionIdToFile(String stringId) throws IOException {
-        // TODO(b/259258249): Name session id after the test.
-        Context context = InstrumentationRegistry.getInstrumentation().getContext();
+    private void writeSessionIdToFile(String stringId) {
         Log.i(TAG, "log_session_id=" + stringId);
-        File logDir = context.getExternalFilesDir(null);
-        File logFile = new File(logDir, "log_session_id.txt");
-        logFile.createNewFile();
-        FileWriter fw = new FileWriter(logFile.getAbsolutePath());
-        fw.write(stringId);
-        fw.close();
-        Log.i(TAG, "Logged to " + logFile.getAbsolutePath());
+        Bundle b = new Bundle();
+        // TODO(b/265311058): use a common constant for metrics keys.
+        b.putString("log_session_id", stringId);
+        SendToInstrumentation.sendBundle(InstrumentationRegistry.getInstrumentation(), b);
     }
 }
diff --git a/hostsidetests/media/app/MediaSessionTest/Android.bp b/hostsidetests/media/app/MediaSessionTest/Android.bp
index 4dd94a0..71528a7 100644
--- a/hostsidetests/media/app/MediaSessionTest/Android.bp
+++ b/hostsidetests/media/app/MediaSessionTest/Android.bp
@@ -25,7 +25,9 @@
     ],
     srcs: [
         "src/**/*.java",
-        ":CtsMediaSessionTestCommon",
+    ],
+    libs: [
+        "CtsMediaHostTestCommon",
     ],
     static_libs: [
         "androidx.test.rules",
diff --git a/hostsidetests/media/app/MediaSessionTestHelper/Android.bp b/hostsidetests/media/app/MediaSessionTestHelper/Android.bp
index 66340b2..54d98d1 100644
--- a/hostsidetests/media/app/MediaSessionTestHelper/Android.bp
+++ b/hostsidetests/media/app/MediaSessionTestHelper/Android.bp
@@ -21,7 +21,9 @@
     defaults: ["cts_defaults"],
     srcs: [
         "src/**/*.java",
-        ":CtsMediaSessionTestCommon",
+    ],
+    libs: [
+        "CtsMediaHostTestCommon",
     ],
     // tag this module as a cts test artifact
     test_suites: [
diff --git a/hostsidetests/media/common/Android.bp b/hostsidetests/media/common/Android.bp
new file mode 100644
index 0000000..40aa1b2
--- /dev/null
+++ b/hostsidetests/media/common/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+//##############################################################################
+// Build the common library for use device-side
+//##############################################################################
+
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+java_library {
+    name: "CtsMediaHostTestCommon",
+    srcs: ["**/*.java"],
+    sdk_version: "current",
+    host_supported: true,
+}
diff --git a/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
index fe2ac25..335bbc5 100644
--- a/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
+++ b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
@@ -24,60 +24,89 @@
 import android.cts.statsdatom.lib.DeviceUtils;
 import android.cts.statsdatom.lib.ReportUtils;
 
+import com.android.ddmlib.testrunner.RemoteAndroidTestRunner;
 import com.android.os.AtomsProto;
 import com.android.os.StatsLog;
-import com.android.tradefed.build.IBuildInfo;
 import com.android.tradefed.device.DeviceNotAvailableException;
-import com.android.tradefed.testtype.DeviceTestCase;
-import com.android.tradefed.testtype.IBuildReceiver;
+import com.android.tradefed.device.ITestDevice;
+import com.android.tradefed.invoker.TestInformation;
+import com.android.tradefed.log.LogUtil;
+import com.android.tradefed.metrics.proto.MetricMeasurement;
+import com.android.tradefed.result.CollectingTestListener;
+import com.android.tradefed.result.TestDescription;
+import com.android.tradefed.result.TestResult;
+import com.android.tradefed.result.TestRunResult;
+import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.testtype.junit4.AfterClassWithInfo;
+import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
+import com.android.tradefed.testtype.junit4.BeforeClassWithInfo;
 
 import com.google.common.truth.Correspondence;
 
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.FileNotFoundException;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Collectors;
 
-public class MediaMetricsAtomTests extends DeviceTestCase implements IBuildReceiver {
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+@RunWith(DeviceJUnit4ClassRunner.class)
+public class MediaMetricsAtomTests extends BaseHostJUnit4Test {
+
+    private static final String TEST_RUNNER = "androidx.test.runner.AndroidJUnitRunner";
     private static final String TAG = "MediaMetricsAtomTests";
     public static final String TEST_APK = "CtsMediaMetricsHostTestApp.apk";
     public static final String TEST_PKG = "android.media.metrics.cts";
     private static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
     private static final String FEATURE_MICROPHONE = "android.hardware.microphone";
     private static final int MAX_BUFFER_CAPACITY = 30 * 1024 * 1024; // 30M
-    private IBuildInfo mCtsBuild;
 
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        assertThat(mCtsBuild).isNotNull();
-        DeviceUtils.installTestApp(getDevice(), TEST_APK, TEST_PKG, mCtsBuild);
+
+    @BeforeClassWithInfo
+    public static void installApp(TestInformation testInfo)
+            throws DeviceNotAvailableException, FileNotFoundException {
+        assertThat(testInfo.getBuildInfo()).isNotNull();
+        DeviceUtils.installTestApp(testInfo.getDevice(), TEST_APK, TEST_PKG,
+                testInfo.getBuildInfo());
+    }
+
+    @Before
+    public void setUp() throws Exception {
         ConfigUtils.removeConfig(getDevice());
         ReportUtils.clearReports(getDevice());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
     }
 
-    @Override
-    protected void tearDown() throws Exception {
+    @After
+    public void tearDown() throws Exception {
         ConfigUtils.removeConfig(getDevice());
         ReportUtils.clearReports(getDevice());
-        DeviceUtils.uninstallTestApp(getDevice(), TEST_PKG);
-        super.tearDown();
     }
 
-    @Override
-    public void setBuild(IBuildInfo buildInfo) {
-        mCtsBuild = buildInfo;
+    @AfterClassWithInfo
+    public static void uninstallApp(TestInformation testInfo) throws Exception {
+        DeviceUtils.uninstallTestApp(testInfo.getDevice(), TEST_PKG);
     }
 
+
+    @Test
     public void testPlaybackStateEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackStateEvent_default");
+                "testPlaybackStateEvent_default", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -90,12 +119,13 @@
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(-1L);
     }
 
+    @Test
     public void testPlaybackStateEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackStateEvent");
+                "testPlaybackStateEvent", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -109,12 +139,13 @@
     }
 
     // same as testPlaybackStateEvent, but we use the BundleSession transport.
+    @Test
     public void testBundleSessionPlaybackStateEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testBundleSessionPlaybackStateEvent");
+                "testBundleSessionPlaybackStateEvent", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -127,13 +158,13 @@
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
     }
 
-
+    @Test
     public void testPlaybackErrorEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackErrorEvent_default");
+                "testPlaybackErrorEvent_default", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -151,12 +182,13 @@
                         + ".testPlaybackErrorEvent")).isTrue();
     }
 
+    @Test
     public void testPlaybackErrorEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_ERROR_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackErrorEvent");
+                "testPlaybackErrorEvent", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -174,12 +206,13 @@
                         + ".testPlaybackErrorEvent")).isTrue();
     }
 
+    @Test
     public void testTrackChangeEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testTrackChangeEvent_default");
+                "testTrackChangeEvent_default", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -203,12 +236,13 @@
         assertThat(result.getChannelCount()).isEqualTo(-1);
     }
 
+    @Test
     public void testTrackChangeEvent_text() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testTrackChangeEvent_text");
+                "testTrackChangeEvent_text", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -230,12 +264,13 @@
         assertThat(result.getLanguageRegion()).isEqualTo("US");
     }
 
+    @Test
     public void testTrackChangeEvent_audio() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testTrackChangeEvent_audio");
+                "testTrackChangeEvent_audio", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -259,12 +294,13 @@
         assertThat(result.getChannelCount()).isEqualTo(3);
     }
 
+    @Test
     public void testTrackChangeEvent_video() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_TRACK_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testTrackChangeEvent_video");
+                "testTrackChangeEvent_video", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -289,12 +325,13 @@
         assertThat(result.getVideoFrameRate()).isEqualTo(60);
     }
 
+    @Test
     public void testNetworkEvent_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testNetworkEvent_default");
+                "testNetworkEvent_default", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -308,11 +345,13 @@
         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_UNKNOWN");
     }
 
+    @Test
     public void testNetworkEvent() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_NETWORK_INFO_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testNetworkEvent");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testNetworkEvent",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -326,12 +365,13 @@
         assertThat(result.getType().toString()).isEqualTo("NETWORK_TYPE_WIFI");
     }
 
+    @Test
     public void testPlaybackMetrics_default() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testPlaybackMetrics_default");
+                "testPlaybackMetrics_default", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -361,11 +401,13 @@
         assertThat(result.getDrmSessionId().length()).isEqualTo(0);
     }
 
+    @Test
     public void testPlaybackMetrics() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackMetrics");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testPlaybackMetrics",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
@@ -397,70 +439,83 @@
         assertThat(result.getDrmSessionId()).isNotEqualTo(null);
     }
 
+    @Test
     public void testSessionId() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testSessionId");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testSessionId",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data).isEmpty();
     }
 
+    @Test
     public void testRecordingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testRecordingSession");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testRecordingSession",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data).isEmpty();
     }
 
+    @Test
     public void testEditingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testEditingSession");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testEditingSession",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data).isEmpty();
     }
 
+    @Test
     public void testTranscodingSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testTranscodingSession");
+                "testTranscodingSession", new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data).isEmpty();
     }
 
+    @Test
     public void testBundleSession() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testBundleSession");
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testBundleSession",
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         assertThat(data).isEmpty();
     }
 
+    @Test
     public void testAppBlocklist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppBlocklist");
+        LogSessionIdListener listener = new LogSessionIdListener();
+        runDeviceTests(getDevice(),
+                TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppBlocklist",
+                listener);
+        String logSessionId = listener.getLogSessionId();
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
-        String logSessionId = getLogSessionId();
         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
@@ -470,17 +525,18 @@
                 "getLogSessionId")).doesNotContain(logSessionId);
     }
 
-
+    @Test
     public void testAttributionBlocklist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        LogSessionIdListener listener = new LogSessionIdListener();
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testAttributionBlocklist");
+                "testAttributionBlocklist", listener);
+        String logSessionId = listener.getLogSessionId();
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        String logSessionId = getLogSessionId();
         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
                 AtomsProto.Atom::getMediametricsPlaybackReported);
@@ -508,15 +564,18 @@
         assertThat(result.getNetworkTransferDurationMillis()).isEqualTo(6000);
     }
 
+    @Test
     public void testAppAllowlist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIA_PLAYBACK_STATE_CHANGED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", "testAppAllowlist");
+        LogSessionIdListener listener = new LogSessionIdListener();
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
+                "testAppAllowlist", listener);
+        String logSessionId = listener.getLogSessionId();
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        String logSessionId = getLogSessionId();
         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
         List<AtomsProto.MediaPlaybackStateChanged> stateChangedList = toMyAtoms(data,
                 AtomsProto.Atom::getMediaPlaybackStateChanged);
@@ -530,16 +589,18 @@
         assertThat(result.getTimeSincePlaybackCreatedMillis()).isEqualTo(1763L);
     }
 
+    @Test
     public void testAttributionAllowlist() throws Exception {
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_PLAYBACK_REPORTED_FIELD_NUMBER);
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
+        LogSessionIdListener listener = new LogSessionIdListener();
+        runDeviceTests(getDevice(), TEST_PKG,
                 "android.media.metrics.cts.MediaMetricsAtomHostSideTests",
-                "testAttributionAllowlist");
+                "testAttributionAllowlist", listener);
+        String logSessionId = listener.getLogSessionId();
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         List<StatsLog.EventMetricData> data = ReportUtils.getEventMetricDataList(getDevice());
-        String logSessionId = getLogSessionId();
         assertWithMessage("log session id").that(logSessionId).isNotEmpty();
         List<AtomsProto.MediametricsPlaybackReported> playbackReportedList = toMyAtoms(data,
                 AtomsProto.Atom::getMediametricsPlaybackReported);
@@ -595,8 +656,9 @@
         ConfigUtils.uploadConfigForPushedAtom(getDevice(), DeviceUtils.STATSD_ATOM_TEST_PKG,
                 AtomsProto.Atom.MEDIAMETRICS_AAUDIOSTREAM_REPORTED_FIELD_NUMBER);
 
-        DeviceUtils.runDeviceTests(getDevice(), TEST_PKG,
-                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", testFunctionName);
+        runDeviceTests(getDevice(), TEST_PKG,
+                "android.media.metrics.cts.MediaMetricsAtomHostSideTests", testFunctionName,
+                new LogSessionIdListener());
         Thread.sleep(AtomTestUtils.WAIT_TIME_LONG);
 
         validateAAudioStreamAtom(direction);
@@ -608,6 +670,7 @@
      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
      * the data is collected correctly.
      */
+    @Test
     public void testAAudioLowLatencyInputStream() throws Exception {
         runAAudioTestAndValidate(FEATURE_MICROPHONE,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_INPUT_VALUE,
@@ -620,6 +683,7 @@
      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
      * the data is collected correctly.
      */
+    @Test
     public void testAAudioLowLatencyOutputStream() throws Exception {
         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_OUTPUT_VALUE,
@@ -632,6 +696,7 @@
      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
      * the data is collected correctly.
      */
+    @Test
     public void testAAudioLegacyInputStream() throws Exception {
         runAAudioTestAndValidate(FEATURE_MICROPHONE,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_INPUT_VALUE,
@@ -644,23 +709,93 @@
      * After that, the event metric data for MediametricsAAudioStreamReported is pushed to verify
      * the data is collected correctly.
      */
+    @Test
     public void testAAudioLegacyOutputStream() throws Exception {
         runAAudioTestAndValidate(FEATURE_AUDIO_OUTPUT,
                 AtomsProto.MediametricsAAudioStreamReported.Direction.DIRECTION_OUTPUT_VALUE,
                 "testAAudioLegacyOutputStream");
     }
 
-    private String getLogSessionId() throws DeviceNotAvailableException {
-        // TODO(b/259258249): Name session id file after the test.
-        String logSessionId = getDevice().pullFileContents(
-                "/storage/emulated/0/Android/data/android.media.metrics"
-                        + ".cts/files/log_session_id" + ".txt");
-        return logSessionId;
-    }
-
     private static <T> List<T> toMyAtoms(List<StatsLog.EventMetricData> data,
             Function<AtomsProto.Atom, T> mapper) {
         return data.stream().map(StatsLog.EventMetricData::getAtom).map(mapper).collect(
                 Collectors.toUnmodifiableList());
     }
+
+    // TODO(b/265208340): update DeviceUtils to accept listeners.
+
+    /**
+     * Runs device side tests.
+     *
+     * @param device         Can be retrieved by running getDevice() in a class that extends
+     *                       DeviceTestCase
+     * @param pkgName        Test package name, such as "com.android.server.cts.statsdatom"
+     * @param testClassName  Test class name which can either be a fully qualified name or "." + a
+     *                       class name; if null, all test in the package will be run
+     * @param testMethodName Test method name; if null, all tests in class or package will be run
+     * @return {@link TestRunResult} of this invocation
+     */
+    @Nonnull
+    private static TestRunResult runDeviceTests(ITestDevice device, String pkgName,
+            @Nullable String testClassName, @Nullable String testMethodName,
+            LogSessionIdListener listener)
+            throws DeviceNotAvailableException {
+        if (testClassName != null && testClassName.startsWith(".")) {
+            testClassName = pkgName + testClassName;
+        }
+
+        RemoteAndroidTestRunner testRunner = new RemoteAndroidTestRunner(
+                pkgName, TEST_RUNNER, device.getIDevice());
+        if (testClassName != null && testMethodName != null) {
+            testRunner.setMethodName(testClassName, testMethodName);
+        } else if (testClassName != null) {
+            testRunner.setClassName(testClassName);
+        }
+
+        assertThat(device.runInstrumentationTests(testRunner, listener)).isTrue();
+
+        final TestRunResult result = listener.getCurrentRunResults();
+        if (result.isRunFailure()) {
+            throw new Error("Failed to successfully run device tests for "
+                    + result.getName() + ": " + result.getRunFailureMessage());
+        }
+        if (result.getNumTests() == 0) {
+            throw new Error("No tests were run on the device");
+        }
+        if (result.hasFailedTests()) {
+            StringBuilder errorBuilder = new StringBuilder("On-device tests failed:\n");
+            for (Map.Entry<TestDescription, TestResult> resultEntry :
+                    result.getTestResults().entrySet()) {
+                if (!resultEntry.getValue().getStatus().equals(
+                        com.android.ddmlib.testrunner.TestResult.TestStatus.PASSED)) {
+                    errorBuilder.append(resultEntry.getKey().toString());
+                    errorBuilder.append(":\n");
+                    errorBuilder.append(resultEntry.getValue().getStackTrace());
+                }
+            }
+            throw new AssertionError(errorBuilder.toString());
+        }
+
+        return result;
+    }
+
+    private static final class LogSessionIdListener extends CollectingTestListener {
+
+        @Nullable
+        private String mLogSessionId;
+
+        @Nullable
+        public String getLogSessionId() {
+            return mLogSessionId;
+        }
+
+        @Override
+        public void testEnded(TestDescription test, long endTime,
+                HashMap<String, MetricMeasurement.Metric> testMetrics) {
+            super.testEnded(test, endTime, testMetrics);
+            LogUtil.CLog.i("testEnded  MetricMeasurement.Metric " + testMetrics);
+            // TODO(b/265311058): use a common constant for metrics keys.
+            mLogSessionId = testMetrics.get("log_session_id").getMeasurements().getSingleString();
+        }
+    }
 }
diff --git a/hostsidetests/multidevices/bluetooth/Android.bp b/hostsidetests/multidevices/bluetooth/Android.bp
new file mode 100644
index 0000000..dc3efac
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/Android.bp
@@ -0,0 +1,42 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+python_test_host {
+    name: "CtsBluetoothMultiDevicesTestCases",
+    main: "bluetooth_multi_devices_test.py",
+    srcs: ["bluetooth_multi_devices_test.py"],
+    libs: [
+        "mobly",
+    ],
+    test_suites: [
+        "cts",
+        "general-tests",
+    ],
+    test_options: {
+        unit_test: false,
+    },
+    data: [
+        // Package the snippet with the mobly test
+        ":bluetooth_multi_devices_snippet",
+    ],
+    version: {
+        py3: {
+            embedded_launcher: true,
+        },
+    },
+}
diff --git a/hostsidetests/multidevices/bluetooth/AndroidTest.xml b/hostsidetests/multidevices/bluetooth/AndroidTest.xml
new file mode 100644
index 0000000..2bc2216
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/AndroidTest.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+<configuration description="Config for CTS Bluetooth multi devices test cases">
+    <option name="test-suite-tag" value="cts" />
+    <option name="config-descriptor:metadata" key="component" value="bluetooth" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_secondary_user" />
+
+    <device name="device1">
+        <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+            <option name="test-file-name" value="bluetooth_multi_devices_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" />
+        </target_preparer>
+    </device>
+    <device name="device2">
+        <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+            <option name="test-file-name" value="bluetooth_multi_devices_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" />
+        </target_preparer>
+    </device>
+
+    <test class="com.android.tradefed.testtype.mobly.MoblyBinaryHostTest">
+      <!-- The mobly-par-file-name should match the module name -->
+      <option name="mobly-par-file-name" value="CtsBluetoothMultiDevicesTestCases" />
+      <!-- Timeout limit in milliseconds for all test cases of the python binary -->
+      <option name="mobly-test-timeout" value="180000" />
+    </test>
+</configuration>
+
diff --git a/hostsidetests/multidevices/bluetooth/OWNERS b/hostsidetests/multidevices/bluetooth/OWNERS
new file mode 100644
index 0000000..21197f3
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/OWNERS
@@ -0,0 +1,10 @@
+# Bug component: 27441
+
+eruffieux@google.com
+girardier@google.com
+muhammadfalam@google.com
+rahulsabnis@google.com
+sattiraju@google.com
+siyuanh@google.com
+sungsoo@google.com
+wescande@google.com
diff --git a/hostsidetests/multidevices/bluetooth/bluetooth_multi_devices_test.py b/hostsidetests/multidevices/bluetooth/bluetooth_multi_devices_test.py
new file mode 100644
index 0000000..145d22e
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/bluetooth_multi_devices_test.py
@@ -0,0 +1,79 @@
+# Lint as: python3
+"""
+Bluetooth multi devices tests.
+"""
+import sys
+import os.path
+import time
+import re
+
+import logging
+logging.basicConfig(filename="/tmp/bluetooth_multi_devices_test_log.txt", level=logging.INFO)
+
+from mobly import asserts
+from mobly import base_test
+from mobly import test_runner
+from mobly import utils
+from mobly.controllers import android_device
+
+BLUETOOTH_MULTI_DEVICES_SNIPPET_PACKAGE = 'com.google.snippet.bluetooth'
+
+GATT_PRIORITY_BALANCED = 0
+GATT_PRIORITY_HIGH = 1
+GATT_PRIORITY_LOW = 2
+CONNECTION_PRIORITY_CCC = 3
+
+class BluetoothMultiDevicesTest(base_test.BaseTestClass):
+
+  def setup_class(self):
+    # Declare that two Android devices are needed.
+    self.client, self.server = self.register_controller(
+      android_device, min_number=2)
+
+    def setup_device(device):
+      device.load_snippet('bluetooth_multi_devices_snippet', BLUETOOTH_MULTI_DEVICES_SNIPPET_PACKAGE)
+
+    # Sets up devices in parallel to save time.
+    utils.concurrent_exec(
+        setup_device, ((self.client,), (self.server,)),
+        max_workers=2,
+        raise_on_exception=True)
+
+  def test_gatt_connection_interval_test_case(self):
+
+    if not self.server.bluetooth_multi_devices_snippet.isBluetoothOn() or\
+        not self.client.bluetooth_multi_devices_snippet.isBluetoothOn():
+      self.server.bluetooth_multi_devices_snippet.enableBluetooth()
+      self.client.bluetooth_multi_devices_snippet.enableBluetooth()
+
+      #TODO implement callback (b/266635827)
+      time.sleep(3)
+
+      asserts.assert_true(self.server.bluetooth_multi_devices_snippet.isBluetoothOn(), 'Server Bluetooth is OFF')
+      asserts.assert_true(self.client.bluetooth_multi_devices_snippet.isBluetoothOn(), 'Client Bluetooth is OFF')
+
+
+    # Start server, register callback, connect client, wait for connection
+    self.server_name = self.server.bluetooth_multi_devices_snippet.createServer()
+    asserts.assert_true(self.client.bluetooth_multi_devices_snippet.discoverServer(self.server_name), "Server not discovered");
+    self.client.bluetooth_multi_devices_snippet.connectGatt(CONNECTION_PRIORITY_CCC)
+    asserts.assert_true(self.server.bluetooth_multi_devices_snippet.waitConnection(), "Device not connected before timeout")
+
+    used_interval = self.server.bluetooth_multi_devices_snippet.receivePriority()
+    asserts.assert_true(used_interval is CONNECTION_PRIORITY_CCC, "Connection priority is not equal")
+
+    self.client.bluetooth_multi_devices_snippet.updatePriority(GATT_PRIORITY_HIGH)
+    used_interval = self.server.bluetooth_multi_devices_snippet.receivePriority()
+    asserts.assert_true(used_interval is GATT_PRIORITY_HIGH, "Connection priority is not equal, expected: " + str(GATT_PRIORITY_HIGH) + " received: " + str(used_interval))
+
+    self.client.bluetooth_multi_devices_snippet.disconnectGatt()
+    self.client.bluetooth_multi_devices_snippet.clearClient()
+
+    self.server.bluetooth_multi_devices_snippet.destroyServer()
+
+
+if __name__ == '__main__':
+  # Take test args
+  index = sys.argv.index('--')
+  sys.argv = sys.argv[:1] + sys.argv[index + 1:]
+  test_runner.main()
diff --git a/hostsidetests/multidevices/bluetooth/snippet/Android.bp b/hostsidetests/multidevices/bluetooth/snippet/Android.bp
new file mode 100644
index 0000000..c9cd2ec
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/snippet/Android.bp
@@ -0,0 +1,33 @@
+// 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 {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+android_test {
+    name: "bluetooth_multi_devices_snippet",
+    sdk_version: "current",
+    srcs: [
+        "BluetoothGattMultiDevicesClient.java",
+        "BluetoothGattMultiDevicesServer.java",
+        "BluetoothGattMultiDevicesSnippet.java",
+    ],
+    manifest: "AndroidManifest.xml",
+    static_libs: [
+        "androidx.test.runner",
+        "guava",
+        "mobly-snippet-lib",
+    ],
+}
diff --git a/hostsidetests/multidevices/bluetooth/snippet/AndroidManifest.xml b/hostsidetests/multidevices/bluetooth/snippet/AndroidManifest.xml
new file mode 100644
index 0000000..75724bf
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/snippet/AndroidManifest.xml
@@ -0,0 +1,38 @@
+<?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.
+-->
+<manifest
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.google.snippet.bluetooth">
+  <!-- Declare the minimum Android SDK version and internet permission,
+       which are required by Mobly Snippet Lib since it uses network socket. -->
+  <uses-sdk android:minSdkVersion="Tiramisu" />
+  <uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
+  <uses-permission android:name="android.permission.BLUETOOTH_ADVERTISE" />
+  <uses-permission android:name="android.permission.BLUETOOTH_SCAN" />
+  <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+  <application>
+    <!-- Add any classes that implement the Snippet interface as meta-data, whose
+         value is a comma-separated string, each section being the package path
+         of a snippet class -->
+    <meta-data
+        android:name="mobly-snippets"
+        android:value="com.google.snippet.bluetooth.BluetoothGattMultiDevicesSnippet" />
+  </application>
+  <!-- Add an instrumentation tag so that the app can be launched through an
+       instrument command. The runner `com.google.android.mobly.snippet.SnippetRunner`
+       is derived from `AndroidJUnitRunner`, and is required to use the
+       Mobly Snippet Lib. -->
+  <instrumentation
+      android:name="com.google.android.mobly.snippet.SnippetRunner"
+      android:targetPackage="com.google.snippet.bluetooth" />
+</manifest>
diff --git a/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesClient.java b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesClient.java
new file mode 100644
index 0000000..c6e9d552
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesClient.java
@@ -0,0 +1,123 @@
+/*
+ * 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.
+ */
+
+package com.google.snippet.bluetooth;
+
+import static android.bluetooth.BluetoothDevice.PHY_LE_1M_MASK;
+import static android.bluetooth.BluetoothDevice.TRANSPORT_LE;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.app.UiAutomation;
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGatt;
+import android.bluetooth.BluetoothGattCallback;
+import android.bluetooth.BluetoothManager;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import java.util.concurrent.CountDownLatch;
+
+public final class BluetoothGattMultiDevicesClient {
+
+    private static final String TAG = "BluetoothGattMultiDevicesClient";
+
+    private Context mContext;
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothGatt mBluetoothGatt;
+
+    private CountDownLatch mServerFoundBlocker = null;
+
+    private UiAutomation mUiAutomation;
+
+    private static final int CALLBACK_TIMEOUT_SEC = 60;
+
+    private String mServerName;
+    private BluetoothDevice mServer;
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (BluetoothDevice.ACTION_FOUND.equals(intent.getAction())) {
+                BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                Log.i(TAG, "Device discovered: " + device.getName()
+                        + " Server name: " + mServerName);
+                if (mServerName.equals(device.getName())) {
+                    Log.i(TAG, "Server discovered");
+                    mServer = device;
+                    mServerFoundBlocker.countDown();
+                }
+            }
+        }
+    };
+
+    public BluetoothGattMultiDevicesClient(Context context, BluetoothManager manager) {
+        mContext = context;
+        mBluetoothAdapter = manager.getAdapter();
+        mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity();
+
+        IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
+        mContext.registerReceiver(mReceiver, filter);
+
+    }
+
+    public void clear() {
+        mContext.unregisterReceiver(mReceiver);
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    private boolean startDiscovery() throws InterruptedException {
+        mServerFoundBlocker = new CountDownLatch(1);
+        mBluetoothAdapter.startDiscovery();
+        boolean timeout = !mServerFoundBlocker.await(CALLBACK_TIMEOUT_SEC, SECONDS);
+        mBluetoothAdapter.cancelDiscovery();
+        if (timeout) {
+            Log.e(TAG, "Did not discover server");
+            return false;
+        }
+        return true;
+    }
+
+    public boolean discoverServer(String deviceName) {
+        try {
+            mServerName = deviceName;
+            return startDiscovery();
+        } catch (Exception e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }
+
+    public void connect(int priority) {
+        mBluetoothGatt = mServer.connectGatt(mContext, false,
+                TRANSPORT_LE, PHY_LE_1M_MASK, priority, null, new BluetoothGattCallback(){});
+    }
+
+    public void disconnect() {
+        mBluetoothGatt.disconnect();
+    }
+
+    public void updatePriority(int priority) {
+        mBluetoothGatt.requestConnectionPriority(priority);
+    }
+}
diff --git a/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesServer.java b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesServer.java
new file mode 100644
index 0000000..fa196da
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesServer.java
@@ -0,0 +1,166 @@
+/*
+ * 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.
+ */
+
+package com.google.snippet.bluetooth;
+
+import static android.bluetooth.BluetoothGattService.SERVICE_TYPE_PRIMARY;
+
+import static java.util.concurrent.TimeUnit.SECONDS;
+
+import android.bluetooth.BluetoothAdapter;
+import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattServer;
+import android.bluetooth.BluetoothGattServerCallback;
+import android.bluetooth.BluetoothGattService;
+import android.bluetooth.BluetoothManager;
+import android.bluetooth.BluetoothProfile;
+import android.bluetooth.le.AdvertiseCallback;
+import android.bluetooth.le.AdvertiseData;
+import android.bluetooth.le.AdvertiseSettings;
+import android.bluetooth.le.BluetoothLeAdvertiser;
+import android.content.Context;
+import android.os.ParcelUuid;
+import android.util.Log;
+
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+public final class BluetoothGattMultiDevicesServer {
+
+    private static final String TAG = "BluetoothGattMultiDevicesServer";
+
+    private Context mContext;
+    private BluetoothManager mBluetoothManager;
+    private BluetoothAdapter mBluetoothAdapter;
+    private BluetoothGattServer mBluetoothGattServer;
+    private BluetoothLeAdvertiser mBluetoothLeAdvertiser;
+
+    private int mConnectionPriority = -1;
+    private CountDownLatch mPriorityBlocker = null;
+    private CountDownLatch mConnectionBlocker = null;
+
+    private static final int CALLBACK_TIMEOUT_SEC = 60;
+
+    private BluetoothGattServerCallback mServerCallback = new BluetoothGattServerCallback() {
+
+        @Override
+        public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
+            Log.i(TAG, "onConnectionStateChange: newState=" + newState);
+            if (newState == BluetoothProfile.STATE_CONNECTED && mConnectionBlocker != null) {
+                mConnectionBlocker.countDown();
+            }
+        }
+
+        @Override
+        public void onPriorityChanged(BluetoothDevice device, int priority) {
+            Log.i(TAG, "onPriorityChanged: priority=" + priority);
+            if (priority == 0) {
+                return;
+            }
+            mConnectionPriority = priority;
+            if (mPriorityBlocker != null) {
+                mPriorityBlocker.countDown();
+            }
+        }
+
+    };
+
+    private AdvertiseCallback mAdvertiseCallback = new AdvertiseCallback() {
+        @Override
+        public void onStartSuccess(AdvertiseSettings settingsInEffect) {
+        }
+
+        @Override
+        public void onStartFailure(int errorCode) {
+        }
+    };
+
+    public BluetoothGattMultiDevicesServer(Context context, BluetoothManager manager) {
+        mContext = context;
+        mBluetoothManager = manager;
+        mBluetoothAdapter = manager.getAdapter();
+    }
+
+    public String createServer() {
+        mBluetoothLeAdvertiser = mBluetoothAdapter.getBluetoothLeAdvertiser();
+        AdvertiseSettings settings = new AdvertiseSettings.Builder()
+                .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED)
+                .setConnectable(true)
+                .setTimeout(0)
+                .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
+                .build();
+
+        AdvertiseData data = new AdvertiseData.Builder()
+                .setIncludeDeviceName(true)
+                .setIncludeTxPowerLevel(false)
+                .addServiceUuid(new ParcelUuid(UUID.fromString(
+                        "0000fffa-0000-1000-8000-00805f9b34fb")))
+                .build();
+
+        mBluetoothLeAdvertiser
+                .startAdvertising(settings, data, mAdvertiseCallback);
+
+        mBluetoothGattServer = mBluetoothManager.openGattServer(mContext, mServerCallback);
+
+        BluetoothGattService service = new BluetoothGattService(UUID.fromString(
+                "0000fffa-0000-1000-8000-00805f9b34fb"), SERVICE_TYPE_PRIMARY);
+        service.addCharacteristic(new BluetoothGattCharacteristic(UUID.fromString(
+                "0000fffb-0000-1000-8000-00805f9b34fb"), 0x02, 0x01));
+        mBluetoothGattServer.addService(service);
+        return mBluetoothAdapter.getName();
+    }
+
+    private boolean waitConnectCallback() throws InterruptedException {
+        mConnectionBlocker = new CountDownLatch(1);
+        return mConnectionBlocker.await(CALLBACK_TIMEOUT_SEC, SECONDS);
+    }
+
+    public boolean waitConnection() {
+        if (mBluetoothManager.getConnectedDevices(BluetoothProfile.GATT_SERVER).size() > 0) {
+            return true;
+        }
+        try {
+            return waitConnectCallback();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+        return false;
+    }
+
+    public void destroyServer() {
+        mBluetoothGattServer.close();
+    }
+
+    private int waitForPriority() throws InterruptedException {
+        mConnectionPriority = -1;
+        mPriorityBlocker = new CountDownLatch(1);
+        boolean timeout = !mPriorityBlocker.await(CALLBACK_TIMEOUT_SEC, SECONDS);
+        if (timeout) {
+            Log.e(TAG, "Did not receive priority update");
+        }
+        return mConnectionPriority;
+    }
+
+    public int receivePriority() {
+        try {
+            return waitForPriority();
+        } catch (InterruptedException e) {
+            Log.e(TAG, "", e);
+        }
+        return -1;
+    }
+}
diff --git a/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesSnippet.java b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesSnippet.java
new file mode 100644
index 0000000..7b78d84
--- /dev/null
+++ b/hostsidetests/multidevices/bluetooth/snippet/BluetoothGattMultiDevicesSnippet.java
@@ -0,0 +1,93 @@
+/*
+ * 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.
+ */
+
+package com.google.snippet.bluetooth;
+
+import android.bluetooth.BluetoothManager;
+import android.content.Context;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.google.android.mobly.snippet.Snippet;
+import com.google.android.mobly.snippet.rpc.Rpc;
+
+public class BluetoothGattMultiDevicesSnippet implements Snippet {
+
+    private static final String TAG = "BluetoothGattMultiDevicesSnippet";
+
+    private BluetoothGattMultiDevicesServer mGattServer;
+    private BluetoothGattMultiDevicesClient mGattClient;
+
+    private Context mContext;
+    private BluetoothManager mBluetoothManager;
+
+    public BluetoothGattMultiDevicesSnippet() {
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        mBluetoothManager = mContext.getSystemService(BluetoothManager.class);
+        mGattServer = new BluetoothGattMultiDevicesServer(mContext, mBluetoothManager);
+        mGattClient = new BluetoothGattMultiDevicesClient(mContext, mBluetoothManager);
+    }
+
+    @Rpc(description = "Creates Bluetooth GATT server and returns device address.")
+    public String createServer() {
+        return mGattServer.createServer();
+    }
+
+    @Rpc(description = "Waits for a connection to be made btween client and server")
+    public boolean waitConnection() {
+        return mGattServer.waitConnection();
+    }
+
+    @Rpc(description = "Destroys Bluetooth GATT server.")
+    public void destroyServer() {
+        mGattServer.destroyServer();
+    }
+
+    @Rpc(description = "Destroys Bluetooth GATT server.")
+    public int receivePriority() {
+        return mGattServer.receivePriority();
+    }
+
+    @Rpc(description = "Try to discover Bluetooth GATT server")
+    public boolean discoverServer(String name) {
+        return mGattClient.discoverServer(name);
+    }
+
+    @Rpc(description = "Creates Bluetooth GATT server and returns device address")
+    public void connectGatt(int priority) {
+        mGattClient.connect(priority);
+    }
+
+    @Rpc(description = "Creates Bluetooth GATT server and returns device address")
+    public void disconnectGatt() {
+        mGattClient.disconnect();
+    }
+
+    @Rpc(description = "Creates Bluetooth GATT server and returns device address")
+    public void updatePriority(int priority) {
+        mGattClient.updatePriority(priority);
+    }
+
+    @Rpc(description = "Checks Bluetooth state")
+    public boolean isBluetoothOn() {
+        return mBluetoothManager.getAdapter().isEnabled();
+    }
+
+    @Rpc(description = "Clears the receivers and permissions")
+    public void clearClient() {
+        mGattClient.clear();
+    }
+}
diff --git a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
index 7f83dce..7c87e54 100644
--- a/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
+++ b/hostsidetests/scopedstorage/device/src/android/scopedstorage/cts/device/ScopedStorageDeviceTest.java
@@ -142,6 +142,7 @@
 import androidx.annotation.Nullable;
 import androidx.test.filters.SdkSuppress;
 
+import com.android.compatibility.common.util.FeatureUtil;
 import com.android.cts.install.lib.TestApp;
 import com.android.modules.utils.build.SdkLevel;
 
@@ -3042,6 +3043,10 @@
     @Test
     @SdkSuppress(minSdkVersion = 31, codeName = "S")
     public void testExternalStorageProviderAndDownloadsProvider() throws Exception {
+        // External Storage Provider and Downloads Provider are not supported on Wear OS
+        if (FeatureUtil.isWatch()) {
+            return;
+        }
         assertWritableMountModeForProvider(DocumentsContract.EXTERNAL_STORAGE_PROVIDER_AUTHORITY);
         assertWritableMountModeForProvider(DocumentsContract.DOWNLOADS_PROVIDER_AUTHORITY);
     }
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
index b5386e1..306f0f34 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5862/poc.c
@@ -36,7 +36,7 @@
   unsigned int id = 0;
   struct snd_ctl_elem_list lst;
   memset(&lst, 0, sizeof(lst));
-  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_list));
+  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_id));
   lst.space = NUM_BLOCKS;
   ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &lst);
   if (ret < 0) {
diff --git a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
index 3b8771f..669101d 100644
--- a/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
+++ b/hostsidetests/securitybulletin/securityPatch/CVE-2016-5867/poc.c
@@ -38,7 +38,7 @@
   unsigned int id = 0;
   struct snd_ctl_elem_list lst;
   memset(&lst, 0, sizeof(lst));
-  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_list));
+  lst.pids = calloc(NUM_BLOCKS, sizeof(struct snd_ctl_elem_id));
   lst.space = NUM_BLOCKS;
   ret = ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &lst);
   if (ret < 0) {
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
index 8b6f991..aa748e5 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/HostAtomTests.java
@@ -339,6 +339,7 @@
     public void testBatterySaverModeStateChangedAtom() throws Exception {
         if (DeviceUtils.hasFeature(getDevice(), FEATURE_TWM)) return;
         if (DeviceUtils.hasFeature(getDevice(), FEATURE_AUTOMOTIVE)) return;
+        if (DeviceUtils.hasFeature(getDevice(), FEATURE_WATCH)) return;
         // Setup, turn off battery saver.
         turnBatterySaverOff();
         DeviceUtils.flushBatteryStatsHandlers(getDevice());
diff --git a/hostsidetests/usage/app/Android.bp b/hostsidetests/usage/app/Android.bp
index 2093cdf..9f96ebd 100644
--- a/hostsidetests/usage/app/Android.bp
+++ b/hostsidetests/usage/app/Android.bp
@@ -20,6 +20,7 @@
     name: "CtsAppUsageTestApp",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
+    min_sdk_version: "29",
     sdk_version: "current",
     // tag this module as a cts test artifact
     test_suites: [
@@ -35,6 +36,7 @@
     name: "CtsAppUsageTestAppToo",
     defaults: ["cts_support_defaults"],
     srcs: ["src/**/*.java"],
+    min_sdk_version: "29",
     sdk_version: "current",
     // tag this module as a cts test artifact
     test_suites: [
diff --git a/libs/helpers/interfaces/Android.bp b/libs/helpers/interfaces/Android.bp
index 3cdb264..dcb38f5 100644
--- a/libs/helpers/interfaces/Android.bp
+++ b/libs/helpers/interfaces/Android.bp
@@ -23,7 +23,6 @@
 
     static_libs: [
         "cts-helpers-core",
-        "ub-uiautomator",
     ],
 
     sdk_version: "test_current",
diff --git a/tests/AlarmManager/Android.bp b/tests/AlarmManager/Android.bp
index 60eefcc..e62687a 100644
--- a/tests/AlarmManager/Android.bp
+++ b/tests/AlarmManager/Android.bp
@@ -43,4 +43,5 @@
         ":AlarmTestAppWithUserPermissionSdk32",
     ],
     per_testcase_directory: true,
+    min_sdk_version: "29",
 }
diff --git a/tests/AlarmManager/app/Android.bp b/tests/AlarmManager/app/Android.bp
index 31bb43c..2e2d642 100644
--- a/tests/AlarmManager/app/Android.bp
+++ b/tests/AlarmManager/app/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "AlarmTestApp",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "29",
     sdk_version: "current",
     test_suites: [
         "cts",
diff --git a/tests/AlarmManager/app30/Android.bp b/tests/AlarmManager/app30/Android.bp
index e6e2f17..6d54031 100644
--- a/tests/AlarmManager/app30/Android.bp
+++ b/tests/AlarmManager/app30/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "AlarmTestApp30",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "30",
     sdk_version: "current",
     test_suites: [
         "cts",
diff --git a/tests/AlarmManager/app_policy_permission32/Android.bp b/tests/AlarmManager/app_policy_permission32/Android.bp
index 420c5db..5e16581 100644
--- a/tests/AlarmManager/app_policy_permission32/Android.bp
+++ b/tests/AlarmManager/app_policy_permission32/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "AlarmTestAppWithPolicyPermissionSdk32",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "32",
     sdk_version: "current",
     test_suites: [
         "cts",
diff --git a/tests/AlarmManager/app_user_permission32/Android.bp b/tests/AlarmManager/app_user_permission32/Android.bp
index 3c5fc0f1..793e565 100644
--- a/tests/AlarmManager/app_user_permission32/Android.bp
+++ b/tests/AlarmManager/app_user_permission32/Android.bp
@@ -19,6 +19,7 @@
 android_test_helper_app {
     name: "AlarmTestAppWithUserPermissionSdk32",
     defaults: ["cts_support_defaults"],
+    min_sdk_version: "32",
     sdk_version: "current",
     test_suites: [
         "cts",
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
index f6ff23f..e26f8b4 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
@@ -24,6 +24,7 @@
 import android.os.BatteryManager;
 import android.provider.Settings;
 import android.util.Log;
+import android.content.res.Resources;
 
 import com.android.compatibility.common.util.SystemUtil;
 
@@ -41,6 +42,7 @@
     public static final int BATTERY_JOB_ID = BatteryConstraintTest.class.hashCode();
 
     private JobInfo.Builder mBuilder;
+    private int mLowBatteryWarningLevel = 15;
     /**
      * Record of the previous state of power save mode trigger level to reset it after the test
      * finishes.
@@ -51,6 +53,9 @@
     public void setUp() throws Exception {
         super.setUp();
 
+        mLowBatteryWarningLevel = Resources.getSystem().getInteger(
+                     Resources.getSystem().getIdentifier(
+                             "config_lowBatteryWarningLevel", "integer", "android"));
         // Disable power save mode as some devices may turn off Android when power save mode is
         // enabled, causing the test to fail.
         mPreviousLowPowerTriggerLevel = Settings.Global.getInt(getContext().getContentResolver(),
@@ -253,7 +258,7 @@
             return;
         }
 
-        setBatteryState(false, 5);
+        setBatteryState(false, mLowBatteryWarningLevel);
         // setBatteryState() waited for the charging/not-charging state to formally settle,
         // but battery level reporting lags behind that.  wait a moment to let that happen
         // before proceeding.
@@ -288,8 +293,8 @@
                 kTestEnvironment.awaitExecution());
 
         // And check that the job is stopped if battery goes low again.
-        setBatteryState(false, 5);
-        setBatteryState(false, 4);
+        setBatteryState(false, mLowBatteryWarningLevel);
+        setBatteryState(false, mLowBatteryWarningLevel - 1);
         Thread.sleep(2_000);
         verifyChargingState(false);
         verifyBatteryNotLowState(false);
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
index 00d7517..7b0d261 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/ConnectivityConstraintTest.java
@@ -18,48 +18,25 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
-import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
 
-import static com.android.compatibility.common.util.TestUtils.waitUntil;
-
-import android.Manifest;
 import android.annotation.TargetApi;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.pm.PackageManager;
-import android.location.LocationManager;
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
-import android.net.wifi.WifiConfiguration;
 import android.net.wifi.WifiManager;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Message;
 import android.platform.test.annotations.RequiresDevice;
 import android.provider.Settings;
 import android.util.Log;
 
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
-import com.android.compatibility.common.util.ShellIdentityUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
-import junit.framework.AssertionFailedError;
-
-import java.util.List;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Schedules jobs with the {@link android.app.job.JobScheduler} that have network connectivity
  * constraints.
@@ -70,18 +47,13 @@
 @RequiresDevice // Emulators don't always have access to wifi/network
 public class ConnectivityConstraintTest extends BaseJobSchedulerTest {
     private static final String TAG = "ConnectivityConstraintTest";
-    private static final String RESTRICT_BACKGROUND_GET_CMD =
-            "cmd netpolicy get restrict-background";
-    private static final String RESTRICT_BACKGROUND_ON_CMD =
-            "cmd netpolicy set restrict-background true";
-    private static final String RESTRICT_BACKGROUND_OFF_CMD =
-            "cmd netpolicy set restrict-background false";
 
     /** Unique identifier for the job scheduled by this suite of tests. */
     public static final int CONNECTIVITY_JOB_ID = ConnectivityConstraintTest.class.hashCode();
     /** Wait this long before timing out the test. */
     private static final long DEFAULT_TIMEOUT_MILLIS = 30000L; // 30 seconds.
 
+    private NetworkingHelper mNetworkingHelper;
     private WifiManager mWifiManager;
     private ConnectivityManager mCm;
 
@@ -89,21 +61,8 @@
     private boolean mHasWifi;
     /** Whether the device running these tests supports telephony. */
     private boolean mHasTelephony;
-    /** Whether the device running these tests supports ethernet. */
-    private boolean mHasEthernet;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    /** Track initial WiFi metered state. */
-    private String mInitialWiFiMeteredState;
-    private String mInitialWiFiSSID;
-    /** Track whether restrict background policy was enabled in case we turn it off. */
-    private boolean mInitialRestrictBackground;
-    /** Track whether airplane mode was enabled in case we toggle it. */
-    private boolean mInitialAirplaneMode;
     /** Track whether the restricted bucket was enabled in case we toggle it. */
     private String mInitialRestrictedBucketEnabled;
-    /** Track the location mode in case we change it. */
-    private String mInitialLocationMode;
 
     private JobInfo.Builder mBuilder;
 
@@ -115,30 +74,20 @@
 
         mWifiManager = (WifiManager) getContext().getSystemService(Context.WIFI_SERVICE);
         mCm = (ConnectivityManager) getContext().getSystemService(Context.CONNECTIVITY_SERVICE);
+        mNetworkingHelper = new NetworkingHelper(getInstrumentation(), getContext());
 
         PackageManager packageManager = mContext.getPackageManager();
         mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
         mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
         mBuilder = new JobInfo.Builder(CONNECTIVITY_JOB_ID, kJobServiceComponent);
 
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         if (mHasWifi) {
-            mInitialWiFiState = mWifiManager.isWifiEnabled();
-            ensureSavedWifiNetwork(mWifiManager);
-            setWifiState(true, mCm, mWifiManager);
-            mInitialWiFiSSID = getWifiSSID();
-            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+            mNetworkingHelper.ensureSavedWifiNetwork();
         }
-        mInitialRestrictBackground = SystemUtil
-                .runShellCommand(getInstrumentation(), RESTRICT_BACKGROUND_GET_CMD)
-                .contains("enabled");
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         setDataSaverEnabled(false);
-        mInitialAirplaneMode = isAirplaneModeOn();
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         // Force the test app out of the never bucket.
         SystemUtil.runShellCommand("am set-standby-bucket "
                 + TestAppInterface.TEST_APP_PACKAGE + " rare");
@@ -153,31 +102,12 @@
 
         BatteryUtils.runDumpsysBatteryReset();
 
-        // Restore initial restrict background data usage policy
-        setDataSaverEnabled(mInitialRestrictBackground);
-
         // Restore initial restricted bucket setting.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
 
         // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi) {
-            setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
-            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-                try {
-                    setWifiState(mInitialWiFiState, mCm, mWifiManager);
-                } catch (AssertionFailedError e) {
-                    // Don't fail the test just because wifi state wasn't set in tearDown.
-                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-                }
-            }
-        }
-
-        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
-        // originally metered.
-        setAirplaneMode(mInitialAirplaneMode);
-
-        setLocationMode(mInitialLocationMode);
+        mNetworkingHelper.tearDown();
 
         super.tearDown();
     }
@@ -585,7 +515,7 @@
     }
 
     public void testJobParametersNetwork() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Everything good.
         final NetworkRequest nr = new NetworkRequest.Builder()
@@ -608,7 +538,7 @@
 
         if (!hasEthernetConnection()) {
             // Deadline passed with no network satisfied.
-            setAirplaneMode(true);
+            mNetworkingHelper.setAllNetworksEnabled(false);
             ji = mBuilder
                     .setRequiredNetwork(nr)
                     .setOverrideDeadline(0)
@@ -624,7 +554,7 @@
         }
 
         // No network requested
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         ji = mBuilder.setRequiredNetwork(null).build();
         kTestEnvironment.setExpectedExecutions(1);
         mJobScheduler.schedule(ji);
@@ -875,149 +805,25 @@
     }
 
     private boolean hasEthernetConnection() {
-        if (!mHasEthernet) return false;
-        Network[] networks = mCm.getAllNetworks();
-        for (Network network : networks) {
-            if (mCm.getNetworkCapabilities(network).hasTransport(TRANSPORT_ETHERNET)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) throws Exception {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+        mNetworkingHelper.setWifiMeteredState(metered);
     }
 
     /**
      * Ensure WiFi is enabled, and block until we've verified that we are in fact connected.
      */
     private void connectToWifi() throws Exception {
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setWifiState(true);
     }
 
     /**
      * Ensure WiFi is disabled, and block until we've verified that we are in fact disconnected.
      */
     private void disconnectFromWifi() throws Exception {
-        setWifiState(false, mCm, mWifiManager);
-    }
-
-    /** Ensures that the device has a wifi network saved. */
-    static void ensureSavedWifiNetwork(WifiManager wifiManager) {
-        final List<WifiConfiguration> savedNetworks =
-                ShellIdentityUtils.invokeMethodWithShellPermissions(
-                        wifiManager, WifiManager::getConfiguredNetworks);
-        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
-    }
-
-    /**
-     * Set Wifi connection to specific state, and block until we've verified
-     * that we are in the state.
-     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
-     */
-    static void setWifiState(final boolean enable,
-            final ConnectivityManager cm, final WifiManager wm) throws Exception {
-        if (enable != isWiFiConnected(cm, wm)) {
-            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
-            NetworkCapabilities nc = new NetworkCapabilities.Builder()
-                    .addTransportType(TRANSPORT_WIFI)
-                    .build();
-            NetworkTracker tracker = new NetworkTracker(nc, enable, cm);
-            cm.registerNetworkCallback(nr, tracker);
-
-            if (enable) {
-                SystemUtil.runShellCommand("svc wifi enable");
-                waitUntil("Failed to enable Wifi", 30 /* seconds */, () -> wm.isWifiEnabled());
-                //noinspection deprecation
-                SystemUtil.runWithShellPermissionIdentity(wm::reconnect,
-                        android.Manifest.permission.NETWORK_SETTINGS);
-            } else {
-                SystemUtil.runShellCommand("svc wifi disable");
-            }
-
-            tracker.waitForStateChange();
-
-            assertTrue("Wifi must be " + (enable ? "connected to" : "disconnected from")
-                            + " an access point for this test.",
-                    enable == isWiFiConnected(cm, wm));
-
-            cm.unregisterNetworkCallback(tracker);
-        }
-    }
-
-    static boolean isWiFiConnected(final ConnectivityManager cm, final WifiManager wm) {
-        if (!wm.isWifiEnabled()) {
-            return false;
-        }
-        final Network network = cm.getActiveNetwork();
-        if (network == null) {
-            return false;
-        }
-        final NetworkCapabilities networkCapabilities = cm.getNetworkCapabilities(network);
-        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+        mNetworkingHelper.setWifiState(false);
     }
 
     /**
@@ -1029,13 +835,14 @@
      * @see #checkDeviceSupportsMobileData()
      */
     private void disconnectWifiToConnectToMobile() throws Exception {
-        setAirplaneMode(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
         if (mHasWifi && mWifiManager.isWifiEnabled()) {
             NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
             NetworkCapabilities nc = new NetworkCapabilities.Builder()
                     .addTransportType(TRANSPORT_CELLULAR)
                     .build();
-            NetworkTracker tracker = new NetworkTracker(nc, true, mCm);
+            NetworkingHelper.NetworkTracker tracker =
+                    new NetworkingHelper.NetworkTracker(nc, true, mCm);
             mCm.registerNetworkCallback(nr, tracker);
 
             disconnectFromWifi();
@@ -1052,107 +859,6 @@
      * If the policy is on, it interferes with tests that relies on metered connection.
      */
     private void setDataSaverEnabled(boolean enabled) throws Exception {
-        SystemUtil.runShellCommand(getInstrumentation(),
-                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
-    }
-
-    private boolean isAirplaneModeOn() throws Exception {
-        final String output = SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        if (isAirplaneModeOn() == on) {
-            return;
-        }
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        SystemUtil.runShellCommand(getInstrumentation(),
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        waitUntil("Networks didn't change to " + (!on ? " on" : " off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static class NetworkTracker extends ConnectivityManager.NetworkCallback {
-        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
-        private final ConnectivityManager mCm;
-
-        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
-
-        private final NetworkCapabilities mExpectedCapabilities;
-
-        private final boolean mExpectedConnected;
-
-        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
-                    checkActiveNetwork();
-                }
-            }
-        };
-
-        private NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
-                ConnectivityManager cm) {
-            mExpectedCapabilities = expectedCapabilities;
-            mExpectedConnected = expectedConnected;
-            mCm = cm;
-        }
-
-        @Override
-        public void onAvailable(Network network) {
-            // Available doesn't mean it's the active network. We need to check that separately.
-            checkActiveNetwork();
-        }
-
-        @Override
-        public void onLost(Network network) {
-            checkActiveNetwork();
-        }
-
-        boolean waitForStateChange() throws InterruptedException {
-            checkActiveNetwork();
-            return mReceiveLatch.await(60, TimeUnit.SECONDS);
-        }
-
-        private void checkActiveNetwork() {
-            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
-            if (mReceiveLatch.getCount() == 0) {
-                return;
-            }
-
-            Network activeNetwork = mCm.getActiveNetwork();
-            if (mExpectedConnected) {
-                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            } else {
-                if (activeNetwork == null
-                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
-                        mCm.getNetworkCapabilities(activeNetwork))) {
-                    mReceiveLatch.countDown();
-                } else {
-                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
-                }
-            }
-        }
+        mNetworkingHelper.setDataSaverEnabled(enabled);
     }
 }
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
index e4cb16c..5789a60 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -18,24 +18,17 @@
 
 import static android.app.job.JobInfo.NETWORK_TYPE_ANY;
 import static android.app.job.JobInfo.NETWORK_TYPE_NONE;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.ensureSavedWifiNetwork;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.isWiFiConnected;
-import static android.jobscheduler.cts.ConnectivityConstraintTest.setWifiState;
 import static android.jobscheduler.cts.TestAppInterface.TEST_APP_PACKAGE;
-import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
 import static android.os.PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED;
 
 import static com.android.compatibility.common.util.TestUtils.waitUntil;
 
-import static junit.framework.Assert.fail;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
-import android.Manifest;
 import android.app.AppOpsManager;
 import android.app.job.JobInfo;
 import android.app.job.JobParameters;
@@ -45,10 +38,6 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.jobscheduler.cts.jobtestapp.TestJobSchedulerReceiver;
-import android.location.LocationManager;
-import android.net.ConnectivityManager;
-import android.net.Network;
-import android.net.wifi.WifiManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Temperature;
@@ -66,23 +55,14 @@
 import com.android.compatibility.common.util.AppOpsUtils;
 import com.android.compatibility.common.util.AppStandbyUtils;
 import com.android.compatibility.common.util.BatteryUtils;
-import com.android.compatibility.common.util.CallbackAsserter;
 import com.android.compatibility.common.util.DeviceConfigStateHelper;
-import com.android.compatibility.common.util.SystemUtil;
 import com.android.compatibility.common.util.ThermalUtils;
 
-import junit.framework.AssertionFailedError;
-
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
-import java.io.IOException;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
 /**
  * Tests related to job throttling -- device idle, app standby and battery saver.
  */
@@ -108,24 +88,15 @@
 
     private Context mContext;
     private UiDevice mUiDevice;
+    private NetworkingHelper mNetworkingHelper;
     private PowerManager mPowerManager;
     private int mTestJobId;
     private int mTestPackageUid;
     private boolean mDeviceInDoze;
     private boolean mDeviceIdleEnabled;
     private boolean mAppStandbyEnabled;
-    private WifiManager mWifiManager;
-    private ConnectivityManager mCm;
-    /** Whether the device running these tests supports WiFi. */
-    private boolean mHasWifi;
-    /** Track whether WiFi was enabled in case we turn it off. */
-    private boolean mInitialWiFiState;
-    /** Whether the device running these tests supports ethernet. */
-    private boolean mHasEthernet;
-    private boolean mInitialAirplaneModeState;
     private String mInitialDisplayTimeout;
     private String mInitialRestrictedBucketEnabled;
-    private String mInitialLocationMode;
     private String mInitialBatteryStatsConstants;
     private boolean mAutomotiveDevice;
     private boolean mLeanbackOnly;
@@ -158,6 +129,8 @@
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mNetworkingHelper =
+                new NetworkingHelper(InstrumentationRegistry.getInstrumentation(), mContext);
         mPowerManager = mContext.getSystemService(PowerManager.class);
         mDeviceInDoze = mPowerManager.isDeviceIdleMode();
         mTestPackageUid = mContext.getPackageManager().getPackageUid(TEST_APP_PACKAGE, 0);
@@ -175,13 +148,6 @@
         } else {
             Log.w(TAG, "App standby not enabled on test device");
         }
-        mWifiManager = mContext.getSystemService(WifiManager.class);
-        mCm = mContext.getSystemService(ConnectivityManager.class);
-        mHasWifi = mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WIFI);
-        mInitialWiFiState = mWifiManager.isWifiEnabled();
-        mHasEthernet = mContext.getPackageManager()
-                .hasSystemFeature(PackageManager.FEATURE_ETHERNET);
-        mInitialAirplaneModeState = isAirplaneModeOn();
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(),
@@ -189,8 +155,6 @@
         // Make sure ACTION_CHARGING is sent immediately.
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.BATTERY_STATS_CONSTANTS, "battery_charged_delay_ms=0");
-        mInitialLocationMode = Settings.Secure.getString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE);
         // Make sure test jobs can run regardless of bucket.
         mDeviceConfigStateHelper =
                 new DeviceConfigStateHelper(DeviceConfig.NAMESPACE_JOB_SCHEDULER);
@@ -610,7 +574,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -642,9 +606,8 @@
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
         assumeFalse("not testable, since ethernet is connected", hasEthernetConnection());
-
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
 
@@ -652,7 +615,7 @@
         mDeviceConfigStateHelper.set("qc_timing_session_coalescing_duration_ms", "0");
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         setScreenState(true);
 
         setChargingState(false);
@@ -681,9 +644,8 @@
         assertFalse("New job started in RESTRICTED bucket", mTestAppInterface.awaitJobStart(3_000));
 
         // Add network
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(5_000));
@@ -987,8 +949,8 @@
         assumeFalse("not testable in leanback device", mLeanbackOnly);
         assumeFalse("not testable, since ethernet is connected", hasEthernetConnection());
 
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
         setTestPackageStandbyBucket(Bucket.RESTRICTED);
@@ -998,9 +960,8 @@
         mDeviceConfigStateHelper.set("qc_max_session_count_restricted", "0");
 
         // Satisfy all additional constraints.
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
-        setWifiMeteredState(false);
+        mNetworkingHelper.setAllNetworksEnabled(true);
+        mNetworkingHelper.setWifiMeteredState(false);
         setChargingState(true);
         BatteryUtils.runDumpsysBatterySetLevel(100);
         setScreenState(false);
@@ -1013,13 +974,12 @@
         runJob();
         assertTrue("New job didn't start in RESTRICTED bucket",
                 mTestAppInterface.awaitJobStart(DEFAULT_WAIT_TIMEOUT));
-        setAirplaneMode(true);
+        mNetworkingHelper.setAllNetworksEnabled(false);
         assertTrue("New job didn't stop when connectivity dropped",
                 mTestAppInterface.awaitJobStop(DEFAULT_WAIT_TIMEOUT));
         assertEquals(JobParameters.STOP_REASON_CONSTRAINT_CONNECTIVITY,
                 mTestAppInterface.getLastParams().getStopReason());
-        setAirplaneMode(false);
-        setWifiState(true, mCm, mWifiManager);
+        mNetworkingHelper.setAllNetworksEnabled(true);
 
         // Idle
         mTestAppInterface.scheduleJob(false, NETWORK_TYPE_ANY, false);
@@ -1204,23 +1164,12 @@
                 Settings.Global.BATTERY_STATS_CONSTANTS, mInitialBatteryStatsConstants);
         removeTestAppFromTempWhitelist();
 
-        // Ensure that we leave WiFi in its previous state.
-        if (mHasWifi && mWifiManager.isWifiEnabled() != mInitialWiFiState) {
-            try {
-                setWifiState(mInitialWiFiState, mCm, mWifiManager);
-            } catch (AssertionFailedError e) {
-                // Don't fail the test just because wifi state wasn't set in tearDown.
-                Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
-            }
-        }
+        mNetworkingHelper.tearDown();
         mDeviceConfigStateHelper.restoreOriginalValues();
         mActivityManagerDeviceConfigStateHelper.restoreOriginalValues();
         Settings.Global.putString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET, mInitialRestrictedBucketEnabled);
-        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
-            setAirplaneMode(mInitialAirplaneModeState);
-        }
-        setLocationMode(mInitialLocationMode);
+
         mUiDevice.executeShellCommand(
                 "cmd jobscheduler reset-execution-quota -u " + UserHandle.myUserId()
                         + " " + TEST_APP_PACKAGE);
@@ -1377,120 +1326,7 @@
     }
 
     private boolean hasEthernetConnection() {
-        if (!mHasEthernet) return false;
-        Network[] networks = mCm.getAllNetworks();
-        for (Network network : networks) {
-            if (mCm.getNetworkCapabilities(network).hasTransport(TRANSPORT_ETHERNET)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean isAirplaneModeOn() throws IOException {
-        final String output =
-                mUiDevice.executeShellCommand("cmd connectivity airplane-mode").trim();
-        return "enabled".equals(output);
-    }
-
-    private void setAirplaneMode(boolean on) throws Exception {
-        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
-                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
-        mUiDevice.executeShellCommand(
-                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
-        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
-                15 /* 15 seconds */);
-        if (!on && mHasWifi) {
-            // Force wifi to connect ASAP.
-            mUiDevice.executeShellCommand("svc wifi enable");
-            waitUntil("Failed to enable Wifi", 30 /* seconds */,
-                    () -> {
-                        return mWifiManager.isWifiEnabled();
-                    });
-            //noinspection deprecation
-            SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
-                    android.Manifest.permission.NETWORK_SETTINGS);
-        }
-        waitUntil("Networks didn't change to " + (!on ? "on" : "off"), 60 /* seconds */,
-                () -> {
-                    if (on) {
-                        return mCm.getActiveNetwork() == null
-                                && (!mHasWifi || !isWiFiConnected(mCm, mWifiManager));
-                    } else {
-                        return mCm.getActiveNetwork() != null;
-                    }
-                });
-        // Wait some time for the network changes to propagate. Can't use
-        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
-        // airplane mode status even though the network changes haven't propagated all the way to
-        // JobScheduler.
-        Thread.sleep(5000);
-    }
-
-    private static String unquoteSSID(String ssid) {
-        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
-        // Otherwise it's guaranteed not to start with a quote.
-        if (ssid.charAt(0) == '"') {
-            return ssid.substring(1, ssid.length() - 1);
-        } else {
-            return ssid;
-        }
-    }
-
-    private String getWifiSSID() throws Exception {
-        // Location needs to be enabled to get the WiFi information.
-        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
-        final AtomicReference<String> ssid = new AtomicReference<>();
-        SystemUtil.runWithShellPermissionIdentity(() -> {
-            ssid.set(mWifiManager.getConnectionInfo().getSSID());
-        }, Manifest.permission.ACCESS_FINE_LOCATION);
-        return unquoteSSID(ssid.get());
-    }
-
-    private void setLocationMode(String mode) throws Exception {
-        Settings.Secure.putString(mContext.getContentResolver(),
-                Settings.Secure.LOCATION_MODE, mode);
-        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
-        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
-        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
-                () -> wantEnabled == locationManager.isLocationEnabled());
-    }
-
-    // Returns "true", "false" or "none"
-    private String getWifiMeteredStatus(String ssid) {
-        // Interestingly giving the SSID as an argument to list wifi-networks
-        // only works iff the network in question has the "false" policy.
-        // Also unfortunately runShellCommand does not pass the command to the interpreter
-        // so it's not possible to | grep the ssid.
-        final String command = "cmd netpolicy list wifi-networks";
-        final String policyString = SystemUtil.runShellCommand(command);
-
-        final Matcher m = Pattern.compile("^" + ssid + ";(true|false|none)$",
-                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
-        if (!m.find()) {
-            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
-                    + policyString);
-        }
-        return m.group(1);
-    }
-
-    private void setWifiMeteredState(boolean metered) throws Exception {
-        if (metered) {
-            // Make sure unmetered cellular networks don't interfere.
-            setAirplaneMode(true);
-            setWifiState(true, mCm, mWifiManager);
-        }
-        final String ssid = getWifiSSID();
-        setWifiMeteredState(ssid, metered ? "true" : "false");
-    }
-
-    // metered should be "true", "false" or "none"
-    private void setWifiMeteredState(String ssid, String metered) {
-        if (metered.equals(getWifiMeteredStatus(ssid))) {
-            return;
-        }
-        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
-        assertEquals(getWifiMeteredStatus(ssid), metered);
+        return mNetworkingHelper.hasEthernetConnection();
     }
 
     private String getJobState() throws Exception {
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
new file mode 100644
index 0000000..1402975
--- /dev/null
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/NetworkingHelper.java
@@ -0,0 +1,432 @@
+/*
+ * 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.jobscheduler.cts;
+
+import static android.net.NetworkCapabilities.TRANSPORT_ETHERNET;
+import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+
+import static com.android.compatibility.common.util.TestUtils.waitUntil;
+
+import static junit.framework.Assert.fail;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import android.Manifest;
+import android.annotation.NonNull;
+import android.app.Instrumentation;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.location.LocationManager;
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiManager;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.compatibility.common.util.CallbackAsserter;
+import com.android.compatibility.common.util.ShellIdentityUtils;
+import com.android.compatibility.common.util.SystemUtil;
+
+import junit.framework.AssertionFailedError;
+
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+public class NetworkingHelper {
+    private static final String TAG = "JsNetworkingUtils";
+
+    private static final String RESTRICT_BACKGROUND_GET_CMD =
+            "cmd netpolicy get restrict-background";
+    private static final String RESTRICT_BACKGROUND_ON_CMD =
+            "cmd netpolicy set restrict-background true";
+    private static final String RESTRICT_BACKGROUND_OFF_CMD =
+            "cmd netpolicy set restrict-background false";
+
+    private final Context mContext;
+    private final Instrumentation mInstrumentation;
+
+    private final ConnectivityManager mConnectivityManager;
+    private final WifiManager mWifiManager;
+
+    /** Whether the device running these tests supports WiFi. */
+    private final boolean mHasWifi;
+    /** Whether the device running these tests supports ethernet. */
+    private final boolean mHasEthernet;
+    /** Whether the device running these tests supports telephony. */
+    private final boolean mHasTelephony;
+
+    private final boolean mInitialAirplaneModeState;
+    private final boolean mInitialDataSaverState;
+    private final String mInitialLocationMode;
+    private final boolean mInitialWiFiState;
+    private String mInitialWiFiMeteredState;
+    private String mInitialWiFiSSID;
+
+    NetworkingHelper(@NonNull Instrumentation instrumentation, @NonNull Context context)
+            throws Exception {
+        mContext = context;
+        mInstrumentation = instrumentation;
+
+        mConnectivityManager = context.getSystemService(ConnectivityManager.class);
+        mWifiManager = context.getSystemService(WifiManager.class);
+
+        PackageManager packageManager = mContext.getPackageManager();
+        mHasWifi = packageManager.hasSystemFeature(PackageManager.FEATURE_WIFI);
+        mHasEthernet = packageManager.hasSystemFeature(PackageManager.FEATURE_ETHERNET);
+        mHasTelephony = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+
+        mInitialAirplaneModeState = isAirplaneModeOn();
+        mInitialDataSaverState = isDataSaverEnabled();
+        mInitialLocationMode = Settings.Secure.getString(
+                mContext.getContentResolver(), Settings.Secure.LOCATION_MODE);
+        mInitialWiFiState = mHasWifi && isWifiEnabled();
+    }
+
+    /** Ensures that the device has a wifi network saved. */
+    void ensureSavedWifiNetwork() throws Exception {
+        if (!mHasWifi) {
+            return;
+        }
+        final List<WifiConfiguration> savedNetworks =
+                ShellIdentityUtils.invokeMethodWithShellPermissions(
+                        mWifiManager, WifiManager::getConfiguredNetworks);
+        assertFalse("Need at least one saved wifi network", savedNetworks.isEmpty());
+
+        setWifiState(true);
+        if (mInitialWiFiSSID == null) {
+            mInitialWiFiSSID = getWifiSSID();
+            mInitialWiFiMeteredState = getWifiMeteredStatus(mInitialWiFiSSID);
+        }
+    }
+
+    // Returns "true", "false", or "none".
+    private String getWifiMeteredStatus(String ssid) {
+        // Interestingly giving the SSID as an argument to list wifi-networks
+        // only works iff the network in question has the "false" policy.
+        // Also unfortunately runShellCommand does not pass the command to the interpreter
+        // so it's not possible to | grep the ssid.
+        final String command = "cmd netpolicy list wifi-networks";
+        final String policyString = SystemUtil.runShellCommand(command);
+
+        final Matcher m = Pattern.compile(ssid + ";(true|false|none)",
+                Pattern.MULTILINE | Pattern.UNIX_LINES).matcher(policyString);
+        if (!m.find()) {
+            fail("Unexpected format from cmd netpolicy (when looking for " + ssid + "): "
+                    + policyString);
+        }
+        return m.group(1);
+    }
+
+    @NonNull
+    private String getWifiSSID() throws Exception {
+        // Location needs to be enabled to get the WiFi information.
+        setLocationMode(String.valueOf(Settings.Secure.LOCATION_MODE_ON));
+        final AtomicReference<String> ssid = new AtomicReference<>();
+        SystemUtil.runWithShellPermissionIdentity(
+                () -> ssid.set(mWifiManager.getConnectionInfo().getSSID()),
+                Manifest.permission.ACCESS_FINE_LOCATION);
+        return unquoteSSID(ssid.get());
+    }
+
+    boolean hasEthernetConnection() {
+        if (!mHasEthernet) return false;
+        Network[] networks = mConnectivityManager.getAllNetworks();
+        for (Network network : networks) {
+            if (mConnectivityManager.getNetworkCapabilities(network)
+                    .hasTransport(TRANSPORT_ETHERNET)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    boolean hasWifiFeature() {
+        return mHasWifi;
+    }
+
+    boolean isAirplaneModeOn() throws Exception {
+        final String output = SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode").trim();
+        return "enabled".equals(output);
+    }
+
+    boolean isDataSaverEnabled() throws Exception {
+        return SystemUtil
+                .runShellCommand(mInstrumentation, RESTRICT_BACKGROUND_GET_CMD)
+                .contains("enabled");
+    }
+
+    boolean isWiFiConnected() {
+        if (!mWifiManager.isWifiEnabled()) {
+            return false;
+        }
+        final Network network = mConnectivityManager.getActiveNetwork();
+        if (network == null) {
+            return false;
+        }
+        final NetworkCapabilities networkCapabilities =
+                mConnectivityManager.getNetworkCapabilities(network);
+        return networkCapabilities != null && networkCapabilities.hasTransport(TRANSPORT_WIFI);
+    }
+
+    boolean isWifiEnabled() {
+        return mWifiManager.isWifiEnabled();
+    }
+
+    /**
+     * Tries to set all network statuses to {@code enabled}.
+     * However, this does not support ethernet connections.
+     * Confirm that {@link #hasEthernetConnection()} returns false before relying on this.
+     */
+    void setAllNetworksEnabled(boolean enabled) throws Exception {
+        if (mHasWifi) {
+            setWifiState(enabled);
+        }
+        setAirplaneMode(!enabled);
+    }
+
+    void setAirplaneMode(boolean on) throws Exception {
+        if (isAirplaneModeOn() == on) {
+            return;
+        }
+        final CallbackAsserter airplaneModeBroadcastAsserter = CallbackAsserter.forBroadcast(
+                new IntentFilter(Intent.ACTION_AIRPLANE_MODE_CHANGED));
+        SystemUtil.runShellCommand(mInstrumentation,
+                "cmd connectivity airplane-mode " + (on ? "enable" : "disable"));
+        airplaneModeBroadcastAsserter.assertCalled("Didn't get airplane mode changed broadcast",
+                15 /* 15 seconds */);
+        if (!on && mHasWifi) {
+            // Try to trigger some network connection.
+            setWifiState(true);
+        }
+        waitUntil("Airplane mode didn't change to " + (on ? " on" : " off"), 60 /* seconds */,
+                () -> {
+                    // Airplane mode only affects the cellular network. If the device doesn't
+                    // support cellular, then we can only check that the airplane mode toggle is on.
+                    if (!mHasTelephony) {
+                        return on == isAirplaneModeOn();
+                    }
+                    if (on) {
+                        Network[] networks = mConnectivityManager.getAllNetworks();
+                        for (Network network : networks) {
+                            if (mConnectivityManager.getNetworkCapabilities(network)
+                                    .hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
+                                return false;
+                            }
+                        }
+                        return true;
+                    } else {
+                        return mConnectivityManager.getActiveNetwork() != null;
+                    }
+                });
+        // Wait some time for the network changes to propagate. Can't use
+        // waitUntil(isAirplaneModeOn() == on) because the response quickly gives the new
+        // airplane mode status even though the network changes haven't propagated all the way to
+        // JobScheduler.
+        Thread.sleep(5000);
+    }
+
+    /**
+     * Ensures that restrict background data usage policy is turned off.
+     * If the policy is on, it interferes with tests that relies on metered connection.
+     */
+    void setDataSaverEnabled(boolean enabled) throws Exception {
+        SystemUtil.runShellCommand(mInstrumentation,
+                enabled ? RESTRICT_BACKGROUND_ON_CMD : RESTRICT_BACKGROUND_OFF_CMD);
+    }
+
+    private void setLocationMode(String mode) throws Exception {
+        Settings.Secure.putString(mContext.getContentResolver(),
+                Settings.Secure.LOCATION_MODE, mode);
+        final LocationManager locationManager = mContext.getSystemService(LocationManager.class);
+        final boolean wantEnabled = !String.valueOf(Settings.Secure.LOCATION_MODE_OFF).equals(mode);
+        waitUntil("Location " + (wantEnabled ? "not enabled" : "still enabled"),
+                () -> wantEnabled == locationManager.isLocationEnabled());
+    }
+
+    void setWifiMeteredState(boolean metered) throws Exception {
+        if (metered) {
+            // Make sure unmetered cellular networks don't interfere.
+            setAirplaneMode(true);
+            setWifiState(true);
+        }
+        final String ssid = getWifiSSID();
+        setWifiMeteredState(ssid, metered ? "true" : "false");
+    }
+
+    // metered should be "true", "false" or "none"
+    private void setWifiMeteredState(String ssid, String metered) {
+        if (metered.equals(getWifiMeteredStatus(ssid))) {
+            return;
+        }
+        SystemUtil.runShellCommand("cmd netpolicy set metered-network " + ssid + " " + metered);
+        assertEquals(getWifiMeteredStatus(ssid), metered);
+    }
+
+    /**
+     * Set Wifi connection to specific state, and block until we've verified
+     * that we are in the state.
+     * Taken from {@link android.net.http.cts.ApacheHttpClientTest}.
+     */
+    void setWifiState(final boolean enable) throws Exception {
+        if (enable != isWiFiConnected()) {
+            NetworkRequest nr = new NetworkRequest.Builder().clearCapabilities().build();
+            NetworkCapabilities nc = new NetworkCapabilities.Builder()
+                    .addTransportType(TRANSPORT_WIFI)
+                    .build();
+            NetworkTracker tracker = new NetworkTracker(nc, enable, mConnectivityManager);
+            mConnectivityManager.registerNetworkCallback(nr, tracker);
+
+            if (enable) {
+                SystemUtil.runShellCommand("svc wifi enable");
+                waitUntil("Failed to enable Wifi", 30 /* seconds */,
+                        this::isWifiEnabled);
+                //noinspection deprecation
+                SystemUtil.runWithShellPermissionIdentity(mWifiManager::reconnect,
+                        android.Manifest.permission.NETWORK_SETTINGS);
+            } else {
+                SystemUtil.runShellCommand("svc wifi disable");
+            }
+
+            tracker.waitForStateChange();
+
+            assertEquals("Wifi must be " + (enable ? "connected to" : "disconnected from")
+                    + " an access point for this test.", enable, isWiFiConnected());
+
+            mConnectivityManager.unregisterNetworkCallback(tracker);
+        }
+    }
+
+    void tearDown() throws Exception {
+        // Restore initial restrict background data usage policy
+        setDataSaverEnabled(mInitialDataSaverState);
+
+        // Ensure that we leave WiFi in its previous state.
+        if (mHasWifi) {
+            if (mInitialWiFiSSID != null) {
+                setWifiMeteredState(mInitialWiFiSSID, mInitialWiFiMeteredState);
+            }
+            if (mWifiManager.isWifiEnabled() != mInitialWiFiState) {
+                try {
+                    setWifiState(mInitialWiFiState);
+                } catch (AssertionFailedError e) {
+                    // Don't fail the test just because wifi state wasn't set in tearDown.
+                    Log.e(TAG, "Failed to return wifi state to " + mInitialWiFiState, e);
+                }
+            }
+        }
+
+        // Restore initial airplane mode status. Do it after setting wifi in case wifi was
+        // originally metered.
+        if (isAirplaneModeOn() != mInitialAirplaneModeState) {
+            setAirplaneMode(mInitialAirplaneModeState);
+        }
+
+        setLocationMode(mInitialLocationMode);
+    }
+
+    private String unquoteSSID(String ssid) {
+        // SSID is returned surrounded by quotes if it can be decoded as UTF-8.
+        // Otherwise it's guaranteed not to start with a quote.
+        if (ssid.charAt(0) == '"') {
+            return ssid.substring(1, ssid.length() - 1);
+        } else {
+            return ssid;
+        }
+    }
+
+    static class NetworkTracker extends ConnectivityManager.NetworkCallback {
+        private static final int MSG_CHECK_ACTIVE_NETWORK = 1;
+        private final ConnectivityManager mConnectivityManager;
+
+        private final CountDownLatch mReceiveLatch = new CountDownLatch(1);
+
+        private final NetworkCapabilities mExpectedCapabilities;
+
+        private final boolean mExpectedConnected;
+
+        private final Handler mHandler = new Handler(Looper.getMainLooper()) {
+            @Override
+            public void handleMessage(Message msg) {
+                if (msg.what == MSG_CHECK_ACTIVE_NETWORK) {
+                    checkActiveNetwork();
+                }
+            }
+        };
+
+        NetworkTracker(NetworkCapabilities expectedCapabilities, boolean expectedConnected,
+                ConnectivityManager cm) {
+            mExpectedCapabilities = expectedCapabilities;
+            mExpectedConnected = expectedConnected;
+            mConnectivityManager = cm;
+        }
+
+        @Override
+        public void onAvailable(Network network) {
+            // Available doesn't mean it's the active network. We need to check that separately.
+            checkActiveNetwork();
+        }
+
+        @Override
+        public void onLost(Network network) {
+            checkActiveNetwork();
+        }
+
+        boolean waitForStateChange() throws InterruptedException {
+            checkActiveNetwork();
+            return mReceiveLatch.await(60, TimeUnit.SECONDS);
+        }
+
+        private void checkActiveNetwork() {
+            mHandler.removeMessages(MSG_CHECK_ACTIVE_NETWORK);
+            if (mReceiveLatch.getCount() == 0) {
+                return;
+            }
+
+            Network activeNetwork = mConnectivityManager.getActiveNetwork();
+            if (mExpectedConnected) {
+                if (activeNetwork != null && mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            } else {
+                if (activeNetwork == null
+                        || !mExpectedCapabilities.satisfiedByNetworkCapabilities(
+                        mConnectivityManager.getNetworkCapabilities(activeNetwork))) {
+                    mReceiveLatch.countDown();
+                } else {
+                    mHandler.sendEmptyMessageDelayed(MSG_CHECK_ACTIVE_NETWORK, 5000);
+                }
+            }
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
index f0e3b67..d23e211 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDispatchTest.java
@@ -25,7 +25,6 @@
 import static android.accessibilityservice.cts.utils.GestureUtils.IS_ACTION_POINTER_UP;
 import static android.accessibilityservice.cts.utils.GestureUtils.IS_ACTION_UP;
 import static android.accessibilityservice.cts.utils.GestureUtils.add;
-import static android.accessibilityservice.cts.utils.GestureUtils.ceil;
 import static android.accessibilityservice.cts.utils.GestureUtils.click;
 import static android.accessibilityservice.cts.utils.GestureUtils.diff;
 import static android.accessibilityservice.cts.utils.GestureUtils.dispatchGesture;
@@ -56,11 +55,11 @@
 import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
 import android.app.Instrumentation;
 import android.app.UiAutomation;
-import android.content.Context;
 import android.content.pm.PackageManager;
 import android.graphics.Matrix;
 import android.graphics.Path;
 import android.graphics.PointF;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.platform.test.annotations.AppModeFull;
@@ -69,7 +68,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.WindowManager;
 import android.widget.TextView;
 
 import androidx.test.rule.ActivityTestRule;
@@ -88,8 +86,6 @@
 import java.util.List;
 import java.util.concurrent.atomic.AtomicBoolean;
 
-import android.graphics.Rect;
-
 /**
  * Verify that gestures dispatched from an accessibility service show up in the current UI
  */
@@ -196,7 +192,8 @@
         // Verify other MotionEvent fields in this test to make sure they get initialized.
         assertEquals(0, clickDown.getActionIndex());
         assertEquals(VIRTUAL_KEYBOARD, clickDown.getDeviceId());
-        assertEquals(MotionEvent.FLAG_IS_ACCESSIBILITY_EVENT, clickDown.getFlags());
+        assertEquals(MotionEvent.FLAG_IS_ACCESSIBILITY_EVENT,
+                clickDown.getFlags() & MotionEvent.FLAG_IS_ACCESSIBILITY_EVENT);
         assertEquals(0, clickDown.getEdgeFlags());
         assertEquals(1F, clickDown.getXPrecision(), 0F);
         assertEquals(1F, clickDown.getYPrecision(), 0F);
diff --git a/tests/app/src/android/app/cts/DisplayTest.java b/tests/app/src/android/app/cts/DisplayTest.java
index f0669b9..a79a6b3 100644
--- a/tests/app/src/android/app/cts/DisplayTest.java
+++ b/tests/app/src/android/app/cts/DisplayTest.java
@@ -20,12 +20,17 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import android.app.ActivityOptions;
 import android.app.stubs.DisplayTestActivity;
 import android.app.stubs.OrientationTestUtils;
+import android.content.Intent;
 import android.graphics.Point;
 import android.server.wm.SetRequestedOrientationRule;
+import android.util.Pair;
 import android.view.Display;
 
+import androidx.test.platform.app.InstrumentationRegistry;
+
 import com.android.compatibility.common.util.ApiTest;
 
 import org.junit.Rule;
@@ -52,55 +57,62 @@
             return;
         }
 
-        final DisplayTestActivity activity =
-                mSetRequestedOrientationRule.launchActivityInFullscreen(DisplayTestActivity.class);
+        final Pair<Intent, ActivityOptions> launchArgs =
+                SetRequestedOrientationRule.buildFullScreenLaunchArgs(DisplayTestActivity.class);
 
-        // Get a {@link Display} instance before rotation.
-        final Display origDisplay = activity.getDisplay();
+        final DisplayTestActivity activity = (DisplayTestActivity) InstrumentationRegistry
+                .getInstrumentation()
+                .startActivitySync(launchArgs.first, launchArgs.second.toBundle());
+        try {
+            // Get a {@link Display} instance before rotation.
+            final Display origDisplay = activity.getDisplay();
 
-        // Capture the originally reported width and heights
-        final Point origSize = new Point();
-        origDisplay.getRealSize(origSize);
+            // Capture the originally reported width and heights
+            final Point origSize = new Point();
+            origDisplay.getRealSize(origSize);
 
-        // Change orientation
-        activity.configurationChangeObserver.startObserving();
-        OrientationTestUtils.switchOrientation(activity);
+            // Change orientation
+            activity.configurationChangeObserver.startObserving();
+            OrientationTestUtils.switchOrientation(activity);
 
-        final boolean closeToSquareBounds =
-                OrientationTestUtils.isCloseToSquareBounds(activity);
+            final boolean closeToSquareBounds =
+                    OrientationTestUtils.isCloseToSquareBounds(activity);
 
-        // Don't wait for the configuration to change if
-        // the display is square. In many cases it won't.
-        if (!closeToSquareBounds) {
-            activity.configurationChangeObserver.await();
-        }
+            // Don't wait for the configuration to change if
+            // the display is square. In many cases it won't.
+            if (!closeToSquareBounds) {
+                activity.configurationChangeObserver.await();
+            }
 
-        final Point newOrigSize = new Point();
-        origDisplay.getRealSize(newOrigSize);
+            final Point newOrigSize = new Point();
+            origDisplay.getRealSize(newOrigSize);
 
-        // Get a {@link Display} instance after rotation.
-        final Display updatedDisplay = activity.getDisplay();
-        final Point updatedSize = new Point();
-        updatedDisplay.getRealSize(updatedSize);
+            // Get a {@link Display} instance after rotation.
+            final Display updatedDisplay = activity.getDisplay();
+            final Point updatedSize = new Point();
+            updatedDisplay.getRealSize(updatedSize);
 
-        // For square screens the following assertions do not make sense and will always
-        // fail.
-        if (!closeToSquareBounds) {
-            // Ensure that the width and height of the original instance no longer are the
-            // same.
-            // Note that this will be false if the device width and height are identical.
-            // Note there are cases where width and height may not all be updated, such as
-            // on docked devices where the app is letterboxed. However, at least one
-            // dimension needs to be updated.
+            // For square screens the following assertions do not make sense and will always
+            // fail.
+            if (!closeToSquareBounds) {
+                // Ensure that the width and height of the original instance no longer are the
+                // same.
+                // Note that this will be false if the device width and height are identical.
+                // Note there are cases where width and height may not all be updated, such as
+                // on docked devices where the app is letterboxed. However, at least one
+                // dimension needs to be updated.
+                assertWithMessage(
+                        "size from original display instance should have changed")
+                        .that(origSize).isNotEqualTo(newOrigSize);
+            }
+
+            // Ensure that the width and height of the original instance have been updated to
+            // match the values that would be found in a new instance.
             assertWithMessage(
-                    "size from original display instance should have changed")
-                    .that(origSize).isNotEqualTo(newOrigSize);
+                    "size from original display instance should match current")
+                    .that(newOrigSize).isEqualTo(updatedSize);
+        } finally {
+            InstrumentationRegistry.getInstrumentation().runOnMainSync(activity::finish);
         }
-
-        // Ensure that the width and height of the original instance have been updated to
-        // match the values that would be found in a new instance.
-        assertWithMessage(
-                "size from original display instance should match current")
-                .that(newOrigSize).isEqualTo(updatedSize);
     }
 }
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index ff8bf56..cd1de26 100644
--- a/tests/app/src/android/app/cts/NotificationTemplateTest.kt
+++ b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
@@ -16,7 +16,6 @@
 package android.app.cts
 
 import android.R
-import android.app.ActivityManager
 import android.app.Notification
 import android.app.PendingIntent
 import android.app.Person
@@ -36,7 +35,6 @@
 import androidx.test.filters.SmallTest
 import com.android.compatibility.common.util.CddTest
 import com.google.common.truth.Truth.assertThat
-import kotlin.math.min
 import kotlin.test.assertFailsWith
 
 class NotificationTemplateTest : NotificationTemplateTestBase() {
@@ -144,11 +142,10 @@
     }
 
     fun testWideIcon_inBigPicture_cappedTo16By9() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_cappedTo16By9" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 100)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -166,11 +163,10 @@
     }
 
     fun testWideIcon_inBigPicture_canShowExact4By3() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_canShowExact4By3" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(400, 300)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -188,11 +184,10 @@
     }
 
     fun testWideIcon_inBigPicture_neverNarrowerThanSquare() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_neverNarrowerThanSquare" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 300)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -254,11 +249,10 @@
     }
 
     fun testBigPictureStyle_populatesExtrasCompatibly() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testBigPictureStyle_populatesExtrasCompatibly" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val bitmap = createBitmap(40, 30)
         val uri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
         val iconWithUri = Icon.createWithContentUri(uri)
@@ -272,7 +266,7 @@
         style.bigPicture(bitmap)
         builder.build().let {
             assertThat(it.extras.getParcelable<Bitmap>(Notification.EXTRA_PICTURE)
-                    !!.sameAs(bitmap)).isTrue()
+            !!.sameAs(bitmap)).isTrue()
             assertThat(it.extras.get(Notification.EXTRA_PICTURE_ICON)).isNull()
         }
 
@@ -286,18 +280,17 @@
         style.bigPicture(iconWithBitmap)
         builder.build().let {
             assertThat(it.extras.getParcelable<Bitmap>(Notification.EXTRA_PICTURE)
-                    !!.sameAs(bitmap)).isTrue()
+            !!.sameAs(bitmap)).isTrue()
             assertThat(it.extras.get(Notification.EXTRA_PICTURE_ICON)).isNull()
         }
     }
 
     @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testBigPictureStyle_bigPictureUriIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testBigPictureStyle_bigPictureUriIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_400_by_300.png")
         val pictureIcon = Icon.createWithContentUri(pictureUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -307,28 +300,19 @@
         checkViews(builder.createBigContentView()) {
             val pictureView = requireViewByIdName<ImageView>("big_picture")
             assertThat(pictureView.visibility).isEqualTo(View.VISIBLE)
-
-            var expectedWidth = min(400, bigPictureWidth())
-            var expectedHeight = min(300, bigPictureWidth() * 3 / 4)
-            // It's possible that big picture width is configured smaller than we expect here.
-            // In that situation, we need to flip the expected size.
-            if (bigPictureHeight() < expectedHeight) {
-                expectedHeight = bigPictureHeight()
-                expectedWidth = bigPictureHeight() * 4 / 3
-            }
-
-            assertThat(pictureView.drawable.intrinsicWidth).isEqualTo(expectedWidth)
-            assertThat(pictureView.drawable.intrinsicHeight).isEqualTo(expectedHeight)
+            assertThat(pictureView.width.toFloat())
+                    .isWithin(1f)
+                    .of((pictureView.height * 4 / 3).toFloat())
+            assertThat(pictureView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
     @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testPromoteBigPicture_withBigPictureUriIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withBigPictureUriIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val pictureUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val pictureIcon = Icon.createWithContentUri(pictureUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -343,17 +327,15 @@
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(rightIconSize())
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(rightIconSize() * 3 / 4)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
     fun testPromoteBigPicture_withoutLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withoutLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -367,8 +349,7 @@
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         checkIconView(builder.createBigContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.GONE)
@@ -376,11 +357,10 @@
     }
 
     fun testPromoteBigPicture_withLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(80, 65)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -392,37 +372,28 @@
                         .showBigPictureWhenCollapsed(true)
                 )
 
-        // At really high densities the size of rendered icon can dip below the
-        // tested size - we allow rendering of smaller icon with the same
-        // aspect ratio then.
-        val expectedIconWidth = minOf(rightIconSize(), 80)
-        val expectedIconHeight = minOf(rightIconSize() * 65 / 80, 65)
-
         checkIconView(builder.createContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         checkIconView(builder.createBigContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 80 / 65).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(expectedIconWidth)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(expectedIconHeight)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
     @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testPromoteBigPicture_withBigLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withBigLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val inputWidth = 400
         val inputHeight = 300
@@ -436,36 +407,30 @@
                         .showBigPictureWhenCollapsed(true)
                 )
 
-        val expectedIconWidth = minOf(rightIconSize(), inputWidth)
-        val expectedIconHeight = minOf(rightIconSize() * inputHeight / inputWidth, inputHeight)
-
         checkIconView(builder.createContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         checkIconView(builder.createBigContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(expectedIconWidth)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(expectedIconHeight)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         assertThat(builder.build().extras.getParcelable<Bitmap>(Notification.EXTRA_PICTURE)
-                !!.sameAs(picture)).isTrue()
+        !!.sameAs(picture)).isTrue()
     }
 
     @CddTest(requirement = "3.8.3.1/C-2-1")
     fun testBigPicture_withBigLargeIcon_withContentUri() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testBigPicture_withBigLargeIcon_withContentUri" +
-                    " - BigPictureStyle is not supported in automotive.")
+    if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val iconUri = Uri.parse("content://android.app.stubs.assets/picture_800_by_600.png")
         val icon = Icon.createWithContentUri(iconUri)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -477,9 +442,7 @@
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(rightIconSize())
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(rightIconSize() * 3 / 4)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
@@ -864,39 +827,14 @@
         PendingIntent.getBroadcast(mContext, 0, Intent("test"), PendingIntent.FLAG_IMMUTABLE)
     }
 
-    private fun rightIconSize(): Int {
-        return mContext.resources.getDimensionPixelSize(getAndroidRDimen(
-                if (isLowRamDevice()) {
-                    "notification_right_icon_size_low_ram"
-                } else {
-                    "notification_right_icon_size"
-                }))
-    }
-
-    private fun bigPictureWidth(): Int {
-        return mContext.resources.getDimensionPixelSize(getAndroidRDimen(
-                if (isLowRamDevice()) {
-                    "notification_big_picture_max_width_low_ram"
-                } else {
-                    "notification_big_picture_max_width"
-                }))
-    }
-
-    private fun bigPictureHeight(): Int {
-        return mContext.resources.getDimensionPixelSize(getAndroidRDimen(
-                if (isLowRamDevice()) {
-                    "notification_big_picture_max_width_low_ram"
-                } else {
-                    "notification_big_picture_max_width"
-                }))
-    }
-
-    private fun isLowRamDevice(): Boolean {
-        return mContext.getSystemService(ActivityManager::class.java).isLowRamDevice()
-    }
-
-    private fun isPlatformAutomotive(): Boolean {
-        return mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    /**
+     * Assume that we're running on the platform that supports styled notifications.
+     *
+     * If the current platform does not support notification styles, skip this test without failure.
+     */
+    private fun skipIfPlatformDoesNotSupportNotificationStyles(): Boolean {
+        return mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
+                        mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
     }
 
     companion object {
diff --git a/tests/appsearch/Android.bp b/tests/appsearch/Android.bp
index c8219c9..f858b17 100644
--- a/tests/appsearch/Android.bp
+++ b/tests/appsearch/Android.bp
@@ -40,6 +40,7 @@
         ":CtsAppSearchTestHelperB",
     ],
     per_testcase_directory: true,
+    min_sdk_version: "31",
 }
 
 android_test_helper_app {
@@ -67,6 +68,7 @@
     ],
     certificate: ":cts-appsearch-helper-cert-a",
     sdk_version: "test_current",
+    min_sdk_version: "31",
 }
 
 android_test_helper_app {
@@ -94,6 +96,7 @@
     ],
     certificate: ":cts-appsearch-helper-cert-b",
     sdk_version: "test_current",
+    min_sdk_version: "31",
 }
 
 filegroup {
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 18d4904..533ece4 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -33,6 +33,7 @@
 import android.hardware.camera2.cts.CameraTestUtils.HandlerExecutor;
 import android.hardware.camera2.cts.CameraTestUtils.MockStateCallback;
 import android.hardware.camera2.cts.helpers.CameraErrorCollector;
+import android.hardware.camera2.cts.helpers.StaticMetadata;
 import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -669,18 +670,23 @@
     }
 
     private <T> void verifyAvailabilityCbsReceived(HashSet<T> expectedCameras,
-            LinkedBlockingQueue<T> queue, LinkedBlockingQueue<T> otherQueue,
+            LinkedBlockingQueue<T> expectedEventQueue, LinkedBlockingQueue<T> unExpectedEventQueue,
             boolean available) throws Exception {
         while (expectedCameras.size() > 0) {
-            T id = queue.poll(AVAILABILITY_TIMEOUT_MS,
+            T id = expectedEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
                     java.util.concurrent.TimeUnit.MILLISECONDS);
             assertTrue("Did not receive initial " + (available ? "available" : "unavailable")
                     + " notices for some cameras", id != null);
+            assertTrue("Received initial " + (available ? "available" : "unavailable")
+                    + " notice for wrong camera " + id, expectedCameras.contains(id));
             expectedCameras.remove(id);
         }
-        // Verify no unavailable/available cameras were reported
-        assertTrue("Some camera devices are initially " + (available ? "unavailable" : "available"),
-                otherQueue.size() == 0);
+        // Verify no unexpected unavailable/available cameras were reported
+        if (unExpectedEventQueue != null) {
+            assertTrue("Received unexpected initial "
+                    + (available ? "unavailable" : "available"),
+                    unExpectedEventQueue.size() == 0);
+        }
     }
 
     private void verifySingleAvailabilityCbsReceived(LinkedBlockingQueue<String> expectedEventQueue,
@@ -781,15 +787,15 @@
         verifyAvailabilityCbsReceived(expectedAvailableCameras, availableEventQueue,
                 unavailableEventQueue, true /*available*/);
 
+        // Clear physical camera callback queue in case the initial state of certain physical
+        // cameras are unavailable.
+        unavailablePhysicalCamEventQueue.clear();
+
         // Verify transitions for individual cameras
         for (String id : cameras) {
             MockStateCallback mockListener = MockStateCallback.mock();
             mCameraListener = new BlockingStateCallback(mockListener);
 
-            // Clear logical camera callback queue in case the initial state of certain physical
-            // cameras are unavailable.
-            unavailablePhysicalCamEventQueue.clear();
-
             if (useExecutor) {
                 mCameraManager.openCamera(id, executor, mCameraListener);
             } else {
@@ -843,8 +849,13 @@
 
             expectedLogicalCameras = new HashSet<Pair<String, String>>(relatedLogicalCameras);
             verifyAvailabilityCbsReceived(expectedLogicalCameras,
-                    availablePhysicalCamEventQueue, unavailablePhysicalCamEventQueue,
+                    availablePhysicalCamEventQueue,
+                    null /*unExpectedEventQueue*/,
                     true /*available*/);
+
+            // Clear physical camera callback queue in case the initial state of certain physical
+            // cameras are unavailable.
+            unavailablePhysicalCamEventQueue.clear();
         }
 
         // Verify that we can unregister the listener and see no more events
@@ -938,9 +949,142 @@
 
             verifySingleAvailabilityCbsReceived(onCameraClosedEventQueue,
                     onCameraOpenedEventQueue, cameras[0], "onCameraClosed", "onCameraOpened");
+
+            mCameraManager.unregisterAvailabilityCallback(ac);
         }
     } // testCameraManagerListenerCallbacks
 
+    /**
+     * Test that the physical camera available/unavailable callback behavior is consistent
+     * between:
+     *
+     * - No camera is open, and
+     * - camera opens, close camera, expect callback
+     */
+    @Test
+    public void testPhysicalCameraAvailabilityConsistency() throws Throwable {
+        final LinkedBlockingQueue<String> availableEventQueue = new LinkedBlockingQueue<>();
+        final LinkedBlockingQueue<String> unavailableEventQueue = new LinkedBlockingQueue<>();
+        final LinkedBlockingQueue<Pair<String, String>> unavailablePhysicalCamEventQueue =
+                new LinkedBlockingQueue<>();
+        CameraManager.AvailabilityCallback ac = new CameraManager.AvailabilityCallback() {
+            @Override
+            public void onCameraAvailable(String cameraId) {
+                super.onCameraAvailable(cameraId);
+                availableEventQueue.offer(cameraId);
+            }
+
+            @Override
+            public void onCameraUnavailable(String cameraId) {
+                super.onCameraUnavailable(cameraId);
+                unavailableEventQueue.offer(cameraId);
+            }
+
+            @Override
+            public void onPhysicalCameraAvailable(String cameraId, String physicalCameraId) {
+                super.onPhysicalCameraAvailable(cameraId, physicalCameraId);
+                unavailablePhysicalCamEventQueue.remove(new Pair<>(cameraId, physicalCameraId));
+            }
+
+            @Override
+            public void onPhysicalCameraUnavailable(String cameraId, String physicalCameraId) {
+                super.onPhysicalCameraUnavailable(cameraId, physicalCameraId);
+                unavailablePhysicalCamEventQueue.offer(new Pair<>(cameraId, physicalCameraId));
+            }
+        };
+
+        String[] cameras = mCameraIdsUnderTest;
+        if (cameras.length == 0) {
+            Log.i(TAG, "Skipping testPhysicalCameraAvailabilityConsistency, no cameras");
+            return;
+        }
+
+        for (String cameraId : cameras) {
+            CameraCharacteristics ch = mCameraManager.getCameraCharacteristics(cameraId);
+            StaticMetadata staticInfo = new StaticMetadata(ch);
+            if (!staticInfo.isLogicalMultiCamera()) {
+                // Test is only applicable for logical multi-camera.
+                continue;
+            }
+
+            // Get initial physical unavailable callbacks without opening camera
+            mCameraManager.registerAvailabilityCallback(ac, mHandler);
+            Set<String> unavailablePhysicalCameras = getUnavailablePhysicalCamerasAndDrain(
+                    unavailablePhysicalCamEventQueue, cameraId);
+
+            // Open camera
+            MockStateCallback mockListener = MockStateCallback.mock();
+            mCameraListener = new BlockingStateCallback(mockListener);
+            mCameraManager.openCamera(cameraId, mCameraListener, mHandler);
+            // Block until opened
+            mCameraListener.waitForState(BlockingStateCallback.STATE_OPENED,
+                    CameraTestUtils.CAMERA_IDLE_TIMEOUT_MS);
+            // Then verify only open happened, and get the camera handle
+            CameraDevice camera = verifyCameraStateOpened(cameraId, mockListener);
+
+            // The camera should be in available->unavailable state.
+            String candidateUnavailableId = unavailableEventQueue.poll(AVAILABILITY_TIMEOUT_MS,
+                    java.util.concurrent.TimeUnit.MILLISECONDS);
+            assertNotNull("No unavailable notice for expected ID " + cameraId,
+                    candidateUnavailableId);
+            assertTrue("Received unavailable notice for wrong ID, "
+                    + "expected " + cameraId + ", got " + candidateUnavailableId,
+                    cameraId.equals(candidateUnavailableId));
+            assertTrue("Received >  1 unavailable callback for id " + cameraId,
+                    unavailableEventQueue.size() == 0);
+            availableEventQueue.clear();
+            unavailableEventQueue.clear();
+
+            // Close camera device
+            camera.close();
+            mCameraListener.waitForState(BlockingStateCallback.STATE_CLOSED,
+                    CameraTestUtils.CAMERA_CLOSE_TIMEOUT_MS);
+            verifySingleAvailabilityCbsReceived(availableEventQueue, unavailableEventQueue,
+                    cameraId, "availability", "Unavailability");
+
+            // Get physical unavailable callbacks after opening and closing camera
+            Set<String> unavailablePhysicalCamerasAfterClose =
+                    getUnavailablePhysicalCamerasAndDrain(
+                            unavailablePhysicalCamEventQueue, cameraId);
+
+            assertTrue("The unavailable physical cameras must be the same between before open "
+                    + unavailablePhysicalCameras.toString()  + " and after close "
+                    + unavailablePhysicalCamerasAfterClose.toString(),
+                    unavailablePhysicalCameras.equals(unavailablePhysicalCamerasAfterClose));
+
+            mCameraManager.unregisterAvailabilityCallback(ac);
+        }
+    }
+
+    /**
+     * This function polls on the event queue to get unavailable physical camera IDs belonging
+     * to a particular logical camera. The event queue is drained before the function returns.
+     *
+     * @param queue The event queue capturing unavailable physical cameras
+     * @param cameraId The logical camera ID
+     *
+     * @return The currently unavailable physical cameras
+     */
+    private Set<String> getUnavailablePhysicalCamerasAndDrain(
+            LinkedBlockingQueue<Pair<String, String>> queue, String cameraId) throws Exception {
+        Set<String> unavailablePhysicalCameras = new HashSet<String>();
+
+        while (true) {
+            Pair<String, String> unavailableIdCombo = queue.poll(
+                    AVAILABILITY_TIMEOUT_MS, java.util.concurrent.TimeUnit.MILLISECONDS);
+            if (unavailableIdCombo == null) {
+                // No more entries in the queue. Break out of the loop and return.
+                break;
+            }
+
+            if (cameraId.equals(unavailableIdCombo.first)) {
+                unavailablePhysicalCameras.add(unavailableIdCombo.second);
+            }
+        };
+
+        return unavailablePhysicalCameras;
+    }
+
     // Verify no LEGACY-level devices appear on devices first launched in the Q release or newer
     @Test
     @AppModeFull(reason = "Instant apps can't access Test API")
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
index 52e1a7e..8d6d421 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
@@ -37,6 +37,7 @@
 import android.os.HandlerExecutor;
 import android.os.HandlerThread;
 import android.os.Process;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.util.Range;
 
@@ -55,11 +56,18 @@
 import org.junit.Before;
 import org.junit.ClassRule;
 import org.junit.Rule;
+import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
+import java.net.Socket;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.TimeUnit;
 
 // TODO(b/190797743): Move this test to to net test folder.
 @RunWith(BedsteadJUnit4.class)
@@ -102,6 +110,33 @@
     }
 
     /**
+     * Make sure both including and excluding UIDs from a policy is disallowed.
+     */
+    @Test
+    public void buildPreferentialNetworkServiceConfig_includedAndExcluded() {
+        // May not set both included and excluded UIDs
+        assertThrows(IllegalStateException.class, () ->
+                new PreferentialNetworkServiceConfig.Builder()
+                        .setIncludedUids(new int[] { 1001, 1002 })
+                        .setExcludedUids(new int[] { 1003, 1004 })
+                        .build());
+    }
+
+    /**
+     * Make sure setting fallback allowed and blocking together is disallowed.
+     */
+    @Test
+    public void buildPreferentialNetworkServiceConfig_fallbackAndBlock() {
+        // May not set block non-matching networks and fallback to default connection at the same
+        // time, because this makes no sense when there is no preferential network service available
+        assertThrows(IllegalStateException.class, () ->
+                new PreferentialNetworkServiceConfig.Builder()
+                        .setFallbackToDefaultConnectionAllowed(true)
+                        .setShouldBlockNonMatchingNetworks(true)
+                        .build());
+    }
+
+    /**
      * Enable PreferentialNetworkService, verify the provider that provides enterprise slice can
      * see the enterprise slice requests.
      */
@@ -174,6 +209,85 @@
         }
     }
 
+    /**
+     * Enable PreferentialNetworkService with blocking non-enterprise network feature enabled,
+     * verify the application cannot access non-enterprise network.
+     */
+    @EnsureHasPermission({ACCESS_NETWORK_STATE, NETWORK_SETTINGS})
+    @PolicyAppliesTest(policy = PreferentialNetworkService.class)
+    public void setPreferentialNetworkServiceEnabled_blockingNonEnterprise_noAccess()
+            throws Exception {
+        // Expect a regular default network.
+        final Network defaultNetwork = Objects.requireNonNull(sCm.getActiveNetwork(),
+                "Default network is required to perform the test.");
+        final TestableNetworkCallback defaultCallback = new TestableNetworkCallback();
+        sCm.registerDefaultNetworkCallback(defaultCallback);
+        defaultCallback.expectAvailableCallbacks(defaultNetwork, /* suspended= */ false,
+                /* validated= */ true, /* blocked= */ false, DEFAULT_TIMEOUT_MS);
+
+        // Verify the default network could be accessed.
+        assertBindSocketToNetwork(true /* expectSuccess */, defaultNetwork);
+
+        PreferentialNetworkServiceConfig blockConfig =
+                (new PreferentialNetworkServiceConfig.Builder())
+                        .setEnabled(true)
+                        .setNetworkId(PreferentialNetworkServiceConfig.PREFERENTIAL_NETWORK_ID_1)
+                        .setFallbackToDefaultConnectionAllowed(false)
+                        .setShouldBlockNonMatchingNetworks(true)
+                        .build();
+        try {
+            // Enable PreferentialNetworkService, with blocking non-enterprise network feature
+            // enabled. The default network should be lost since the preference does not allow
+            // fallback.
+            sDeviceState.dpc().devicePolicyManager().setPreferentialNetworkServiceConfigs(
+                    List.of(blockConfig));
+            defaultCallback.expect(TestableNetworkCallback.CallbackEntry.LOST, DEFAULT_TIMEOUT_MS);
+
+            // Verify the application cannot access default network  since it is
+            // a non-enterprise network.
+            assertBindSocketToNetwork(false /* expectSuccess */, defaultNetwork);
+        } finally {
+            sCm.unregisterNetworkCallback(defaultCallback);
+            sDeviceState.dpc().devicePolicyManager().setPreferentialNetworkServiceConfigs(
+                    List.of(PreferentialNetworkServiceConfig.DEFAULT));
+        }
+    }
+
+    // TODO: Copied and modified from android.net.cts.ConnectivityManager. Need to refactor them
+    //  to a common place.
+    private void assertBindSocketToNetwork(boolean expectSuccess, final Network network)
+            throws Exception {
+        final CompletableFuture<Boolean> future = new CompletableFuture<>();
+        final ExecutorService executor = Executors.newSingleThreadExecutor();
+        try {
+            executor.execute(() -> {
+                for (int i = 0; i < 300; i++) {
+                    SystemClock.sleep(10);
+
+                    try (Socket socket = new Socket()) {
+                        network.bindSocket(socket);
+                        if (expectSuccess) {
+                            future.complete(true);
+                            return;
+                        }
+                    } catch (IOException e) {
+                        if (!expectSuccess) {
+                            future.complete(false);
+                            return;
+                        }
+                    }
+                }
+            });
+            if (expectSuccess) {
+                assertThat(future.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isTrue();
+            } else {
+                assertThat(future.get(DEFAULT_TIMEOUT_MS, TimeUnit.MILLISECONDS)).isFalse();
+            }
+        } finally {
+            executor.shutdown();
+        }
+    }
+
     @CannotSetPolicyTest(policy = PreferentialNetworkService.class)
     public void setPreferentialNetworkServiceEnabled_enableService_throwsSecurityException() {
         assertThrows(SecurityException.class,
@@ -232,6 +346,33 @@
     }
 
     @CanSetPolicyTest(policy = PreferentialNetworkService.class)
+    public void setPreferentialNetworkServiceConfigs_block_isSet() {
+        PreferentialNetworkServiceConfig blockConfig =
+                (new PreferentialNetworkServiceConfig.Builder())
+                        .setEnabled(true)
+                        .setNetworkId(PreferentialNetworkServiceConfig.PREFERENTIAL_NETWORK_ID_1)
+                        .setFallbackToDefaultConnectionAllowed(false)
+                        .setShouldBlockNonMatchingNetworks(true)
+                        .build();
+        try {
+            sDeviceState.dpc().devicePolicyManager().setPreferentialNetworkServiceConfigs(
+                    List.of(blockConfig));
+
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .getPreferentialNetworkServiceConfigs().get(0).isEnabled()).isTrue();
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .getPreferentialNetworkServiceConfigs().get(0)
+                    .shouldBlockNonMatchingNetworks()).isTrue();
+            assertThat(sDeviceState.dpc().devicePolicyManager()
+                    .getPreferentialNetworkServiceConfigs().get(0)
+                    .isFallbackToDefaultConnectionAllowed()).isFalse();
+        } finally {
+            sDeviceState.dpc().devicePolicyManager().setPreferentialNetworkServiceConfigs(
+                    List.of(PreferentialNetworkServiceConfig.DEFAULT));
+        }
+    }
+
+    @CanSetPolicyTest(policy = PreferentialNetworkService.class)
     public void setPreferentialNetworkServiceConfigs_enabled_isSet_excludedUids_set() {
         UserHandle user = UserHandle.of(sContext.getUserId());
         final int currentUid = user.getUid(0 /* appId */);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/UserRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserRestrictionsTest.java
index 61301a5..af4bf24 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserRestrictionsTest.java
@@ -18,6 +18,7 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assume.assumeFalse;
 import static org.testng.Assert.assertThrows;
 
 import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -31,6 +32,9 @@
 import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnUnaffiliatedProfileOwnerSecondaryUser;
 import com.android.bedstead.harrier.policies.AffiliatedProfileOwnerOnlyUserRestrictions;
 import com.android.bedstead.harrier.policies.UserRestrictions;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.devicepolicy.DeviceOwner;
+import com.android.bedstead.nene.devicepolicy.DeviceOwnerType;
 import com.android.bedstead.nene.userrestrictions.CommonUserRestrictions;
 import com.android.compatibility.common.util.BlockingBroadcastReceiver;
 
@@ -327,6 +331,8 @@
     @Postsubmit(reason = "new test")
     public void addUserRestriction_deviceOwnerOnlyRestriction_throwsSecurityException(
             @DeviceOwnerOnlyUserRestrictions String restriction) {
+        skipTestForFinancedDevice();
+
         try {
             assertThrows(SecurityException.class, () -> {
                 sDeviceState.dpc().devicePolicyManager().addUserRestriction(
@@ -371,4 +377,12 @@
             broadcastReceiver.awaitForBroadcastOrFail();
         }
     }
+
+    private void skipTestForFinancedDevice() {
+        DeviceOwner deviceOwner = TestApis.devicePolicy().getDeviceOwner();
+
+        // TODO(): Determine a pattern to special case states so that they are not considered in
+        //  tests.
+        assumeFalse(deviceOwner != null && deviceOwner.getType() == DeviceOwnerType.FINANCED);
+    }
 }
diff --git a/tests/framework/base/biometrics/OWNERS b/tests/framework/base/biometrics/OWNERS
index 95749d0..fbd1d59 100644
--- a/tests/framework/base/biometrics/OWNERS
+++ b/tests/framework/base/biometrics/OWNERS
@@ -5,3 +5,4 @@
 jaggies@google.com
 jbolinger@google.com
 joshmccloskey@google.com
+jeffpu@google.com
diff --git a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
index 1bb7eea..fa05e86 100644
--- a/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
+++ b/tests/framework/base/biometrics/src/android/server/biometrics/BiometricTestBase.java
@@ -523,6 +523,13 @@
         mInstrumentation.waitForIdleSync();
         Utils.waitForBusySensor(sensorId, this::getSensorStates);
 
+        //Wait for enrollment operation in biometrics sensor to be complete before
+        //retrieving enrollment results. The operation takes a little time especically
+        //on Cutterfish where multiple biometric operations must be completed during
+        //the enrollent
+        //TODO(b/217275524)
+        Thread.sleep(200);
+
         session.finishEnroll(userId);
         mInstrumentation.waitForIdleSync();
         Utils.waitForIdleService(this::getSensorStates);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index ca5c66c..806f2af 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -514,7 +514,8 @@
         // Bring launching activity back to the foreground
         launchActivityNoWait(LAUNCHING_ACTIVITY);
         // Wait for the most front activity of the task.
-        mWmState.waitForValidState(ALT_LAUNCHING_ACTIVITY);
+        mWmState.waitForFocusedActivity("Waiting for Alt Launching Activity to be focused",
+                ALT_LAUNCHING_ACTIVITY);
 
         // Ensure the alternate launching activity is still in focus.
         mWmState.assertFocusedActivity("Alt Launching Activity must be focused",
@@ -523,7 +524,8 @@
         pressBackButton();
 
         // Wait for the bottom activity back to the foreground.
-        mWmState.waitForValidState(LAUNCHING_ACTIVITY);
+        mWmState.waitForFocusedActivity("Waiting for Launching Activity to be focused",
+                LAUNCHING_ACTIVITY);
 
         // Ensure launching activity was brought forward.
         mWmState.assertFocusedActivity("Launching Activity must be focused",
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTests.java
index 38b3ed7..a8e8c07 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTests.java
@@ -16,6 +16,7 @@
 
 package android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.server.wm.app.Components.MAX_ASPECT_RATIO_ACTIVITY;
 import static android.server.wm.app.Components.MAX_ASPECT_RATIO_RESIZABLE_ACTIVITY;
 import static android.server.wm.app.Components.MAX_ASPECT_RATIO_UNSET_ACTIVITY;
@@ -52,7 +53,7 @@
     @Test
     public void testMaxAspectRatio() {
         // Activity has a maxAspectRatio, assert that the actual ratio is less than that.
-        runAspectRatioTest(MAX_ASPECT_RATIO_ACTIVITY,
+        runAspectRatioTest(MAX_ASPECT_RATIO_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             assertThat(actual, lessThanOrEqualTo(MAX_ASPECT_RATIO));
         });
@@ -61,7 +62,7 @@
     @Test
     public void testMetaDataMaxAspectRatio() {
         // Activity has a maxAspectRatio, assert that the actual ratio is less than that.
-        runAspectRatioTest(META_DATA_MAX_ASPECT_RATIO_ACTIVITY,
+        runAspectRatioTest(META_DATA_MAX_ASPECT_RATIO_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             assertThat(actual, lessThanOrEqualTo(MAX_ASPECT_RATIO));
         });
@@ -70,7 +71,7 @@
     @Test
     public void testMaxAspectRatioResizeableActivity() {
         // Since this activity is resizeable, its max aspect ratio should be ignored.
-        runAspectRatioTest(MAX_ASPECT_RATIO_RESIZABLE_ACTIVITY,
+        runAspectRatioTest(MAX_ASPECT_RATIO_RESIZABLE_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             // TODO(b/69982434): Add ability to get native aspect ratio non-default display.
             assumeThat(displayId, is(Display.DEFAULT_DISPLAY));
@@ -85,7 +86,7 @@
     public void testMaxAspectRatioUnsetActivity() {
         // Since this activity didn't set an explicit maxAspectRatio, there should be no such
         // ratio enforced.
-        runAspectRatioTest(MAX_ASPECT_RATIO_UNSET_ACTIVITY,
+        runAspectRatioTest(MAX_ASPECT_RATIO_UNSET_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             // TODO(b/69982434): Add ability to get native aspect ratio non-default display.
             assumeThat(displayId, is(Display.DEFAULT_DISPLAY));
@@ -98,7 +99,7 @@
     @Test
     public void testMinAspectRatio() {
         // Activity has a minAspectRatio, assert the ratio is at least that.
-        runAspectRatioTest(MIN_ASPECT_RATIO_ACTIVITY,
+        runAspectRatioTest(MIN_ASPECT_RATIO_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             assertThat(actual, greaterThanOrEqualToInexact(MIN_ASPECT_RATIO));
         });
@@ -108,7 +109,7 @@
     public void testMinAspectRatioUnsetActivity() {
         // Since this activity didn't set an explicit minAspectRatio, there should be no such
         // ratio enforced.
-        runAspectRatioTest(MIN_ASPECT_RATIO_UNSET_ACTIVITY,
+        runAspectRatioTest(MIN_ASPECT_RATIO_UNSET_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             // TODO(b/69982434): Add ability to get native aspect ratio non-default display.
             assumeThat(displayId, is(Display.DEFAULT_DISPLAY));
@@ -121,7 +122,7 @@
     @Test
     public void testMinAspectLandscapeActivity() {
         // Activity has requested a fixed orientation, assert the orientation is that.
-        runAspectRatioTest(MIN_ASPECT_RATIO_LANDSCAPE_ACTIVITY,
+        runAspectRatioTest(MIN_ASPECT_RATIO_LANDSCAPE_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             assertThat(activitySize.x, greaterThan(activitySize.y));
             // Since activities must fit within the bounds of the display and they should respect
@@ -140,7 +141,7 @@
 
     @Test
     public void testMinAspectPortraitActivity() {
-        runAspectRatioTest(MIN_ASPECT_RATIO_PORTRAIT_ACTIVITY,
+        runAspectRatioTest(MIN_ASPECT_RATIO_PORTRAIT_ACTIVITY, WINDOWING_MODE_FULLSCREEN,
                 (actual, displayId, activitySize, displaySize) -> {
             assertThat(activitySize.y, greaterThan(activitySize.x));
             // Since activities must fit within the bounds of the display and they should respect
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
index 459ff76..117a26d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AspectRatioTestsBase.java
@@ -45,9 +45,9 @@
         void assertAspectRatio(float actual, int displayId, Point activitySize, Point displaySize);
     }
 
-    void runAspectRatioTest(final ComponentName componentName,
+    void runAspectRatioTest(final ComponentName componentName, int windowingMode,
             final AssertAspectRatioCallback callback) {
-        launchActivity(componentName);
+        launchActivity(componentName, windowingMode);
         mWmState.computeState();
 
         final int displayId = mWmState.getDisplayByActivity(componentName);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
index 7dd3d2b..8101a41 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
@@ -58,16 +58,12 @@
     }
 
     /**
-     * DisplayContent should have feature id of FEATURE_ROOT. It should be organized.
+     * DisplayContent should have feature id of FEATURE_ROOT.
      */
     @Test
     public void testDisplayContent() {
         for (DisplayContent displayContent : mDisplays) {
             assertThat(displayContent.getFeatureId()).isEqualTo(FEATURE_ROOT);
-            // DisplayAreaOrganizerController registers the organizer for the trusted displays only.
-            if (isTrustedDisplay(displayContent)) {
-                assertThat(displayContent.isOrganized()).isTrue();
-            }
         }
     }
 
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/SetRequestedOrientationRule.java b/tests/framework/base/windowmanager/util/src/android/server/wm/SetRequestedOrientationRule.java
index f882022..be64440 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/SetRequestedOrientationRule.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/SetRequestedOrientationRule.java
@@ -21,6 +21,7 @@
 import android.app.WindowConfiguration;
 import android.content.Intent;
 import android.util.Log;
+import android.util.Pair;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
@@ -30,19 +31,12 @@
 import org.junit.rules.ExternalResource;
 import org.junit.rules.TestRule;
 import org.junit.runner.Description;
-import org.junit.runners.model.MultipleFailureException;
 import org.junit.runners.model.Statement;
 
-import java.util.ArrayDeque;
-import java.util.ArrayList;
-import java.util.Deque;
-
 /**
  * Rule for using setRequestedOrientation API in tests.
  */
 public class SetRequestedOrientationRule implements TestRule {
-    final Deque<AutoCloseable> mAutoCloseables = new ArrayDeque<>();
-
     @Override
     public Statement apply(Statement base,
             Description description) {
@@ -51,44 +45,35 @@
             public void evaluate() throws Throwable {
                 final DisableFixedToUserRotationRule mDisableFixedToUserRotationRule =
                         new DisableFixedToUserRotationRule();
+                mDisableFixedToUserRotationRule.before();
                 try {
-                    mDisableFixedToUserRotationRule.before();
-                    mAutoCloseables.push(mDisableFixedToUserRotationRule::after);
-                    mAutoCloseables.push(
-                            new IgnoreOrientationRequestSession(false /* don' ignore */));
-                    base.evaluate();
-                } finally {
-                    final ArrayList<Throwable> throwables = new ArrayList<>();
-                    while (!mAutoCloseables.isEmpty()) {
-                        try {
-                            mAutoCloseables.pop().close();
-                        } catch (Throwable t) {
-                            throwables.add(t);
-                        }
+                    try (IgnoreOrientationRequestSession session =
+                                 new IgnoreOrientationRequestSession(false /* don' ignore */)) {
+                        base.evaluate();
                     }
-                    MultipleFailureException.assertEmpty(throwables);
+                } finally {
+                    mDisableFixedToUserRotationRule.after();
                 }
             }
         };
     }
 
     /**
-     * Launch an activity in fullscreen.
+     * Builds launch args to launch Activity in fullscreen windowing mode.
      *
      * Activities which request orientation need to be in fullscreen windowing mode.
-     * The activity will be finished at the test end.
      */
-    public <T extends Activity> T launchActivityInFullscreen(Class<T> klass) {
+    public static <T extends Activity> Pair<Intent, ActivityOptions> buildFullScreenLaunchArgs(
+            Class<T> klass) {
         final Intent intent = new Intent(
                 InstrumentationRegistry.getInstrumentation().getTargetContext(),
                 klass);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+
         final ActivityOptions options = ActivityOptions.makeBasic();
         options.setLaunchWindowingMode(WindowConfiguration.WINDOWING_MODE_FULLSCREEN);
-        final T activity = (T) InstrumentationRegistry.getInstrumentation().startActivitySync(
-                intent, options.toBundle());
-        mAutoCloseables.push(activity::finish);
-        return activity;
+
+        return Pair.create(intent, options);
     }
 
     public static class DisableFixedToUserRotationRule extends ExternalResource {
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
index 95eaa02..0fa0307 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/ImeInsetsControllerTest.java
@@ -164,8 +164,8 @@
             CountDownLatch insetsLatch = new CountDownLatch(1);
             InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
                 editText.setOnApplyWindowInsetsListener((v, insets) -> {
-                    insetsLatch.countDown();
                     lastInsets[0] = insets;
+                    insetsLatch.countDown();
                     return CONSUMED;
                 });
                 animController[0].finish(true);
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
index 2e2516a..10d5bda 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/KeyboardVisibilityControlTest.java
@@ -835,7 +835,8 @@
             final ImeEventStream stream = imeSession.openEventStream();
             final String marker = getTestMarker();
             final AtomicReference<EditText> editorRef = new AtomicReference<>();
-            TestActivity.startSync(activity -> {
+            new TestActivity.Starter().withWindowingMode(
+                    WINDOWING_MODE_FULLSCREEN).startSync(activity -> {
                 final LinearLayout layout = new LinearLayout(activity);
                 layout.setOrientation(LinearLayout.VERTICAL);
                 layout.setGravity(Gravity.BOTTOM);
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index b741a2e..bc2a2a8 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -22,6 +22,7 @@
 import static android.app.AppOpsManager.OPSTR_MONITOR_LOCATION;
 import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
 import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
 import static android.location.LocationManager.EXTRA_PROVIDER_NAME;
 import static android.location.LocationManager.FUSED_PROVIDER;
@@ -754,10 +755,12 @@
     }
 
     @Test
+    @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
     public void testRequestLocationUpdates_BatterySaver_GpsDisabledScreenOff() throws Exception {
-        // battery saver is unsupported on auto and tv
+        // battery saver is unsupported on auto, tv and watch
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
         assumeTrue(BatteryUtils.isBatterySaverSupported());
 
         PowerManager powerManager = Objects.requireNonNull(
@@ -816,10 +819,12 @@
     }
 
     @Test
+    @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
     public void testRequestLocationUpdates_BatterySaver_AllDisabledScreenOff() throws Exception {
-        // battery saver is unsupported on auto and tv
+        // battery saver is unsupported on auto, tv and watch
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
         assumeTrue(BatteryUtils.isBatterySaverSupported());
 
         PowerManager powerManager = Objects.requireNonNull(
@@ -859,10 +864,12 @@
     }
 
     @Test
+    @AppModeFull(reason = "Instant apps can't access ACTION_BATTERY_CHANGED intent")
     public void testRequestLocationUpdates_BatterySaver_ThrottleScreenOff() throws Exception {
-        // battery saver is unsupported on auto and tv
+        // battery saver is unsupported on auto, tv and watch
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_AUTOMOTIVE));
         assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION));
+        assumeFalse(mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH));
         assumeTrue(BatteryUtils.isBatterySaverSupported());
 
         PowerManager powerManager = Objects.requireNonNull(
diff --git a/tests/media/common/src/android/mediav2/common/cts/CodecEncoderTestBase.java b/tests/media/common/src/android/mediav2/common/cts/CodecEncoderTestBase.java
index daf4abb..cfff01c 100644
--- a/tests/media/common/src/android/mediav2/common/cts/CodecEncoderTestBase.java
+++ b/tests/media/common/src/android/mediav2/common/cts/CodecEncoderTestBase.java
@@ -16,21 +16,31 @@
 
 package android.mediav2.common.cts;
 
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_FIRST;
+import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_LAST;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.annotation.NonNull;
 import android.graphics.ImageFormat;
+import android.media.AudioFormat;
 import android.media.Image;
 import android.media.MediaCodec;
 import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
+import android.media.MediaMuxer;
 import android.os.PersistableBundle;
 import android.util.Log;
 
 import com.android.compatibility.common.util.Preconditions;
 
+import org.junit.After;
 import org.junit.Before;
 
 import java.io.File;
@@ -38,19 +48,63 @@
 import java.io.IOException;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * Wrapper class for trying and testing encoder components.
- * @deprecated This class is marked for future removal. Use {@link EncoderTestBase} instead.
- * {@link EncoderTestBase} offers same functionality as the current class. Besides that, it has
- * utility functions for muxing, offers better control over configuration params, utility
- * functions for better test labelling.
- * TODO (b/260533828) remove this once all encoders are update to use {@link EncoderConfigParams}
  */
-@Deprecated(forRemoval = true)
 public class CodecEncoderTestBase extends CodecTestBase {
     private static final String LOG_TAG = CodecEncoderTestBase.class.getSimpleName();
 
+    protected final EncoderConfigParams[] mEncCfgParams;
+
+    protected EncoderConfigParams mActiveEncCfg;
+    protected RawResource mActiveRawRes;
+    protected boolean mIsLoopBack;
+    protected int mLoopBackFrameLimit;
+
+    protected byte[] mInputData;
+    protected int mInputBufferReadOffset;
+    protected int mNumBytesSubmitted;
+    protected long mInputOffsetPts;
+
+    protected ArrayList<MediaCodec.BufferInfo> mInfoList = new ArrayList<>();
+
+    protected boolean mMuxOutput;
+    protected String mMuxedOutputFile;
+    protected MediaMuxer mMuxer;
+    protected int mTrackID = -1;
+
+    public CodecEncoderTestBase(String encoder, String mime, EncoderConfigParams[] encCfgParams,
+            String allTestParams) {
+        super(encoder, mime, allTestParams);
+        mEncCfgParams = encCfgParams;
+    }
+
+    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_MP4 = new ArrayList<>(
+            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+                    MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
+                    MediaFormat.MIMETYPE_AUDIO_AAC));
+    static {
+        if (CodecTestBase.IS_AT_LEAST_U) {
+            MEDIATYPE_LIST_FOR_TYPE_MP4.add(MediaFormat.MIMETYPE_VIDEO_AV1);
+        }
+    }
+    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_WEBM =
+            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9,
+                    MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS);
+    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_3GP =
+            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
+                    MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_AUDIO_AAC,
+                    MediaFormat.MIMETYPE_AUDIO_AMR_NB, MediaFormat.MIMETYPE_AUDIO_AMR_WB);
+    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_OGG =
+            Collections.singletonList(MediaFormat.MIMETYPE_AUDIO_OPUS);
+
+    public static final float ACCEPTABLE_WIRELESS_TX_QUALITY = 20.0f;  // psnr in dB
+    public static final float ACCEPTABLE_AV_SYNC_ERROR = 22.0f; // duration in ms
+
     /**
      * Selects encoder input color format in byte buffer mode. As of now ndk tests support only
      * 420p, 420sp. COLOR_FormatYUV420Flexible although can represent any form of yuv, it doesn't
@@ -72,50 +126,90 @@
         return colorFormat;
     }
 
-    protected final int[] mBitrates;
-    protected final int[] mEncParamList1;
-    protected final int[] mEncParamList2;
-
-    protected RawResource mActiveRawRes;
-    protected byte[] mInputData;
-    protected int mInputBufferReadOffset;
-    protected int mNumBytesSubmitted;
-    protected long mInputOffsetPts;
-
-    protected ArrayList<MediaFormat> mFormats;
-    protected ArrayList<MediaCodec.BufferInfo> mInfoList;
-
-    protected int mWidth, mHeight;
-    protected int mBytesPerSample;
-    protected int mFrameRate;
-    protected int mMaxBFrames;
-    protected int mChannels;
-    protected int mSampleRate;
-    protected int mLoopBackFrameLimit;
-    protected boolean mIsLoopBack;
-
-    public CodecEncoderTestBase(String encoder, String mime, int[] bitrates, int[] encoderInfo1,
-            int[] encoderInfo2, RawResource rawResource, String allTestParams) {
-        super(encoder, mime, allTestParams);
-        mBitrates = bitrates;
-        mEncParamList1 = encoderInfo1;
-        mEncParamList2 = encoderInfo2;
-        mFormats = new ArrayList<>();
-        mInfoList = new ArrayList<>();
-        mWidth = 0;
-        mHeight = 0;
-        if (mime.equals(MediaFormat.MIMETYPE_VIDEO_MPEG4)) {
-            mFrameRate = 12;
-        } else if (mime.equals(MediaFormat.MIMETYPE_VIDEO_H263)) {
-            mFrameRate = 12;
-        } else {
-            mFrameRate = 30;
+    public static void muxOutput(String filePath, int muxerFormat, MediaFormat format,
+            ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> infos) throws IOException {
+        MediaMuxer muxer = null;
+        try {
+            muxer = new MediaMuxer(filePath, muxerFormat);
+            int trackID = muxer.addTrack(format);
+            muxer.start();
+            for (MediaCodec.BufferInfo info : infos) {
+                muxer.writeSampleData(trackID, buffer, info);
+            }
+            muxer.stop();
+        } finally {
+            if (muxer != null) muxer.release();
         }
-        mMaxBFrames = 0;
-        mChannels = 0;
-        mSampleRate = 0;
-        mActiveRawRes = rawResource;
-        mBytesPerSample = mActiveRawRes.mBytesPerSample;
+    }
+
+    public static boolean isMediaTypeContainerPairValid(String mime, int format) {
+        boolean result = false;
+        if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) {
+            result = MEDIATYPE_LIST_FOR_TYPE_MP4.contains(mime) || mime.startsWith("application/");
+        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM) {
+            result = MEDIATYPE_LIST_FOR_TYPE_WEBM.contains(mime);
+        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) {
+            result = MEDIATYPE_LIST_FOR_TYPE_3GP.contains(mime);
+        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG) {
+            result = MEDIATYPE_LIST_FOR_TYPE_OGG.contains(mime);
+        }
+        return result;
+    }
+
+    public static int getMuxerFormatForMediaType(String mediaType) {
+        for (int muxFormat = MUXER_OUTPUT_FIRST; muxFormat <= MUXER_OUTPUT_LAST; muxFormat++) {
+            if (isMediaTypeContainerPairValid(mediaType, muxFormat)) {
+                return muxFormat;
+            }
+        }
+        fail("no configured muxer support for " + mediaType);
+        return MUXER_OUTPUT_LAST;
+    }
+
+    public static String getTempFilePath(String infix) throws IOException {
+        return File.createTempFile("tmp" + infix, ".bin").getAbsolutePath();
+    }
+
+    public static void validateEncodedPSNR(String inpMediaType, String inpFile,
+            String outMediaType, String outFile, boolean allowInpResize, boolean allowInpLoopBack,
+            double perFramePsnrThreshold)
+            throws IOException, InterruptedException {
+        CompareStreams cs = new CompareStreams(inpMediaType, inpFile, outMediaType, outFile,
+                allowInpResize, allowInpLoopBack);
+        validateEncodedPSNR(cs, perFramePsnrThreshold);
+        cs.cleanUp();
+    }
+
+    public static void validateEncodedPSNR(RawResource inp, String outMediaType, String outFile,
+            boolean allowInpResize, boolean allowInpLoopBack, double perFramePsnrThreshold)
+            throws IOException, InterruptedException {
+        CompareStreams cs = new CompareStreams(inp, outMediaType, outFile, allowInpResize,
+                allowInpLoopBack);
+        validateEncodedPSNR(cs, perFramePsnrThreshold);
+        cs.cleanUp();
+    }
+
+    public static void validateEncodedPSNR(@NonNull CompareStreams cs,
+            double perFramePsnrThreshold) throws IOException {
+        ArrayList<double[]> framesPSNR = cs.getFramesPSNR();
+        StringBuilder msg = new StringBuilder();
+        boolean isOk = true;
+        for (int j = 0; j < framesPSNR.size(); j++) {
+            double[] framePSNR = framesPSNR.get(j);
+            // https://www.itu.int/wftp3/av-arch/jctvc-site/2011_01_D_Daegu/JCTVC-D500.doc
+            // weighted psnr (6 * psnrY + psnrU + psnrV) / 8;
+            double weightPSNR = (6 * framePSNR[0] + framePSNR[1] + framePSNR[2]) / 8;
+            if (weightPSNR < perFramePsnrThreshold) {
+                msg.append(String.format(
+                        "Frame %d - PSNR Y: %f, PSNR U: %f, PSNR V: %f, Weighted PSNR: %f < "
+                                + "Threshold %f \n",
+                        j, framePSNR[0], framePSNR[1], framePSNR[2], weightPSNR,
+                        perFramePsnrThreshold));
+                isOk = false;
+            }
+        }
+        assertTrue("Encountered frames with PSNR less than configured threshold "
+                + perFramePsnrThreshold + "dB \n" + msg, isOk);
     }
 
     public static String bitRateModeToString(int mode) {
@@ -133,22 +227,96 @@
         }
     }
 
+    public static String rangeToString(int range) {
+        switch (range) {
+            case UNSPECIFIED:
+                return "unspecified";
+            case MediaFormat.COLOR_RANGE_FULL:
+                return "full";
+            case MediaFormat.COLOR_RANGE_LIMITED:
+                return "limited";
+            default:
+                return "unknown";
+        }
+    }
+
+    public static String colorStandardToString(int standard) {
+        switch (standard) {
+            case UNSPECIFIED:
+                return "unspecified";
+            case MediaFormat.COLOR_STANDARD_BT709:
+                return "bt709";
+            case MediaFormat.COLOR_STANDARD_BT601_PAL:
+                return "bt601pal";
+            case MediaFormat.COLOR_STANDARD_BT601_NTSC:
+                return "bt601ntsc";
+            case MediaFormat.COLOR_STANDARD_BT2020:
+                return "bt2020";
+            default:
+                return "unknown";
+        }
+    }
+
+    public static String colorTransferToString(int transfer) {
+        switch (transfer) {
+            case UNSPECIFIED:
+                return "unspecified";
+            case MediaFormat.COLOR_TRANSFER_LINEAR:
+                return "linear";
+            case MediaFormat.COLOR_TRANSFER_SDR_VIDEO:
+                return "sdr";
+            case MediaFormat.COLOR_TRANSFER_HLG:
+                return "hlg";
+            case MediaFormat.COLOR_TRANSFER_ST2084:
+                return "st2084";
+            default:
+                return "unknown";
+        }
+    }
+
+    public static String colorFormatToString(int colorFormat, int bitDepth) {
+        switch (colorFormat) {
+            case COLOR_FormatYUV420Flexible:
+                return "yuv420flexible";
+            case COLOR_FormatYUVP010:
+                return "yuvp010";
+            case COLOR_FormatSurface:
+                if (bitDepth == 8) {
+                    return "surfacergb888";
+                } else if (bitDepth == 10) {
+                    return "surfaceabgr2101010";
+                } else {
+                    return "unknown";
+                }
+            default:
+                return "unknown";
+        }
+    }
+
+    public static String audioEncodingToString(int enc) {
+        switch (enc) {
+            case AudioFormat.ENCODING_INVALID:
+                return "invalid";
+            case AudioFormat.ENCODING_PCM_16BIT:
+                return "pcm16";
+            case AudioFormat.ENCODING_PCM_FLOAT:
+                return "pcmfloat";
+            default:
+                return "unknown";
+        }
+    }
+
     @Before
     public void setUpCodecEncoderTestBase() {
         assertTrue("Testing a mime that is neither audio nor video is not supported \n"
                 + mTestConfig, mIsAudio || mIsVideo);
     }
 
-    @Override
-    protected void configureCodec(MediaFormat format, boolean isAsync,
-            boolean signalEOSWithLastFrame, boolean isEncoder) {
-        super.configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
-        if (mIsAudio) {
-            mSampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
-            mChannels = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
-        } else {
-            mWidth = format.getInteger(MediaFormat.KEY_WIDTH);
-            mHeight = format.getInteger(MediaFormat.KEY_HEIGHT);
+    @After
+    public void tearDown() {
+        if (mMuxer != null) {
+            mMuxer.release();
+            mMuxer = null;
         }
     }
 
@@ -158,6 +326,7 @@
         mInputBufferReadOffset = 0;
         mNumBytesSubmitted = 0;
         mInputOffsetPts = 0;
+        mInfoList.clear();
     }
 
     protected void setUpSource(String inpPath) throws IOException {
@@ -175,7 +344,7 @@
                 format == ImageFormat.YUV_420_888 || format == ImageFormat.YCBCR_P010);
         int bytesPerSample = (ImageFormat.getBitsPerPixel(format) * 2) / (8 * 3);  // YUV420
         assertEquals("Invalid bytes per sample \n" + mTestConfig + mTestEnv, bytesPerSample,
-                mBytesPerSample);
+                mActiveRawRes.mBytesPerSample);
 
         int imageWidth = image.getWidth();
         int imageHeight = image.getHeight();
@@ -237,13 +406,13 @@
     void fillByteBuffer(ByteBuffer inputBuffer) {
         int offset = 0, frmOffset = mInputBufferReadOffset;
         for (int plane = 0; plane < 3; plane++) {
-            int width = mWidth;
-            int height = mHeight;
+            int width = mActiveEncCfg.mWidth;
+            int height = mActiveEncCfg.mHeight;
             int tileWidth = mActiveRawRes.mWidth;
             int tileHeight = mActiveRawRes.mHeight;
             if (plane != 0) {
-                width = mWidth / 2;
-                height = mHeight / 2;
+                width = mActiveEncCfg.mWidth / 2;
+                height = mActiveEncCfg.mHeight / 2;
                 tileWidth = mActiveRawRes.mWidth / 2;
                 tileHeight = mActiveRawRes.mHeight / 2;
             }
@@ -253,14 +422,16 @@
                     for (int i = 0; i < width; i += tileWidth) {
                         int colsToCopy = Math.min(width - i, tileWidth);
                         inputBuffer.position(
-                                offset + (k + j) * width * mBytesPerSample + i * mBytesPerSample);
-                        inputBuffer.put(mInputData, frmOffset + j * tileWidth * mBytesPerSample,
-                                colsToCopy * mBytesPerSample);
+                                offset + (k + j) * width * mActiveRawRes.mBytesPerSample
+                                        + i * mActiveRawRes.mBytesPerSample);
+                        inputBuffer.put(mInputData,
+                                frmOffset + j * tileWidth * mActiveRawRes.mBytesPerSample,
+                                colsToCopy * mActiveRawRes.mBytesPerSample);
                     }
                 }
             }
-            offset += width * height * mBytesPerSample;
-            frmOffset += tileWidth * tileHeight * mBytesPerSample;
+            offset += width * height * mActiveRawRes.mBytesPerSample;
+            frmOffset += tileWidth * tileHeight * mActiveRawRes.mBytesPerSample;
         }
     }
 
@@ -276,10 +447,11 @@
             int flags = 0;
             long pts = mInputOffsetPts;
             if (mIsAudio) {
-                pts += mNumBytesSubmitted * 1000000L / ((long) mBytesPerSample * mChannels
-                        * mSampleRate);
+                pts += mNumBytesSubmitted * 1000000L / ((long) mActiveRawRes.mBytesPerSample
+                        * mActiveEncCfg.mChannelCount * mActiveEncCfg.mSampleRate);
                 size = Math.min(inputBuffer.capacity(), mInputData.length - mInputBufferReadOffset);
-                assertEquals(0, size % ((long) mBytesPerSample * mChannels));
+                assertEquals(0, size % ((long) mActiveRawRes.mBytesPerSample
+                        * mActiveEncCfg.mChannelCount));
                 inputBuffer.put(mInputData, mInputBufferReadOffset, size);
                 if (mSignalEOSWithLastFrame) {
                     if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
@@ -290,8 +462,9 @@
                 }
                 mInputBufferReadOffset += size;
             } else {
-                pts += mInputCount * 1000000L / mFrameRate;
-                size = mBytesPerSample * mWidth * mHeight * 3 / 2;
+                pts += mInputCount * 1000000L / mActiveEncCfg.mFrameRate;
+                size = mActiveRawRes.mBytesPerSample * mActiveEncCfg.mWidth * mActiveEncCfg.mHeight
+                        * 3 / 2;
                 int frmSize = mActiveRawRes.mBytesPerSample * mActiveRawRes.mWidth
                         * mActiveRawRes.mHeight * 3 / 2;
                 if (mInputBufferReadOffset + frmSize > mInputData.length) {
@@ -331,19 +504,26 @@
             mSawOutputEOS = true;
         }
         if (info.size > 0) {
+            ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
             if (mSaveToMem) {
                 MediaCodec.BufferInfo copy = new MediaCodec.BufferInfo();
                 copy.set(mOutputBuff.getOutStreamSize(), info.size, info.presentationTimeUs,
                         info.flags);
                 mInfoList.add(copy);
 
-                ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
                 mOutputBuff.saveToMemory(buf, info);
             }
             if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
                 mOutputBuff.saveOutPTS(info.presentationTimeUs);
                 mOutputCount++;
             }
+            if (mMuxer != null) {
+                if (mTrackID == -1) {
+                    mTrackID = mMuxer.addTrack(mCodec.getOutputFormat());
+                    mMuxer.start();
+                }
+                mMuxer.writeSampleData(mTrackID, buf, info);
+            }
         }
         mCodec.releaseOutputBuffer(bufferIndex, false);
     }
@@ -351,10 +531,30 @@
     @Override
     protected void doWork(int frameLimit) throws IOException, InterruptedException {
         mLoopBackFrameLimit = frameLimit;
+        if (mMuxOutput) {
+            int muxerFormat = getMuxerFormatForMediaType(mMime);
+            mMuxedOutputFile = getTempFilePath((mActiveEncCfg.mInputBitDepth == 10) ? "10bit" : "");
+            mMuxer = new MediaMuxer(mMuxedOutputFile, muxerFormat);
+        }
         super.doWork(frameLimit);
     }
 
     @Override
+    public void waitForAllOutputs() throws InterruptedException {
+        super.waitForAllOutputs();
+        if (mMuxOutput) {
+            if (mTrackID != -1) {
+                mMuxer.stop();
+                mTrackID = -1;
+            }
+            if (mMuxer != null) {
+                mMuxer.release();
+                mMuxer = null;
+            }
+        }
+    }
+
+    @Override
     protected PersistableBundle validateMetrics(String codec, MediaFormat format) {
         PersistableBundle metrics = super.validateMetrics(codec, format);
         assertEquals("error! metrics#MetricsConstants.MIME_TYPE is not as expected \n" + mTestConfig
@@ -364,74 +564,39 @@
         return metrics;
     }
 
-    protected void setUpParams(int limit) {
-        int count = 0;
-        for (int bitrate : mBitrates) {
-            if (mIsAudio) {
-                for (int rate : mEncParamList1) {
-                    for (int channels : mEncParamList2) {
-                        MediaFormat format = new MediaFormat();
-                        format.setString(MediaFormat.KEY_MIME, mMime);
-                        if (mMime.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
-                            format.setInteger(MediaFormat.KEY_FLAC_COMPRESSION_LEVEL, bitrate);
-                        } else {
-                            format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-                        }
-                        format.setInteger(MediaFormat.KEY_SAMPLE_RATE, rate);
-                        format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, channels);
-                        mFormats.add(format);
-                        count++;
-                        if (count >= limit) return;
-                    }
-                }
-            } else {
-                assertEquals("Wrong number of height, width parameters \n" + mTestConfig + mTestEnv,
-                        mEncParamList1.length, mEncParamList2.length);
-                for (int i = 0; i < mEncParamList1.length; i++) {
-                    MediaFormat format = new MediaFormat();
-                    format.setString(MediaFormat.KEY_MIME, mMime);
-                    format.setInteger(MediaFormat.KEY_BIT_RATE, bitrate);
-                    format.setInteger(MediaFormat.KEY_WIDTH, mEncParamList1[i]);
-                    format.setInteger(MediaFormat.KEY_HEIGHT, mEncParamList2[i]);
-                    format.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
-                    format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, mMaxBFrames);
-                    format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
-                    format.setInteger(MediaFormat.KEY_COLOR_FORMAT,
-                            MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible);
-                    mFormats.add(format);
-                    count++;
-                    if (count >= limit) return;
-                }
-            }
-        }
-    }
-
-    public void encodeToMemory(String file, String encoder, int frameLimit, MediaFormat format,
-            boolean saveToMem) throws IOException, InterruptedException {
+    public void encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res,
+            int frameLimit, boolean saveToMem, boolean muxOutput)
+            throws IOException, InterruptedException {
         mSaveToMem = saveToMem;
+        mMuxOutput = muxOutput;
         mOutputBuff = new OutputManager();
         mInfoList.clear();
+        mActiveEncCfg = cfg;
+        mActiveRawRes = res;
         mCodec = MediaCodec.createByCodecName(encoder);
-        setUpSource(file);
-        configureCodec(format, false, true, true);
+        setUpSource(mActiveRawRes.mFileName);
+        configureCodec(mActiveEncCfg.getFormat(), false, true, true);
         mCodec.start();
         doWork(frameLimit);
         queueEOS();
         waitForAllOutputs();
         mCodec.stop();
         mCodec.release();
+        mActiveRawRes = null;
+        mActiveEncCfg = null;
         mSaveToMem = false;
+        mMuxOutput = false;
     }
 
     void validateTestState() {
         super.validateTestState();
-        if ((mIsAudio || (mIsVideo && mMaxBFrames == 0))
+        if ((mIsAudio || (mIsVideo && mActiveEncCfg.mMaxBFrames == 0))
                 && !mOutputBuff.isPtsStrictlyIncreasing(mPrevOutputPts)) {
             fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv
                     + mOutputBuff.getErrMsg());
         }
         if (mIsVideo) {
-            if (!mOutputBuff.isOutPtsListIdenticalToInpPtsList((mMaxBFrames != 0))) {
+            if (!mOutputBuff.isOutPtsListIdenticalToInpPtsList((mActiveEncCfg.mMaxBFrames != 0))) {
                 fail("Input pts list and Output pts list are not identical \n" + mTestConfig
                         + mTestEnv + mOutputBuff.getErrMsg());
             }
diff --git a/tests/media/common/src/android/mediav2/common/cts/CodecTestBase.java b/tests/media/common/src/android/mediav2/common/cts/CodecTestBase.java
index a775ca4..08a958f 100644
--- a/tests/media/common/src/android/mediav2/common/cts/CodecTestBase.java
+++ b/tests/media/common/src/android/mediav2/common/cts/CodecTestBase.java
@@ -108,6 +108,7 @@
     //TODO(b/248315681) Remove codenameEquals() check once devices return correct version for U
     public static final boolean IS_AT_LEAST_U = ApiLevelUtil.isAfter(Build.VERSION_CODES.TIRAMISU)
             || ApiLevelUtil.codenameEquals("UpsideDownCake");
+    public static final boolean IS_BEFORE_U = !IS_AT_LEAST_U;
     public static final boolean FIRST_SDK_IS_AT_LEAST_T =
             ApiLevelUtil.isFirstApiAtLeast(Build.VERSION_CODES.TIRAMISU);
     public static final boolean VNDK_IS_AT_LEAST_T =
@@ -274,8 +275,8 @@
     // SurfaceView or TextureView, ... They hold the responsibility of calling release().
     protected CodecTestActivity mActivity;
 
-    private static final MediaCodecList MEDIA_CODEC_LIST_ALL;
-    private static final MediaCodecList MEDIA_CODEC_LIST_REGULAR;
+    public static final MediaCodecList MEDIA_CODEC_LIST_ALL;
+    public static final MediaCodecList MEDIA_CODEC_LIST_REGULAR;
     static {
         MEDIA_CODEC_LIST_ALL = new MediaCodecList(MediaCodecList.ALL_CODECS);
         MEDIA_CODEC_LIST_REGULAR = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -581,7 +582,7 @@
         return false;
     }
 
-    private static String paramToString(Object[] param) {
+    protected static String paramToString(Object[] param) {
         StringBuilder paramStr = new StringBuilder("[  ");
         for (int j = 0; j < param.length - 1; j++) {
             Object o = param[j];
diff --git a/tests/media/common/src/android/mediav2/common/cts/EncoderConfigParams.java b/tests/media/common/src/android/mediav2/common/cts/EncoderConfigParams.java
index b549644..8cac99b 100644
--- a/tests/media/common/src/android/mediav2/common/cts/EncoderConfigParams.java
+++ b/tests/media/common/src/android/mediav2/common/cts/EncoderConfigParams.java
@@ -18,6 +18,8 @@
 
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar;
+import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
 
 import android.media.AudioFormat;
@@ -29,6 +31,8 @@
  * Class to hold encoder configuration settings.
  */
 public class EncoderConfigParams {
+    public static final String TOKEN_SEPARATOR = "<>";
+
     public final boolean mIsAudio;
     public final String mMediaType;
 
@@ -141,7 +145,9 @@
             mLevel = cfg.mLevel;
             if (cfg.mColorFormat != COLOR_FormatYUV420Flexible
                     && cfg.mColorFormat != COLOR_FormatYUVP010
-                    && cfg.mColorFormat != COLOR_FormatSurface) {
+                    && cfg.mColorFormat != COLOR_FormatSurface
+                    && cfg.mColorFormat != COLOR_FormatYUV420SemiPlanar
+                    && cfg.mColorFormat != COLOR_FormatYUV420Planar) {
                 throw new IllegalArgumentException("bad color format config for video component");
             }
             mColorFormat = cfg.mColorFormat;
@@ -149,6 +155,14 @@
                 if (cfg.mColorFormat == COLOR_FormatYUV420Flexible && cfg.mInputBitDepth != 8) {
                     throw new IllegalArgumentException(
                             "bad bit depth configuration for COLOR_FormatYUV420Flexible");
+                } else if (cfg.mColorFormat == COLOR_FormatYUV420SemiPlanar
+                        && cfg.mInputBitDepth != 8) {
+                    throw new IllegalArgumentException(
+                            "bad bit depth configuration for COLOR_FormatYUV420SemiPlanar");
+                } else if (cfg.mColorFormat == COLOR_FormatYUV420Planar
+                        && cfg.mInputBitDepth != 8) {
+                    throw new IllegalArgumentException(
+                            "bad bit depth configuration for COLOR_FormatYUV420Planar");
                 } else if (cfg.mColorFormat == COLOR_FormatYUVP010 && cfg.mInputBitDepth != 10) {
                     throw new IllegalArgumentException(
                             "bad bit depth configuration for COLOR_FormatYUVP010");
@@ -216,6 +230,30 @@
         return new MediaFormat(mFormat);
     }
 
+    /**
+     * Converts MediaFormat object to a string. All Keys, ValueTypes, Values are concatenated with
+     * a separator and sent for further usage.
+     */
+    public static String serializeMediaFormat(MediaFormat format) {
+        StringBuilder msg = new StringBuilder();
+        java.util.Set<String> keys = format.getKeys();
+        for (String key : keys) {
+            int valueTypeForKey = format.getValueTypeForKey(key);
+            msg.append(key).append(TOKEN_SEPARATOR);
+            msg.append(valueTypeForKey).append(TOKEN_SEPARATOR);
+            if (valueTypeForKey == MediaFormat.TYPE_INTEGER) {
+                msg.append(format.getInteger(key)).append(TOKEN_SEPARATOR);
+            } else if (valueTypeForKey == MediaFormat.TYPE_FLOAT) {
+                msg.append(format.getFloat(key)).append(TOKEN_SEPARATOR);
+            } else if (valueTypeForKey == MediaFormat.TYPE_STRING) {
+                msg.append(format.getString(key)).append(TOKEN_SEPARATOR);
+            } else {
+                throw new RuntimeException("unrecognized Type for Key: " + key);
+            }
+        }
+        return msg.toString();
+    }
+
     @NonNull
     @Override
     public String toString() {
diff --git a/tests/media/common/src/android/mediav2/common/cts/EncoderTestBase.java b/tests/media/common/src/android/mediav2/common/cts/EncoderTestBase.java
deleted file mode 100644
index 4941e39..0000000
--- a/tests/media/common/src/android/mediav2/common/cts/EncoderTestBase.java
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * 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.mediav2.common.cts;
-
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
-import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
-import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_FIRST;
-import static android.media.MediaMuxer.OutputFormat.MUXER_OUTPUT_LAST;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
-
-import android.graphics.ImageFormat;
-import android.media.AudioFormat;
-import android.media.Image;
-import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
-import android.media.MediaFormat;
-import android.media.MediaMuxer;
-import android.os.PersistableBundle;
-import android.util.Log;
-
-import com.android.compatibility.common.util.Preconditions;
-
-import org.junit.After;
-import org.junit.Before;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.nio.ByteBuffer;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Wrapper class for trying and testing encoder components.
- */
-public class EncoderTestBase extends CodecTestBase {
-    private static final String LOG_TAG = EncoderTestBase.class.getSimpleName();
-
-    protected final EncoderConfigParams[] mEncCfgParams;
-
-    protected EncoderConfigParams mActiveEncCfg;
-    protected RawResource mActiveRawRes;
-    protected boolean mIsLoopBack;
-    protected int mLoopBackFrameLimit;
-
-    protected byte[] mInputData;
-    protected int mInputBufferReadOffset;
-    protected int mNumBytesSubmitted;
-    protected long mInputOffsetPts;
-
-    protected ArrayList<MediaCodec.BufferInfo> mInfoList = new ArrayList<>();
-
-    protected boolean mMuxOutput;
-    protected String mMuxedOutputFile;
-    protected MediaMuxer mMuxer;
-    protected int mTrackID = -1;
-
-    public EncoderTestBase(String encoder, String mime, EncoderConfigParams[] encCfgParams,
-            String allTestParams) {
-        super(encoder, mime, allTestParams);
-        mEncCfgParams = encCfgParams;
-    }
-
-    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_MP4 =
-            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
-                    MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_VIDEO_HEVC,
-                    MediaFormat.MIMETYPE_AUDIO_AAC);
-    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_WEBM =
-            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_VP8, MediaFormat.MIMETYPE_VIDEO_VP9,
-                    MediaFormat.MIMETYPE_AUDIO_VORBIS, MediaFormat.MIMETYPE_AUDIO_OPUS);
-    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_3GP =
-            Arrays.asList(MediaFormat.MIMETYPE_VIDEO_MPEG4, MediaFormat.MIMETYPE_VIDEO_H263,
-                    MediaFormat.MIMETYPE_VIDEO_AVC, MediaFormat.MIMETYPE_AUDIO_AAC,
-                    MediaFormat.MIMETYPE_AUDIO_AMR_NB, MediaFormat.MIMETYPE_AUDIO_AMR_WB);
-    private static final List<String> MEDIATYPE_LIST_FOR_TYPE_OGG =
-            Collections.singletonList(MediaFormat.MIMETYPE_AUDIO_OPUS);
-
-    public static final float ACCEPTABLE_WIRELESS_TX_QUALITY = 20.0f;  // psnr in dB
-    public static final float ACCEPTABLE_AV_SYNC_ERROR = 22.0f; // duration in ms
-
-    /**
-     * Selects encoder input color format in byte buffer mode. As of now ndk tests support only
-     * 420p, 420sp. COLOR_FormatYUV420Flexible although can represent any form of yuv, it doesn't
-     * work in ndk due to lack of AMediaCodec_GetInputImage()
-     */
-    public static int findByteBufferColorFormat(String encoder, String mime) throws IOException {
-        MediaCodec codec = MediaCodec.createByCodecName(encoder);
-        MediaCodecInfo.CodecCapabilities cap = codec.getCodecInfo().getCapabilitiesForType(mime);
-        int colorFormat = -1;
-        for (int c : cap.colorFormats) {
-            if (c == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar
-                    || c == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) {
-                Log.v(LOG_TAG, "selecting color format: " + c);
-                colorFormat = c;
-                break;
-            }
-        }
-        codec.release();
-        return colorFormat;
-    }
-
-    public static void muxOutput(String filePath, int muxerFormat, MediaFormat format,
-            ByteBuffer buffer, ArrayList<MediaCodec.BufferInfo> infos) throws IOException {
-        MediaMuxer muxer = null;
-        try {
-            muxer = new MediaMuxer(filePath, muxerFormat);
-            int trackID = muxer.addTrack(format);
-            muxer.start();
-            for (MediaCodec.BufferInfo info : infos) {
-                muxer.writeSampleData(trackID, buffer, info);
-            }
-            muxer.stop();
-        } finally {
-            if (muxer != null) muxer.release();
-        }
-    }
-
-    public static boolean isMediaTypeContainerPairValid(String mime, int format) {
-        boolean result = false;
-        if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4) {
-            result = MEDIATYPE_LIST_FOR_TYPE_MP4.contains(mime) || mime.startsWith("application/");
-        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM) {
-            result = MEDIATYPE_LIST_FOR_TYPE_WEBM.contains(mime);
-        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_3GPP) {
-            result = MEDIATYPE_LIST_FOR_TYPE_3GP.contains(mime);
-        } else if (format == MediaMuxer.OutputFormat.MUXER_OUTPUT_OGG) {
-            result = MEDIATYPE_LIST_FOR_TYPE_OGG.contains(mime);
-        }
-        return result;
-    }
-
-    public static int getMuxerFormatForMediaType(String mediaType) {
-        for (int muxFormat = MUXER_OUTPUT_FIRST; muxFormat <= MUXER_OUTPUT_LAST; muxFormat++) {
-            if (isMediaTypeContainerPairValid(mediaType, muxFormat)) {
-                return muxFormat;
-            }
-        }
-        fail("no configured muxer support for " + mediaType);
-        return MUXER_OUTPUT_LAST;
-    }
-
-    public static String getTempFilePath(String infix) throws IOException {
-        return File.createTempFile("tmp" + infix, ".bin").getAbsolutePath();
-    }
-
-    public static String bitRateModeToString(int mode) {
-        switch (mode) {
-            case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR:
-                return "cbr";
-            case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR:
-                return "vbr";
-            case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CQ:
-                return "cq";
-            case MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR_FD:
-                return "cbrwithfd";
-            default:
-                return "unknown";
-        }
-    }
-
-    public static String rangeToString(int range) {
-        switch (range) {
-            case UNSPECIFIED:
-                return "unspecified";
-            case MediaFormat.COLOR_RANGE_FULL:
-                return "full";
-            case MediaFormat.COLOR_RANGE_LIMITED:
-                return "limited";
-            default:
-                return "unknown";
-        }
-    }
-
-    public static String colorStandardToString(int standard) {
-        switch (standard) {
-            case UNSPECIFIED:
-                return "unspecified";
-            case MediaFormat.COLOR_STANDARD_BT709:
-                return "bt709";
-            case MediaFormat.COLOR_STANDARD_BT601_PAL:
-                return "bt601pal";
-            case MediaFormat.COLOR_STANDARD_BT601_NTSC:
-                return "bt601ntsc";
-            case MediaFormat.COLOR_STANDARD_BT2020:
-                return "bt2020";
-            default:
-                return "unknown";
-        }
-    }
-
-    public static String colorTransferToString(int transfer) {
-        switch (transfer) {
-            case UNSPECIFIED:
-                return "unspecified";
-            case MediaFormat.COLOR_TRANSFER_LINEAR:
-                return "linear";
-            case MediaFormat.COLOR_TRANSFER_SDR_VIDEO:
-                return "sdr";
-            case MediaFormat.COLOR_TRANSFER_HLG:
-                return "hlg";
-            case MediaFormat.COLOR_TRANSFER_ST2084:
-                return "st2084";
-            default:
-                return "unknown";
-        }
-    }
-
-    public static String colorFormatToString(int colorFormat, int bitDepth) {
-        switch (colorFormat) {
-            case COLOR_FormatYUV420Flexible:
-                return "yuv420flexible";
-            case COLOR_FormatYUVP010:
-                return "yuvp010";
-            case COLOR_FormatSurface:
-                if (bitDepth == 8) {
-                    return "surfacergb888";
-                } else if (bitDepth == 10) {
-                    return "surfaceabgr2101010";
-                } else {
-                    return "unknown";
-                }
-            default:
-                return "unknown";
-        }
-    }
-
-    public static String audioEncodingToString(int enc) {
-        switch (enc) {
-            case AudioFormat.ENCODING_INVALID:
-                return "invalid";
-            case AudioFormat.ENCODING_PCM_16BIT:
-                return "pcm16";
-            case AudioFormat.ENCODING_PCM_FLOAT:
-                return "pcmfloat";
-            default:
-                return "unknown";
-        }
-    }
-
-    @Before
-    public void setUpCodecEncoderTestBase() {
-        assertTrue("Testing a mime that is neither audio nor video is not supported \n"
-                + mTestConfig, mIsAudio || mIsVideo);
-    }
-
-    @After
-    public void tearDown() {
-        if (mMuxer != null) {
-            mMuxer.release();
-            mMuxer = null;
-        }
-    }
-
-    @Override
-    protected void resetContext(boolean isAsync, boolean signalEOSWithLastFrame) {
-        super.resetContext(isAsync, signalEOSWithLastFrame);
-        mInputBufferReadOffset = 0;
-        mNumBytesSubmitted = 0;
-        mInputOffsetPts = 0;
-        mInfoList.clear();
-    }
-
-    protected void setUpSource(String inpPath) throws IOException {
-        Preconditions.assertTestFileExists(inpPath);
-        try (FileInputStream fInp = new FileInputStream(inpPath)) {
-            int size = (int) new File(inpPath).length();
-            mInputData = new byte[size];
-            fInp.read(mInputData, 0, size);
-        }
-    }
-
-    protected void fillImage(Image image) {
-        int format = image.getFormat();
-        assertTrue("unexpected image format \n" + mTestConfig + mTestEnv,
-                format == ImageFormat.YUV_420_888 || format == ImageFormat.YCBCR_P010);
-        int bytesPerSample = (ImageFormat.getBitsPerPixel(format) * 2) / (8 * 3);  // YUV420
-        assertEquals("Invalid bytes per sample \n" + mTestConfig + mTestEnv, bytesPerSample,
-                mActiveRawRes.mBytesPerSample);
-
-        int imageWidth = image.getWidth();
-        int imageHeight = image.getHeight();
-        Image.Plane[] planes = image.getPlanes();
-        int offset = mInputBufferReadOffset;
-        for (int i = 0; i < planes.length; ++i) {
-            ByteBuffer buf = planes[i].getBuffer();
-            int width = imageWidth;
-            int height = imageHeight;
-            int tileWidth = mActiveRawRes.mWidth;
-            int tileHeight = mActiveRawRes.mHeight;
-            int rowStride = planes[i].getRowStride();
-            int pixelStride = planes[i].getPixelStride();
-            if (i != 0) {
-                width = imageWidth / 2;
-                height = imageHeight / 2;
-                tileWidth = mActiveRawRes.mWidth / 2;
-                tileHeight = mActiveRawRes.mHeight / 2;
-            }
-            if (pixelStride == bytesPerSample) {
-                if (width == rowStride && width == tileWidth && height == tileHeight) {
-                    buf.put(mInputData, offset, width * height * bytesPerSample);
-                } else {
-                    for (int z = 0; z < height; z += tileHeight) {
-                        int rowsToCopy = Math.min(height - z, tileHeight);
-                        for (int y = 0; y < rowsToCopy; y++) {
-                            for (int x = 0; x < width; x += tileWidth) {
-                                int colsToCopy = Math.min(width - x, tileWidth);
-                                buf.position((z + y) * rowStride + x * bytesPerSample);
-                                buf.put(mInputData, offset + y * tileWidth * bytesPerSample,
-                                        colsToCopy * bytesPerSample);
-                            }
-                        }
-                    }
-                }
-            } else {
-                // do it pixel-by-pixel
-                for (int z = 0; z < height; z += tileHeight) {
-                    int rowsToCopy = Math.min(height - z, tileHeight);
-                    for (int y = 0; y < rowsToCopy; y++) {
-                        int lineOffset = (z + y) * rowStride;
-                        for (int x = 0; x < width; x += tileWidth) {
-                            int colsToCopy = Math.min(width - x, tileWidth);
-                            for (int w = 0; w < colsToCopy; w++) {
-                                for (int bytePos = 0; bytePos < bytesPerSample; bytePos++) {
-                                    buf.position(lineOffset + (x + w) * pixelStride + bytePos);
-                                    buf.put(mInputData[offset + y * tileWidth * bytesPerSample
-                                            + w * bytesPerSample + bytePos]);
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            offset += tileWidth * tileHeight * bytesPerSample;
-        }
-    }
-
-    void fillByteBuffer(ByteBuffer inputBuffer) {
-        int offset = 0, frmOffset = mInputBufferReadOffset;
-        for (int plane = 0; plane < 3; plane++) {
-            int width = mActiveEncCfg.mWidth;
-            int height = mActiveEncCfg.mHeight;
-            int tileWidth = mActiveRawRes.mWidth;
-            int tileHeight = mActiveRawRes.mHeight;
-            if (plane != 0) {
-                width = mActiveEncCfg.mWidth / 2;
-                height = mActiveEncCfg.mHeight / 2;
-                tileWidth = mActiveRawRes.mWidth / 2;
-                tileHeight = mActiveRawRes.mHeight / 2;
-            }
-            for (int k = 0; k < height; k += tileHeight) {
-                int rowsToCopy = Math.min(height - k, tileHeight);
-                for (int j = 0; j < rowsToCopy; j++) {
-                    for (int i = 0; i < width; i += tileWidth) {
-                        int colsToCopy = Math.min(width - i, tileWidth);
-                        inputBuffer.position(
-                                offset + (k + j) * width * mActiveRawRes.mBytesPerSample
-                                        + i * mActiveRawRes.mBytesPerSample);
-                        inputBuffer.put(mInputData,
-                                frmOffset + j * tileWidth * mActiveRawRes.mBytesPerSample,
-                                colsToCopy * mActiveRawRes.mBytesPerSample);
-                    }
-                }
-            }
-            offset += width * height * mActiveRawRes.mBytesPerSample;
-            frmOffset += tileWidth * tileHeight * mActiveRawRes.mBytesPerSample;
-        }
-    }
-
-    protected void enqueueInput(int bufferIndex) {
-        if (mIsLoopBack && mInputBufferReadOffset >= mInputData.length) {
-            mInputBufferReadOffset = 0;
-        }
-        ByteBuffer inputBuffer = mCodec.getInputBuffer(bufferIndex);
-        if (mInputBufferReadOffset >= mInputData.length) {
-            enqueueEOS(bufferIndex);
-        } else {
-            int size;
-            int flags = 0;
-            long pts = mInputOffsetPts;
-            if (mIsAudio) {
-                pts += mNumBytesSubmitted * 1000000L / ((long) mActiveRawRes.mBytesPerSample
-                        * mActiveEncCfg.mChannelCount * mActiveEncCfg.mSampleRate);
-                size = Math.min(inputBuffer.capacity(), mInputData.length - mInputBufferReadOffset);
-                assertEquals(0, size % ((long) mActiveRawRes.mBytesPerSample
-                        * mActiveEncCfg.mChannelCount));
-                inputBuffer.put(mInputData, mInputBufferReadOffset, size);
-                if (mSignalEOSWithLastFrame) {
-                    if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
-                            (mInputBufferReadOffset + size >= mInputData.length)) {
-                        flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                        mSawInputEOS = true;
-                    }
-                }
-                mInputBufferReadOffset += size;
-            } else {
-                pts += mInputCount * 1000000L / mActiveEncCfg.mFrameRate;
-                size = mActiveRawRes.mBytesPerSample * mActiveEncCfg.mWidth * mActiveEncCfg.mHeight
-                        * 3 / 2;
-                int frmSize = mActiveRawRes.mBytesPerSample * mActiveRawRes.mWidth
-                        * mActiveRawRes.mHeight * 3 / 2;
-                if (mInputBufferReadOffset + frmSize > mInputData.length) {
-                    fail("received partial frame to encode \n" + mTestConfig + mTestEnv);
-                } else {
-                    Image img = mCodec.getInputImage(bufferIndex);
-                    assertNotNull("getInputImage() expected to return non-null for video \n"
-                            + mTestConfig + mTestEnv, img);
-                    fillImage(img);
-                }
-                if (mSignalEOSWithLastFrame) {
-                    if (mIsLoopBack ? (mInputCount + 1 >= mLoopBackFrameLimit) :
-                            (mInputBufferReadOffset + frmSize >= mInputData.length)) {
-                        flags |= MediaCodec.BUFFER_FLAG_END_OF_STREAM;
-                        mSawInputEOS = true;
-                    }
-                }
-                mInputBufferReadOffset += frmSize;
-            }
-            mNumBytesSubmitted += size;
-            if (ENABLE_LOGS) {
-                Log.v(LOG_TAG, "input: id: " + bufferIndex + " size: " + size + " pts: " + pts
-                        + " flags: " + flags);
-            }
-            mCodec.queueInputBuffer(bufferIndex, 0, size, pts, flags);
-            mOutputBuff.saveInPTS(pts);
-            mInputCount++;
-        }
-    }
-
-    protected void dequeueOutput(int bufferIndex, MediaCodec.BufferInfo info) {
-        if (ENABLE_LOGS) {
-            Log.v(LOG_TAG, "output: id: " + bufferIndex + " flags: " + info.flags + " size: "
-                    + info.size + " timestamp: " + info.presentationTimeUs);
-        }
-        if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
-            mSawOutputEOS = true;
-        }
-        if (info.size > 0) {
-            ByteBuffer buf = mCodec.getOutputBuffer(bufferIndex);
-            if (mSaveToMem) {
-                MediaCodec.BufferInfo copy = new MediaCodec.BufferInfo();
-                copy.set(mOutputBuff.getOutStreamSize(), info.size, info.presentationTimeUs,
-                        info.flags);
-                mInfoList.add(copy);
-
-                mOutputBuff.saveToMemory(buf, info);
-            }
-            if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
-                mOutputBuff.saveOutPTS(info.presentationTimeUs);
-                mOutputCount++;
-            }
-            if (mMuxer != null) {
-                if (mTrackID == -1) {
-                    mTrackID = mMuxer.addTrack(mCodec.getOutputFormat());
-                    mMuxer.start();
-                }
-                mMuxer.writeSampleData(mTrackID, buf, info);
-            }
-        }
-        mCodec.releaseOutputBuffer(bufferIndex, false);
-    }
-
-    @Override
-    protected void doWork(int frameLimit) throws IOException, InterruptedException {
-        mLoopBackFrameLimit = frameLimit;
-        if (mMuxOutput) {
-            int muxerFormat = getMuxerFormatForMediaType(mMime);
-            mMuxedOutputFile = getTempFilePath((mActiveEncCfg.mInputBitDepth == 10) ? "10bit" : "");
-            mMuxer = new MediaMuxer(mMuxedOutputFile, muxerFormat);
-        }
-        super.doWork(frameLimit);
-    }
-
-    @Override
-    public void waitForAllOutputs() throws InterruptedException {
-        super.waitForAllOutputs();
-        if (mMuxOutput) {
-            if (mTrackID != -1) {
-                mMuxer.stop();
-                mTrackID = -1;
-            }
-            if (mMuxer != null) {
-                mMuxer.release();
-                mMuxer = null;
-            }
-        }
-    }
-
-    @Override
-    protected PersistableBundle validateMetrics(String codec, MediaFormat format) {
-        PersistableBundle metrics = super.validateMetrics(codec, format);
-        assertEquals("error! metrics#MetricsConstants.MIME_TYPE is not as expected \n" + mTestConfig
-                + mTestEnv, metrics.getString(MediaCodec.MetricsConstants.MIME_TYPE), mMime);
-        assertEquals("error! metrics#MetricsConstants.ENCODER is not as expected \n" + mTestConfig
-                + mTestEnv, 1, metrics.getInt(MediaCodec.MetricsConstants.ENCODER));
-        return metrics;
-    }
-
-    public void encodeToMemory(String encoder, EncoderConfigParams cfg, RawResource res,
-            int frameLimit, boolean saveToMem, boolean muxOutput)
-            throws IOException, InterruptedException {
-        mSaveToMem = saveToMem;
-        mMuxOutput = muxOutput;
-        mOutputBuff = new OutputManager();
-        mInfoList.clear();
-        mActiveEncCfg = cfg;
-        mActiveRawRes = res;
-        mCodec = MediaCodec.createByCodecName(encoder);
-        setUpSource(mActiveRawRes.mFileName);
-        configureCodec(mActiveEncCfg.getFormat(), false, true, true);
-        mCodec.start();
-        doWork(frameLimit);
-        queueEOS();
-        waitForAllOutputs();
-        mCodec.stop();
-        mCodec.release();
-        mActiveRawRes = null;
-        mActiveEncCfg = null;
-        mSaveToMem = false;
-        mMuxOutput = false;
-    }
-
-    void validateTestState() {
-        super.validateTestState();
-        if ((mIsAudio || (mIsVideo && mActiveEncCfg.mMaxBFrames == 0))
-                && !mOutputBuff.isPtsStrictlyIncreasing(mPrevOutputPts)) {
-            fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv
-                    + mOutputBuff.getErrMsg());
-        }
-        if (mIsVideo) {
-            if (!mOutputBuff.isOutPtsListIdenticalToInpPtsList((mActiveEncCfg.mMaxBFrames != 0))) {
-                fail("Input pts list and Output pts list are not identical \n" + mTestConfig
-                        + mTestEnv + mOutputBuff.getErrMsg());
-            }
-        }
-    }
-}
diff --git a/tests/media/common/src/android/mediav2/common/cts/HDREncoderTestBase.java b/tests/media/common/src/android/mediav2/common/cts/HDREncoderTestBase.java
index f5d9186..14ef351 100644
--- a/tests/media/common/src/android/mediav2/common/cts/HDREncoderTestBase.java
+++ b/tests/media/common/src/android/mediav2/common/cts/HDREncoderTestBase.java
@@ -35,7 +35,7 @@
 /**
  * Wrapper class for testing HDR support in video encoder components
  */
-public class HDREncoderTestBase extends EncoderTestBase {
+public class HDREncoderTestBase extends CodecEncoderTestBase {
     private static final String LOG_TAG = HDREncoderTestBase.class.getSimpleName();
 
     private ByteBuffer mHdrStaticInfo;
diff --git a/tests/media/common/src/android/mediav2/common/cts/OutputManager.java b/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
index 5d879c6..d59f432 100644
--- a/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
+++ b/tests/media/common/src/android/mediav2/common/cts/OutputManager.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.graphics.ImageFormat;
 import android.graphics.Rect;
@@ -25,6 +26,8 @@
 import android.media.Image;
 import android.media.MediaCodec;
 
+import java.io.File;
+import java.io.FileOutputStream;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.util.ArrayList;
@@ -38,9 +41,17 @@
  * in memory and outPtsList fields of this class. For video decoders, the decoded information can
  * be overwhelming as it is uncompressed YUV. For them we compute the CRC32 checksum of the
  * output image and buffer and store it instead.
+ *
+ * ByteBuffer output of encoder/decoder components can be written to disk by setting ENABLE_DUMP
+ * to true. Exercise CAUTION while running tests with ENABLE_DUMP set to true as this will crowd
+ * the storage with files. These files are configured to be deleted on exit. So, in order to see
+ * the captured output, File.deleteOnExit() needs to be be commented. Also it might be necessary
+ * to set option name="cleanup-apks" to "false" in AndroidTest.xml.
  */
 public class OutputManager {
     private static final String LOG_TAG = OutputManager.class.getSimpleName();
+    private static final boolean ENABLE_DUMP = false;
+
     private byte[] mMemory;
     private int mMemIndex;
     private final CRC32 mCrc32UsingImage;
@@ -49,6 +60,11 @@
     private final ArrayList<Long> mOutPtsList;
     private final StringBuilder mErrorLogs;
     private final StringBuilder mSharedErrorLogs;
+    private File mOutFileYuv;
+    private boolean mAppendToYuvFile;
+    private File mOutFileY;
+    private boolean mAppendToYFile;
+    private File mOutFileDefault;
 
     public OutputManager() {
         this(new StringBuilder());
@@ -170,6 +186,9 @@
                     offset += stride;
                 }
                 mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
+                if (ENABLE_DUMP) {
+                    dumpY(bb, 0, width * height * bytesPerSample);
+                }
             } else {
                 mCrc32UsingBuffer.update(buf.array(), buf.position() + buf.arrayOffset(), size);
             }
@@ -184,6 +203,9 @@
                 offset += stride;
             }
             mCrc32UsingBuffer.update(bb, 0, width * height * bytesPerSample);
+            if (ENABLE_DUMP) {
+                dumpY(bb, 0, width * height * bytesPerSample);
+            }
             buf.position(pos);
         } else {
             int pos = buf.position();
@@ -282,6 +304,9 @@
                 buf.position(base);
             }
             mCrc32UsingImage.update(bb, 0, width * height * bytesPerSample);
+            if (ENABLE_DUMP) {
+                dumpYuv(bb, 0, width * height * bytesPerSample);
+            }
         }
     }
 
@@ -316,6 +341,18 @@
         mSharedErrorLogs.setLength(0);
         mErrorLogs.setLength(0);
         mErrorLogs.append("##################       Error Details         ####################\n");
+        cleanUp();
+    }
+
+    public void cleanUp() {
+        if (mOutFileYuv != null && mOutFileYuv.exists()) mOutFileYuv.delete();
+        mOutFileYuv = null;
+        mAppendToYuvFile = false;
+        if (mOutFileY != null && mOutFileY.exists()) mOutFileY.delete();
+        mOutFileY = null;
+        mAppendToYFile = false;
+        if (mOutFileDefault != null && mOutFileDefault.exists()) mOutFileDefault.delete();
+        mOutFileDefault = null;
     }
 
     public float getRmsError(Object refObject, int audioFormat) {
@@ -418,6 +455,16 @@
                     mCrc32UsingImage.getValue()));
             mSharedErrorLogs.append(String.format("Test CRC32 checksum value is %d \n",
                     that.mCrc32UsingImage.getValue()));
+            if (ENABLE_DUMP) {
+                mSharedErrorLogs.append(String.format("Decoded Ref YUV file is at : %s \n",
+                        mOutFileYuv.getAbsolutePath()));
+                mSharedErrorLogs.append(String.format("Decoded Test YUV file is at : %s \n",
+                        that.mOutFileYuv.getAbsolutePath()));
+            } else {
+                mSharedErrorLogs.append("As the reference YUV and test YUV are different, try "
+                        + "re-running the test by changing ENABLE_DUMP of OutputManager class to "
+                        + "'true' to dump the decoded YUVs for further analysis. \n");
+            }
         }
         if (mCrc32UsingBuffer.getValue() != that.mCrc32UsingBuffer.getValue()) {
             isEqual = false;
@@ -427,6 +474,30 @@
                     mCrc32UsingBuffer.getValue()));
             mSharedErrorLogs.append(String.format("Test CRC32 checksum value is %d \n",
                     that.mCrc32UsingBuffer.getValue()));
+            if (ENABLE_DUMP) {
+                if (mOutFileY != null) {
+                    mSharedErrorLogs.append(String.format("Decoded Ref Y file is at : %s \n",
+                            mOutFileY.getAbsolutePath()));
+                }
+                if (that.mOutFileY != null) {
+                    mSharedErrorLogs.append(String.format("Decoded Test Y file is at : %s \n",
+                            that.mOutFileY.getAbsolutePath()));
+                }
+                if (mMemIndex > 0) {
+                    mSharedErrorLogs.append(
+                            String.format("Output Ref ByteBuffer is dumped at : %s \n",
+                                    dumpBuffer()));
+                }
+                if (that.mMemIndex > 0) {
+                    mSharedErrorLogs.append(
+                            String.format("Output Test ByteBuffer is dumped at : %s \n",
+                                    that.dumpBuffer()));
+                }
+            } else {
+                mSharedErrorLogs.append("As the output of the component is not consistent, try "
+                        + "re-running the test by changing ENABLE_DUMP of OutputManager class to "
+                        + "'true' to dump the outputs for further analysis. \n");
+            }
             if (mMemIndex == that.mMemIndex) {
                 int count = 0;
                 StringBuilder msg = new StringBuilder();
@@ -459,4 +530,58 @@
     public String getErrMsg() {
         return (mErrorLogs.toString() + mSharedErrorLogs.toString());
     }
+
+    public void dumpYuv(byte[] mem, int offset, int size) {
+        try {
+            if (mOutFileYuv == null) {
+                mOutFileYuv = File.createTempFile(LOG_TAG + "YUV", ".bin");
+                mOutFileYuv.deleteOnExit();
+            }
+            try (FileOutputStream outputStream = new FileOutputStream(mOutFileYuv,
+                    mAppendToYuvFile)) {
+                outputStream.write(mem, offset, size);
+                mAppendToYuvFile = true;
+            }
+        } catch (Exception e) {
+            fail("Encountered IOException during output image write. Exception is" + e);
+        }
+    }
+
+    public void dumpY(byte[] mem, int offset, int size) {
+        try {
+            if (mOutFileY == null) {
+                mOutFileY = File.createTempFile(LOG_TAG + "Y", ".bin");
+                mOutFileY.deleteOnExit();
+            }
+            try (FileOutputStream outputStream = new FileOutputStream(mOutFileY, mAppendToYFile)) {
+                outputStream.write(mem, offset, size);
+                mAppendToYFile = true;
+            }
+        } catch (Exception e) {
+            fail("Encountered IOException during output image write. Exception is" + e);
+        }
+    }
+
+    public String dumpBuffer() {
+        if (ENABLE_DUMP) {
+            try {
+                if (mOutFileDefault == null) {
+                    mOutFileDefault = File.createTempFile(LOG_TAG + "OUT", ".bin");
+                    mOutFileDefault.deleteOnExit();
+                }
+                try (FileOutputStream outputStream = new FileOutputStream(mOutFileDefault)) {
+                    outputStream.write(mMemory, 0, mMemIndex);
+                }
+            } catch (Exception e) {
+                fail("Encountered IOException during output buffer write. Exception is" + e);
+            }
+            return mOutFileDefault.getAbsolutePath();
+        }
+        return "file not dumped yet, re-run the test by changing ENABLE_DUMP of OutputManager "
+                + "class to 'true' to dump the buffer";
+    }
+
+    public String getOutYuvFileName() {
+        return (mOutFileYuv != null) ? mOutFileYuv.getAbsolutePath() : null;
+    }
 }
diff --git a/tests/media/jni/NativeCodecDecoderTestCommon.cpp b/tests/media/jni/NativeCodecDecoderTestCommon.cpp
index e722813..907b9f3 100644
--- a/tests/media/jni/NativeCodecDecoderTestCommon.cpp
+++ b/tests/media/jni/NativeCodecDecoderTestCommon.cpp
@@ -108,7 +108,7 @@
 
 bool CodecDecoderTest::setUpExtractor(const char* srcFile, int colorFormat) {
     FILE* fp = fopen(srcFile, "rbe");
-    RETURN_IF_TRUE(!fp, StringFormat("Unable to open file %s", srcFile))
+    RETURN_IF_NULL(fp, StringFormat("Unable to open file %s", srcFile))
     struct stat buf {};
     if (!fstat(fileno(fp), &buf)) {
         deleteExtractor();
@@ -143,7 +143,7 @@
         }
     }
     if (fp) fclose(fp);
-    RETURN_IF_TRUE(mInpDecFormat == nullptr,
+    RETURN_IF_NULL(mInpDecFormat,
                    StringFormat("No track with media type %s found in file: %s", mMime, srcFile))
     return true;
 }
@@ -198,7 +198,7 @@
 bool CodecDecoderTest::enqueueCodecConfig(int32_t bufferIndex) {
     size_t bufSize;
     uint8_t* buf = AMediaCodec_getInputBuffer(mCodec, bufferIndex, &bufSize);
-    RETURN_IF_TRUE(buf == nullptr, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
+    RETURN_IF_NULL(buf, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
     void* csdBuffer = mCsdBuffers[mCurrCsdIdx].first;
     size_t csdSize = mCsdBuffers[mCurrCsdIdx].second;
     RETURN_IF_TRUE(bufSize < csdSize,
@@ -218,7 +218,7 @@
         uint32_t flags = 0;
         size_t bufSize;
         uint8_t* buf = AMediaCodec_getInputBuffer(mCodec, bufferIndex, &bufSize);
-        RETURN_IF_TRUE(buf == nullptr, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
+        RETURN_IF_NULL(buf, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
         ssize_t size = AMediaExtractor_getSampleSize(mExtractor);
         int64_t pts = AMediaExtractor_getSampleTime(mExtractor);
         RETURN_IF_TRUE(size > bufSize,
@@ -250,8 +250,7 @@
         if (mSaveToMem) {
             size_t buffSize;
             uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
-            RETURN_IF_TRUE(buf == nullptr,
-                           std::string{"AMediaCodec_getOutputBuffer returned nullptr"})
+            RETURN_IF_NULL(buf, std::string{"AMediaCodec_getOutputBuffer returned nullptr"})
             if (mIsAudio) {
                 mOutputBuff->saveToMemory(buf, info);
                 mOutputBuff->updateChecksum(buf, info);
@@ -277,9 +276,9 @@
 
 bool CodecDecoderTest::isTestStateValid() {
     if (!CodecTestBase::isTestStateValid()) return false;
-    RETURN_IF_TRUE(!mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts),
-                   std::string{"Output timestamps are not strictly increasing \n"}.append(
-                           mOutputBuff->getErrorMsg()))
+    RETURN_IF_FALSE(mOutputBuff->isPtsStrictlyIncreasing(mPrevOutputPts),
+                    std::string{"Output timestamps are not strictly increasing \n"}.append(
+                            mOutputBuff->getErrorMsg()))
     RETURN_IF_TRUE(mIsVideo && !mIsInterlaced &&
                    !mOutputBuff->isOutPtsListIdenticalToInpPtsList(false),
                    std::string{"Input pts list and Output pts list are not identical \n"}.append(
@@ -338,7 +337,7 @@
     mOutputBuff = ref;
     AMediaExtractor_seekTo(mExtractor, pts, mode);
     mCodec = AMediaCodec_createCodecByName(decoder);
-    RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", decoder))
+    RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", decoder))
     if (!configureCodec(format, false, true, false)) return false;
     RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
     if (!doWork(frameLimit)) return false;
@@ -370,10 +369,10 @@
             /* Instead of create and delete codec at every iteration, we would like to create
              * once and use it for all iterations and delete before exiting */
             mCodec = AMediaCodec_createCodecByName(decoder);
-            RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", decoder))
+            RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", decoder))
             char* name = nullptr;
             RETURN_IF_FAIL(AMediaCodec_getName(mCodec, &name), "AMediaCodec_getName failed")
-            RETURN_IF_TRUE(!name, std::string{"AMediaCodec_getName returned null"})
+            RETURN_IF_NULL(name, std::string{"AMediaCodec_getName returned null"})
             auto res = strcmp(name, decoder) != 0;
             AMediaCodec_releaseName(mCodec, name);
             RETURN_IF_TRUE(res, StringFormat("Codec name mismatch act/got: %s/%s", decoder, name))
@@ -431,8 +430,8 @@
     const int64_t pts = 500000;
     const SeekMode mode = AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC;
     auto ref = mRefBuff;
-    RETURN_IF_TRUE(!decodeToMemory(decoder, mInpDecFormat, INT32_MAX, ref, pts, mode),
-                   StringFormat("decodeToMemory failed for file: %s codec: %s", testFile, decoder))
+    RETURN_IF_FALSE(decodeToMemory(decoder, mInpDecFormat, INT32_MAX, ref, pts, mode),
+                    StringFormat("decodeToMemory failed for file: %s codec: %s", testFile, decoder))
     auto test = mTestBuff;
     mOutputBuff = test;
     const bool boolStates[]{true, false};
@@ -442,7 +441,7 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(decoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", decoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", decoder))
         AMediaExtractor_seekTo(mExtractor, 0, mode);
         if (!configureCodec(mInpDecFormat, isAsync, true, false)) return false;
         AMediaFormat* defFormat = AMediaCodec_getOutputFormat(mCodec);
@@ -527,7 +526,7 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(decoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", decoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", decoder))
         if (!configureCodec(mInpDecFormat, isAsync, false, false)) return false;
         RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
         if (!queueEOS()) return false;
@@ -579,7 +578,7 @@
                 /* Instead of create and delete codec at every iteration, we would like to create
                  * once and use it for all iterations and delete before exiting */
                 mCodec = AMediaCodec_createCodecByName(decoder);
-                RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", decoder))
+                RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", decoder))
                 AMediaExtractor_seekTo(mExtractor, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
                 if (!configureCodec(fmt, isAsync, eosType, false)) return false;
                 AMediaFormat* defFormat = AMediaCodec_getOutputFormat(mCodec);
diff --git a/tests/media/jni/NativeCodecEncoderSurfaceTest.cpp b/tests/media/jni/NativeCodecEncoderSurfaceTest.cpp
index a186147..2c1e2b2 100644
--- a/tests/media/jni/NativeCodecEncoderSurfaceTest.cpp
+++ b/tests/media/jni/NativeCodecEncoderSurfaceTest.cpp
@@ -47,8 +47,6 @@
     int mDecInputCount;
     int mDecOutputCount;
     int mEncOutputCount;
-    int mEncBitrate;
-    int mEncFramerate;
     int mMaxBFrames;
     int mLatency;
     bool mReviseLatency;
@@ -66,7 +64,6 @@
     void deleteExtractor();
     bool configureCodec(bool isAsync, bool signalEOSWithLastFrame);
     void resetContext(bool isAsync, bool signalEOSWithLastFrame);
-    void setUpEncoderFormat();
     bool enqueueDecoderInput(size_t bufferIndex);
     bool dequeueDecoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo);
     bool dequeueEncoderOutput(size_t bufferIndex, AMediaCodecBufferInfo* info);
@@ -83,24 +80,28 @@
                 "###################       Error Details         #####################\n" +
                 mErrorLogs;
     }
-    CodecEncoderSurfaceTest(const char* mime, int bitrate, int framerate);
+    CodecEncoderSurfaceTest(const char* mime, const char* cfgParams, const char* separator);
     ~CodecEncoderSurfaceTest();
 
     bool testSimpleEncode(const char* encoder, const char* decoder, const char* srcPath,
                           const char* muxOutPath, int colorFormat);
 };
 
-CodecEncoderSurfaceTest::CodecEncoderSurfaceTest(const char* mime, int bitrate, int framerate)
-    : mMime{mime}, mEncBitrate{bitrate}, mEncFramerate{framerate} {
+CodecEncoderSurfaceTest::CodecEncoderSurfaceTest(const char* mime, const char* cfgParams,
+                                                 const char* separator)
+    : mMime{mime} {
     mWindow = nullptr;
     mExtractor = nullptr;
     mDecFormat = nullptr;
-    mEncFormat = nullptr;
+    mEncFormat = deSerializeMediaFormat(cfgParams, separator);
     mMuxer = nullptr;
     mDecoder = nullptr;
     mEncoder = nullptr;
     resetContext(false, false);
     mMaxBFrames = 0;
+    if (mEncFormat != nullptr) {
+        AMediaFormat_getInt32(mEncFormat, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES, &mMaxBFrames);
+    }
     mLatency = mMaxBFrames;
     mReviseLatency = false;
     mMuxTrackID = -1;
@@ -177,6 +178,8 @@
 }
 
 bool CodecEncoderSurfaceTest::configureCodec(bool isAsync, bool signalEOSWithLastFrame) {
+    RETURN_IF_NULL(mEncFormat,
+                   std::string{"encountered error during deserialization of media format"})
     resetContext(isAsync, signalEOSWithLastFrame);
     mTestEnv = "###################      Test Environment       #####################\n";
     {
@@ -243,22 +246,6 @@
     mEncOutputCount = 0;
 }
 
-void CodecEncoderSurfaceTest::setUpEncoderFormat() {
-    if (mEncFormat) AMediaFormat_delete(mEncFormat);
-    mEncFormat = AMediaFormat_new();
-    int width, height;
-    AMediaFormat_getInt32(mDecFormat, AMEDIAFORMAT_KEY_WIDTH, &width);
-    AMediaFormat_getInt32(mDecFormat, AMEDIAFORMAT_KEY_HEIGHT, &height);
-    AMediaFormat_setString(mEncFormat, AMEDIAFORMAT_KEY_MIME, mMime);
-    AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_WIDTH, width);
-    AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_HEIGHT, height);
-    AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_BIT_RATE, mEncBitrate);
-    AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_FRAME_RATE, mEncFramerate);
-    AMediaFormat_setInt32(mEncFormat, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES, mMaxBFrames);
-    AMediaFormat_setInt32(mEncFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatSurface);
-    AMediaFormat_setFloat(mEncFormat, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1.0F);
-}
-
 bool CodecEncoderSurfaceTest::enqueueDecoderEOS(size_t bufferIndex) {
     if (!hasSeenError() && !mSawDecInputEOS) {
         RETURN_IF_FAIL(AMediaCodec_queueInputBuffer(mDecoder, bufferIndex, 0, 0, 0,
@@ -277,7 +264,7 @@
         uint32_t flags = 0;
         size_t bufSize = 0;
         uint8_t* buf = AMediaCodec_getInputBuffer(mDecoder, bufferIndex, &bufSize);
-        RETURN_IF_TRUE(buf == nullptr, std::string{"AMediaCodec_getInputBuffer failed"})
+        RETURN_IF_NULL(buf, std::string{"AMediaCodec_getInputBuffer failed"})
         ssize_t size = AMediaExtractor_getSampleSize(mExtractor);
         int64_t pts = AMediaExtractor_getSampleTime(mExtractor);
         RETURN_IF_TRUE(size > bufSize,
@@ -553,9 +540,8 @@
 bool CodecEncoderSurfaceTest::testSimpleEncode(const char* encoder, const char* decoder,
                                                const char* srcPath, const char* muxOutPath,
                                                int colorFormat) {
-    RETURN_IF_TRUE(!setUpExtractor(srcPath, colorFormat), std::string{"setUpExtractor failed"})
-    setUpEncoderFormat();
-    bool muxOutput = true;
+    RETURN_IF_FALSE(setUpExtractor(srcPath, colorFormat), std::string{"setUpExtractor failed"})
+    bool muxOutput = muxOutPath != nullptr;
 
     /* TODO(b/149027258) */
     if (true) mSaveToMem = false;
@@ -574,8 +560,8 @@
          * once and use it for all iterations and delete before exiting */
         mEncoder = AMediaCodec_createCodecByName(encoder);
         mDecoder = AMediaCodec_createCodecByName(decoder);
-        RETURN_IF_TRUE(!mDecoder, StringFormat("unable to create media codec by name %s", decoder))
-        RETURN_IF_TRUE(!mEncoder, StringFormat("unable to create media codec by name %s", encoder))
+        RETURN_IF_NULL(mDecoder, StringFormat("unable to create media codec by name %s", decoder))
+        RETURN_IF_NULL(mEncoder, StringFormat("unable to create media codec by name %s", encoder))
         FILE* ofp = nullptr;
         if (muxOutput && loopCounter == 0) {
             int muxerFormat = 0;
@@ -649,15 +635,16 @@
 
 static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jDecoder,
                                        jstring jMime, jstring jtestFile, jstring jmuxFile,
-                                       jint jBitrate, jint jFramerate, jint jColorFormat,
+                                       jint jColorFormat, jstring jCfgParams, jstring jSeparator,
                                        jobject jRetMsg) {
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
     const char* cDecoder = env->GetStringUTFChars(jDecoder, nullptr);
     const char* cMime = env->GetStringUTFChars(jMime, nullptr);
     const char* cTestFile = env->GetStringUTFChars(jtestFile, nullptr);
-    const char* cMuxFile = env->GetStringUTFChars(jmuxFile, nullptr);
-    auto codecEncoderSurfaceTest =
-            new CodecEncoderSurfaceTest(cMime, (int)jBitrate, (int)jFramerate);
+    const char* cMuxFile = jmuxFile ? env->GetStringUTFChars(jmuxFile, nullptr) : nullptr;
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderSurfaceTest = new CodecEncoderSurfaceTest(cMime, cCfgParams, cSeparator);
     bool isPass = codecEncoderSurfaceTest->testSimpleEncode(cEncoder, cDecoder, cTestFile, cMuxFile,
                                                             jColorFormat);
     std::string msg = isPass ? std::string{} : codecEncoderSurfaceTest->getErrorMsg();
@@ -670,7 +657,10 @@
     env->ReleaseStringUTFChars(jDecoder, cDecoder);
     env->ReleaseStringUTFChars(jMime, cMime);
     env->ReleaseStringUTFChars(jtestFile, cTestFile);
-    env->ReleaseStringUTFChars(jmuxFile, cMuxFile);
+    if (cMuxFile) env->ReleaseStringUTFChars(jmuxFile, cMuxFile);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
+
     return isPass;
 }
 
@@ -678,7 +668,7 @@
     const JNINativeMethod methodTable[] = {
             {"nativeTestSimpleEncode",
              "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
-             "String;IIILjava/lang/StringBuilder;)Z",
+             "String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/StringBuilder;)Z",
              (void*)nativeTestSimpleEncode},
     };
     jclass c = env->FindClass("android/mediav2/cts/CodecEncoderSurfaceTest");
diff --git a/tests/media/jni/NativeCodecEncoderTest.cpp b/tests/media/jni/NativeCodecEncoderTest.cpp
index d0fecea..e7c2470 100644
--- a/tests/media/jni/NativeCodecEncoderTest.cpp
+++ b/tests/media/jni/NativeCodecEncoderTest.cpp
@@ -37,13 +37,6 @@
     int mNumSyncFramesReceived;
     std::vector<int> mSyncFramesPos;
 
-    int32_t* mBitRates;
-    int mLen0;
-    int32_t* mEncParamList1;
-    int mLen1;
-    int32_t* mEncParamList2;
-    int mLen2;
-
     int mWidth, mHeight;
     int mChannels;
     int mSampleRate;
@@ -56,7 +49,6 @@
     void convertyuv420ptoyuv420sp();
     void setUpSource(const char* srcPath);
     void deleteSource();
-    void setUpParams(int limit);
     void deleteParams();
     bool configureCodec(AMediaFormat* format, bool isAsync, bool signalEOSWithLastFrame,
                         bool isEncoder) override;
@@ -65,7 +57,7 @@
     bool dequeueOutput(size_t bufferIndex, AMediaCodecBufferInfo* bufferInfo) override;
     bool doWork(int frameLimit) override;
     bool isTestStateValid() override;
-    void initFormat(AMediaFormat* format);
+    bool initFormat(AMediaFormat* format);
     bool encodeToMemory(const char* file, const char* encoder, int frameLimit, AMediaFormat* format,
                         OutputManager* ref);
     void fillByteBuffer(uint8_t* inputBuffer);
@@ -73,8 +65,8 @@
     void updateBitrate(AMediaFormat* format, int bitrate);
 
   public:
-    CodecEncoderTest(const char* mime, int32_t* list0, int len0, int32_t* list1, int len1,
-                     int32_t* list2, int len2, int colorFormat);
+    CodecEncoderTest(const char* mime, const char* cfgParams, const char* cfgReconfigParams,
+                     const char* separator);
     ~CodecEncoderTest();
 
     bool testSimpleEncode(const char* encoder, const char* srcPath);
@@ -84,20 +76,16 @@
     bool testOnlyEos(const char* encoder);
 };
 
-CodecEncoderTest::CodecEncoderTest(const char* mime, int32_t* list0, int len0, int32_t* list1,
-                                   int len1, int32_t* list2, int len2, int colorFormat)
-    : CodecTestBase(mime),
-      mBitRates{list0},
-      mLen0{len0},
-      mEncParamList1{list1},
-      mLen1{len1},
-      mEncParamList2{list2},
-      mLen2{len2},
-      mColorFormat{colorFormat} {
-    mDefFrameRate = 30;
-    if (!strcmp(mime, AMEDIA_MIMETYPE_VIDEO_H263)) mDefFrameRate = 12;
-    else if (!strcmp(mime, AMEDIA_MIMETYPE_VIDEO_MPEG4)) mDefFrameRate = 12;
-    mMaxBFrames = 0;
+CodecEncoderTest::CodecEncoderTest(const char* mime, const char* cfgParams,
+                                   const char* cfgReconfigParams, const char* separator)
+    : CodecTestBase(mime) {
+    mFormats.push_back(deSerializeMediaFormat(cfgParams, separator));
+    if (cfgReconfigParams) {
+        mFormats.push_back(deSerializeMediaFormat(cfgReconfigParams, separator));
+    }
+    if (mIsVideo && mFormats[0] != nullptr) {
+        AMediaFormat_getInt32(mFormats[0], AMEDIAFORMAT_KEY_COLOR_FORMAT, &mColorFormat);
+    }
     mInputData = nullptr;
     mInputLength = 0;
     mInputBufferReadOffset = 0;
@@ -159,52 +147,6 @@
     mInputLength = 0;
 }
 
-void CodecEncoderTest::setUpParams(int limit) {
-    int count = 0;
-    for (int k = 0; k < mLen0; k++) {
-        int bitrate = mBitRates[k];
-        if (mIsAudio) {
-            for (int j = 0; j < mLen1; j++) {
-                int rate = mEncParamList1[j];
-                for (int i = 0; i < mLen2; i++) {
-                    int channels = mEncParamList2[i];
-                    AMediaFormat* format = AMediaFormat_new();
-                    AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mMime);
-                    if (!strcmp(mMime, AMEDIA_MIMETYPE_AUDIO_FLAC)) {
-                        AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FLAC_COMPRESSION_LEVEL,
-                                              bitrate);
-                    } else {
-                        AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
-                    }
-                    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, rate);
-                    AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channels);
-                    mFormats.push_back(format);
-                    count++;
-                    if (count >= limit) break;
-                }
-            }
-        } else {
-            for (int j = 0; j < mLen1; j++) {
-                int width = mEncParamList1[j];
-                int height = mEncParamList2[j];
-                AMediaFormat* format = AMediaFormat_new();
-                AMediaFormat_setString(format, AMEDIAFORMAT_KEY_MIME, mMime);
-                AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, bitrate);
-                AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_WIDTH, width);
-                AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_HEIGHT, height);
-                AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, mDefFrameRate);
-                AMediaFormat_setInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES,
-                                      mMaxBFrames);
-                AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 1.0F);
-                AMediaFormat_setInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, mColorFormat);
-                mFormats.push_back(format);
-                count++;
-                if (count >= limit) break;
-            }
-        }
-    }
-}
-
 void CodecEncoderTest::deleteParams() {
     for (auto format : mFormats) AMediaFormat_delete(format);
     mFormats.clear();
@@ -212,9 +154,8 @@
 
 bool CodecEncoderTest::configureCodec(AMediaFormat* format, bool isAsync,
                                       bool signalEOSWithLastFrame, bool isEncoder) {
-    bool res = CodecTestBase::configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
-    initFormat(format);
-    return res;
+    if (!initFormat(format)) return false;
+    return CodecTestBase::configureCodec(format, isAsync, signalEOSWithLastFrame, isEncoder);
 }
 
 void CodecEncoderTest::resetContext(bool isAsync, bool signalEOSWithLastFrame) {
@@ -278,8 +219,7 @@
         int64_t pts = mInputOffsetPts;
         size_t buffSize;
         uint8_t* inputBuffer = AMediaCodec_getInputBuffer(mCodec, bufferIndex, &buffSize);
-        RETURN_IF_TRUE(inputBuffer == nullptr,
-                       std::string{"AMediaCodec_getInputBuffer returned nullptr"})
+        RETURN_IF_NULL(inputBuffer, std::string{"AMediaCodec_getInputBuffer returned nullptr"})
         if (mIsAudio) {
             pts += mNumBytesSubmitted * 1000000LL / (2 * mChannels * mSampleRate);
             size = std::min(buffSize, mInputLength - mInputBufferReadOffset);
@@ -334,8 +274,7 @@
         if (mSaveToMem) {
             size_t buffSize;
             uint8_t* buf = AMediaCodec_getOutputBuffer(mCodec, bufferIndex, &buffSize);
-            RETURN_IF_TRUE(buf == nullptr,
-                           std::string{"AMediaCodec_getOutputBuffer returned nullptr"})
+            RETURN_IF_NULL(buf, std::string{"AMediaCodec_getOutputBuffer returned nullptr"})
             mOutputBuff->saveToMemory(buf, info);
         }
         if ((info->flags & TBD_AMEDIACODEC_BUFFER_FLAG_KEY_FRAME) != 0) {
@@ -371,14 +310,27 @@
     return true;
 }
 
-void CodecEncoderTest::initFormat(AMediaFormat* format) {
+bool CodecEncoderTest::initFormat(AMediaFormat* format) {
     if (mIsAudio) {
-        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate);
-        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mChannels);
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_SAMPLE_RATE))
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mChannels),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_CHANNEL_COUNT))
     } else {
-        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth);
-        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight);
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_WIDTH, &mWidth),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_WIDTH))
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_HEIGHT, &mHeight),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_HEIGHT))
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES,
+                                              &mMaxBFrames),
+                        StringFormat("format does not have key %s",
+                                     TBD_AMEDIACODEC_PARAMETER_KEY_MAX_B_FRAMES))
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_COLOR_FORMAT, &mColorFormat),
+                        StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_COLOR_FORMAT))
     }
+    return true;
 }
 
 bool CodecEncoderTest::encodeToMemory(const char* file, const char* encoder, int32_t frameLimit,
@@ -388,9 +340,9 @@
     else mSaveToMem = true;
     mOutputBuff = ref;
     mCodec = AMediaCodec_createCodecByName(encoder);
-    RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec by name %s \n", encoder))
+    RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s \n", encoder))
     setUpSource(file);
-    RETURN_IF_TRUE(!mInputData, StringFormat("unable to open input file %s", file))
+    RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", file))
     if (!configureCodec(format, false, true, true)) return false;
     RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
     if (!doWork(frameLimit)) return false;
@@ -417,8 +369,7 @@
 
 bool CodecEncoderTest::testSimpleEncode(const char* encoder, const char* srcPath) {
     setUpSource(srcPath);
-    RETURN_IF_TRUE(!mInputData, StringFormat("unable to open input file %s", srcPath))
-    setUpParams(1);
+    RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
     /* TODO(b/149027258) */
     if (true) mSaveToMem = false;
     else mSaveToMem = true;
@@ -426,6 +377,8 @@
     auto test = mTestBuff;
     const bool boolStates[]{true, false};
     for (auto format : mFormats) {
+        RETURN_IF_NULL(format,
+                       std::string{"encountered error during deserialization of media format"})
         int loopCounter = 0;
         for (auto eosType : boolStates) {
             for (auto isAsync : boolStates) {
@@ -435,10 +388,10 @@
                 /* Instead of create and delete codec at every iteration, we would like to create
                  * once and use it for all iterations and delete before exiting */
                 mCodec = AMediaCodec_createCodecByName(encoder);
-                RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", encoder))
+                RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", encoder))
                 char* name = nullptr;
                 RETURN_IF_FAIL(AMediaCodec_getName(mCodec, &name), "AMediaCodec_getName failed")
-                RETURN_IF_TRUE(!name, std::string{"AMediaCodec_getName returned null"})
+                RETURN_IF_NULL(name, std::string{"AMediaCodec_getName returned null"})
                 auto res = strcmp(name, encoder) != 0;
                 AMediaCodec_releaseName(mCodec, name);
                 RETURN_IF_TRUE(res,
@@ -463,20 +416,22 @@
 
 bool CodecEncoderTest::testReconfigure(const char* encoder, const char* srcPath) {
     setUpSource(srcPath);
-    RETURN_IF_TRUE(!mInputData, StringFormat("unable to open input file %s", srcPath))
-    setUpParams(2);
+    RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
     auto configRef = mReconfBuff;
     if (mFormats.size() > 1) {
         auto format = mFormats[1];
-        RETURN_IF_TRUE(!encodeToMemory(srcPath, encoder, INT32_MAX, format, configRef),
-                       StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
-                                    srcPath, encoder, AMediaFormat_toString(format)))
+        RETURN_IF_NULL(format,
+                       std::string{"encountered error during deserialization of media format"})
+        RETURN_IF_FALSE(encodeToMemory(srcPath, encoder, INT32_MAX, format, configRef),
+                        StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
+                                     srcPath, encoder, AMediaFormat_toString(format)))
     }
     auto format = mFormats[0];
+    RETURN_IF_NULL(format, std::string{"encountered error during deserialization of media format"})
     auto ref = mRefBuff;
-    RETURN_IF_TRUE(!encodeToMemory(srcPath, encoder, INT32_MAX, format, ref),
-                   StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
-                                srcPath, encoder, AMediaFormat_toString(format)))
+    RETURN_IF_FALSE(encodeToMemory(srcPath, encoder, INT32_MAX, format, ref),
+                    StringFormat("encodeToMemory failed for file: %s codec: %s \n format: %s",
+                                 srcPath, encoder, AMediaFormat_toString(format)))
 
     auto test = mTestBuff;
     mOutputBuff = test;
@@ -486,7 +441,7 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(encoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec %s", encoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec %s", encoder))
         if (!configureCodec(format, isAsync, true, true)) return false;
         /* test reconfigure in init state */
         if (!reConfigureCodec(format, !isAsync, false, true)) return false;
@@ -546,7 +501,6 @@
 }
 
 bool CodecEncoderTest::testOnlyEos(const char* encoder) {
-    setUpParams(1);
     /* TODO(b/149027258) */
     if (true) mSaveToMem = false;
     else mSaveToMem = true;
@@ -554,6 +508,8 @@
     auto test = mTestBuff;
     const bool boolStates[]{true, false};
     AMediaFormat* format = mFormats[0];
+    RETURN_IF_NULL(format,
+                   std::string{"encountered error during deserialization of media format"})
     int loopCounter = 0;
     for (auto isAsync : boolStates) {
         mOutputBuff = loopCounter == 0 ? ref : test;
@@ -562,7 +518,7 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(encoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec by name %s", encoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s", encoder))
         if (!configureCodec(format, isAsync, false, true)) return false;
         RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
         if (!queueEOS()) return false;
@@ -580,10 +536,12 @@
 
 bool CodecEncoderTest::testSetForceSyncFrame(const char* encoder, const char* srcPath) {
     setUpSource(srcPath);
-    RETURN_IF_TRUE(!mInputData, StringFormat("unable to open input file %s", srcPath))
-    setUpParams(1);
+    RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
     AMediaFormat* format = mFormats[0];
-    AMediaFormat_setFloat(format, AMEDIAFORMAT_KEY_I_FRAME_INTERVAL, 500.f);
+    RETURN_IF_NULL(format,
+                   std::string{"encountered error during deserialization of media format"})
+    RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
+                    StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
     // Maximum allowed key frame interval variation from the target value.
     int kMaxKeyFrameIntervalVariation = 3;
     int kKeyFrameInterval = 2;  // force key frame every 2 seconds.
@@ -599,7 +557,7 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(encoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec by name%s", encoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name%s", encoder))
         if (!configureCodec(format, isAsync, false, true)) return false;
         RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
         for (int i = 0; i < kNumKeyFrameRequests; i++) {
@@ -642,9 +600,12 @@
 
 bool CodecEncoderTest::testAdaptiveBitRate(const char* encoder, const char* srcPath) {
     setUpSource(srcPath);
-    RETURN_IF_TRUE(!mInputData, StringFormat("unable to open input file %s", srcPath))
-    setUpParams(1);
+    RETURN_IF_NULL(mInputData, StringFormat("unable to open input file %s", srcPath))
     AMediaFormat* format = mFormats[0];
+    RETURN_IF_NULL(format,
+                   std::string{"encountered error during deserialization of media format"})
+    RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_FRAME_RATE, &mDefFrameRate),
+                    StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_FRAME_RATE))
     int kAdaptiveBitrateInterval = 3;  // change bitrate every 3 seconds.
     int kAdaptiveBitrateDurationFrame = mDefFrameRate * kAdaptiveBitrateInterval;
     int kBitrateChangeRequests = 7;
@@ -652,8 +613,6 @@
     float kMaxBitrateDeviation = 60.0; // allowed bitrate deviation in %
     AMediaFormat* params = AMediaFormat_new();
     mFormats.push_back(params);
-    // Setting in CBR Mode
-    AMediaFormat_setInt32(format, TBD_AMEDIAFORMAT_KEY_BIT_RATE_MODE, kBitrateModeConstant);
     mOutputBuff = mTestBuff;
     mSaveToMem = true;
     const bool boolStates[]{true, false};
@@ -663,12 +622,13 @@
         /* Instead of create and delete codec at every iteration, we would like to create
          * once and use it for all iterations and delete before exiting */
         mCodec = AMediaCodec_createCodecByName(encoder);
-        RETURN_IF_TRUE(!mCodec, StringFormat("unable to create codec by name %s", encoder))
+        RETURN_IF_NULL(mCodec, StringFormat("unable to create codec by name %s", encoder))
         if (!configureCodec(format, isAsync, false, true)) return false;
         RETURN_IF_FAIL(AMediaCodec_start(mCodec), "AMediaCodec_start failed")
         int expOutSize = 0;
         int bitrate;
-        AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate);
+        RETURN_IF_FALSE(AMediaFormat_getInt32(format, AMEDIAFORMAT_KEY_BIT_RATE, &bitrate),
+                       StringFormat("format does not have key %s", AMEDIAFORMAT_KEY_BIT_RATE))
         for (int i = 0; i < kBitrateChangeRequests; i++) {
             if (!doWork(kAdaptiveBitrateDurationFrame)) return false;
             RETURN_IF_TRUE(mSawInputEOS,
@@ -696,19 +656,14 @@
 }
 
 static jboolean nativeTestSimpleEncode(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
-                                       jstring jMime, jintArray jList0, jintArray jList1,
-                                       jintArray jList2, jint colorFormat, jobject jRetMsg) {
+                                       jstring jMime, jstring jCfgParams, jstring jSeparator,
+                                       jobject jRetMsg) {
     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
     const char* cmime = env->GetStringUTFChars(jMime, nullptr);
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
-    jsize cLen0 = env->GetArrayLength(jList0);
-    jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
-    jsize cLen1 = env->GetArrayLength(jList1);
-    jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
-    jsize cLen2 = env->GetArrayLength(jList2);
-    jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
-    auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
-                                                 (int)colorFormat);
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderTest = new CodecEncoderTest(cmime, cCfgParams, nullptr, cSeparator);
     bool isPass = codecEncoderTest->testSimpleEncode(cEncoder, csrcPath);
     std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
     delete codecEncoderTest;
@@ -716,9 +671,8 @@
     jmethodID mId =
             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
-    env->ReleaseIntArrayElements(jList0, cList0, 0);
-    env->ReleaseIntArrayElements(jList1, cList1, 0);
-    env->ReleaseIntArrayElements(jList2, cList2, 0);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
     env->ReleaseStringUTFChars(jEncoder, cEncoder);
     env->ReleaseStringUTFChars(jMime, cmime);
     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
@@ -726,20 +680,18 @@
 }
 
 static jboolean nativeTestReconfigure(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
-                                      jstring jMime, jintArray jList0, jintArray jList1,
-                                      jintArray jList2, jint colorFormat, jobject jRetMsg) {
+                                      jstring jMime, jstring jCfgParams, jstring jReconfigCfgParams,
+                                      jstring jSeparator, jobject jRetMsg) {
     bool isPass;
     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
     const char* cmime = env->GetStringUTFChars(jMime, nullptr);
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
-    jsize cLen0 = env->GetArrayLength(jList0);
-    jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
-    jsize cLen1 = env->GetArrayLength(jList1);
-    jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
-    jsize cLen2 = env->GetArrayLength(jList2);
-    jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
-    auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
-                                                 (int)colorFormat);
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cReconfigCfgParams = jReconfigCfgParams != nullptr
+                                             ? env->GetStringUTFChars(jReconfigCfgParams, nullptr)
+                                             : nullptr;
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderTest = new CodecEncoderTest(cmime, cCfgParams, cReconfigCfgParams, cSeparator);
     isPass = codecEncoderTest->testReconfigure(cEncoder, csrcPath);
     std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
     delete codecEncoderTest;
@@ -747,9 +699,11 @@
     jmethodID mId =
             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
-    env->ReleaseIntArrayElements(jList0, cList0, 0);
-    env->ReleaseIntArrayElements(jList1, cList1, 0);
-    env->ReleaseIntArrayElements(jList2, cList2, 0);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    if (cReconfigCfgParams != nullptr) {
+        env->ReleaseStringUTFChars(jReconfigCfgParams, cReconfigCfgParams);
+    }
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
     env->ReleaseStringUTFChars(jEncoder, cEncoder);
     env->ReleaseStringUTFChars(jMime, cmime);
     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
@@ -757,20 +711,14 @@
 }
 
 static jboolean nativeTestSetForceSyncFrame(JNIEnv* env, jobject, jstring jEncoder,
-                                            jstring jsrcPath, jstring jMime, jintArray jList0,
-                                            jintArray jList1, jintArray jList2, jint colorFormat,
-                                            jobject jRetMsg) {
+                                            jstring jsrcPath, jstring jMime, jstring jCfgParams,
+                                            jstring jSeparator, jobject jRetMsg) {
     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
     const char* cmime = env->GetStringUTFChars(jMime, nullptr);
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
-    jsize cLen0 = env->GetArrayLength(jList0);
-    jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
-    jsize cLen1 = env->GetArrayLength(jList1);
-    jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
-    jsize cLen2 = env->GetArrayLength(jList2);
-    jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
-    auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
-                                                 (int)colorFormat);
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderTest = new CodecEncoderTest(cmime, cCfgParams, nullptr, cSeparator);
     bool isPass = codecEncoderTest->testSetForceSyncFrame(cEncoder, csrcPath);
     std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
     delete codecEncoderTest;
@@ -778,9 +726,8 @@
     jmethodID mId =
             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
-    env->ReleaseIntArrayElements(jList0, cList0, 0);
-    env->ReleaseIntArrayElements(jList1, cList1, 0);
-    env->ReleaseIntArrayElements(jList2, cList2, 0);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
     env->ReleaseStringUTFChars(jEncoder, cEncoder);
     env->ReleaseStringUTFChars(jMime, cmime);
     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
@@ -788,19 +735,14 @@
 }
 
 static jboolean nativeTestAdaptiveBitRate(JNIEnv* env, jobject, jstring jEncoder, jstring jsrcPath,
-                                          jstring jMime, jintArray jList0, jintArray jList1,
-                                          jintArray jList2, jint colorFormat, jobject jRetMsg) {
+                                          jstring jMime, jstring jCfgParams, jstring jSeparator,
+                                          jobject jRetMsg) {
     const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
     const char* cmime = env->GetStringUTFChars(jMime, nullptr);
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
-    jsize cLen0 = env->GetArrayLength(jList0);
-    jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
-    jsize cLen1 = env->GetArrayLength(jList1);
-    jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
-    jsize cLen2 = env->GetArrayLength(jList2);
-    jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
-    auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
-                                                 (int)colorFormat);
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderTest = new CodecEncoderTest(cmime, cCfgParams, nullptr, cSeparator);
     bool isPass = codecEncoderTest->testAdaptiveBitRate(cEncoder, csrcPath);
     std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
     delete codecEncoderTest;
@@ -808,9 +750,8 @@
     jmethodID mId =
             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
-    env->ReleaseIntArrayElements(jList0, cList0, 0);
-    env->ReleaseIntArrayElements(jList1, cList1, 0);
-    env->ReleaseIntArrayElements(jList2, cList2, 0);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
     env->ReleaseStringUTFChars(jEncoder, cEncoder);
     env->ReleaseStringUTFChars(jMime, cmime);
     env->ReleaseStringUTFChars(jsrcPath, csrcPath);
@@ -818,18 +759,12 @@
 }
 
 static jboolean nativeTestOnlyEos(JNIEnv* env, jobject, jstring jEncoder, jstring jMime,
-                                  jintArray jList0, jintArray jList1, jintArray jList2,
-                                  jint colorFormat, jobject jRetMsg) {
+                                  jstring jCfgParams, jstring jSeparator, jobject jRetMsg) {
     const char* cmime = env->GetStringUTFChars(jMime, nullptr);
     const char* cEncoder = env->GetStringUTFChars(jEncoder, nullptr);
-    jsize cLen0 = env->GetArrayLength(jList0);
-    jint* cList0 = env->GetIntArrayElements(jList0, nullptr);
-    jsize cLen1 = env->GetArrayLength(jList1);
-    jint* cList1 = env->GetIntArrayElements(jList1, nullptr);
-    jsize cLen2 = env->GetArrayLength(jList2);
-    jint* cList2 = env->GetIntArrayElements(jList2, nullptr);
-    auto codecEncoderTest = new CodecEncoderTest(cmime, cList0, cLen0, cList1, cLen1, cList2, cLen2,
-                                                 (int)colorFormat);
+    const char* cCfgParams = env->GetStringUTFChars(jCfgParams, nullptr);
+    const char* cSeparator = env->GetStringUTFChars(jSeparator, nullptr);
+    auto codecEncoderTest = new CodecEncoderTest(cmime, cCfgParams, nullptr, cSeparator);
     bool isPass = codecEncoderTest->testOnlyEos(cEncoder);
     std::string msg = isPass ? std::string{} : codecEncoderTest->getErrorMsg();
     delete codecEncoderTest;
@@ -837,9 +772,8 @@
     jmethodID mId =
             env->GetMethodID(clazz, "append", "(Ljava/lang/String;)Ljava/lang/StringBuilder;");
     env->CallObjectMethod(jRetMsg, mId, env->NewStringUTF(msg.c_str()));
-    env->ReleaseIntArrayElements(jList0, cList0, 0);
-    env->ReleaseIntArrayElements(jList1, cList1, 0);
-    env->ReleaseIntArrayElements(jList2, cList2, 0);
+    env->ReleaseStringUTFChars(jCfgParams, cCfgParams);
+    env->ReleaseStringUTFChars(jSeparator, cSeparator);
     env->ReleaseStringUTFChars(jEncoder, cEncoder);
     env->ReleaseStringUTFChars(jMime, cmime);
     return static_cast<jboolean>(isPass);
@@ -848,23 +782,24 @@
 int registerAndroidMediaV2CtsEncoderTest(JNIEnv* env) {
     const JNINativeMethod methodTable[] = {
             {"nativeTestSimpleEncode",
-             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[IILjava/lang/"
-             "StringBuilder;)Z",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+             "String;Ljava/lang/StringBuilder;)Z",
              (void*)nativeTestSimpleEncode},
             {"nativeTestReconfigure",
-             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[IILjava/lang/"
-             "StringBuilder;)Z",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+             "String;Ljava/lang/String;Ljava/lang/StringBuilder;)Z",
              (void*)nativeTestReconfigure},
             {"nativeTestSetForceSyncFrame",
-             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[IILjava/lang/"
-             "StringBuilder;)Z",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+             "String;Ljava/lang/StringBuilder;)Z",
              (void*)nativeTestSetForceSyncFrame},
             {"nativeTestAdaptiveBitRate",
-             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[I[I[IILjava/lang/"
-             "StringBuilder;)Z",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+             "String;Ljava/lang/StringBuilder;)Z",
              (void*)nativeTestAdaptiveBitRate},
             {"nativeTestOnlyEos",
-             "(Ljava/lang/String;Ljava/lang/String;[I[I[IILjava/lang/StringBuilder;)Z",
+             "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/"
+             "StringBuilder;)Z",
              (void*)nativeTestOnlyEos},
     };
     jclass c = env->FindClass("android/mediav2/cts/CodecEncoderTest");
diff --git a/tests/media/jni/NativeCodecTestBase.h b/tests/media/jni/NativeCodecTestBase.h
index f4b60b6..8cbac7e 100644
--- a/tests/media/jni/NativeCodecTestBase.h
+++ b/tests/media/jni/NativeCodecTestBase.h
@@ -46,6 +46,20 @@
         return false;                          \
     }
 
+#define RETURN_IF_FALSE(cond, msg)              \
+    if (!(cond)) {                              \
+        ALOGE("%s", (msg).c_str());             \
+        mErrorLogs.append((msg)).append("\n");  \
+        return false;                           \
+    }
+
+#define RETURN_IF_NULL(var, msg)               \
+    if ((var) == nullptr) {                    \
+        ALOGE("%s", (msg).c_str());            \
+        mErrorLogs.append((msg)).append("\n"); \
+        return false;                          \
+    }
+
 struct callbackObject {
     AMediaCodecBufferInfo bufferInfo;
     int32_t bufferIndex;
diff --git a/tests/media/jni/NativeMediaCommon.cpp b/tests/media/jni/NativeMediaCommon.cpp
index 3aabda3..da5cb36 100644
--- a/tests/media/jni/NativeMediaCommon.cpp
+++ b/tests/media/jni/NativeMediaCommon.cpp
@@ -154,3 +154,59 @@
     if (strncmp(mediaType, "video/", strlen("video/")) == 0) return true;
     return false;
 }
+
+AMediaFormat* deSerializeMediaFormat(const char* msg, const char* separator) {
+    // constants to be kept in sync with definitions at MediaFormat.java
+    static const int TYPE_INTEGER = 1;
+    static const int TYPE_FLOAT = 3;
+    static const int TYPE_STRING = 4;
+    std::string limiter{separator};
+    std::string fmtMsg{msg};
+    AMediaFormat* fmt = AMediaFormat_new();
+    if (fmt == nullptr) {
+        ALOGE("no format received");
+        return nullptr;
+    }
+    auto start = 0u;
+    auto end = fmtMsg.find(limiter);
+    std::string keyStr, valueTypeStr, valueStr;
+    for (; end != std::string::npos;) {
+        // key
+        keyStr = fmtMsg.substr(start, end - start);
+        start = end + limiter.length();
+        end = fmtMsg.find(limiter, start);
+        if (end == std::string::npos) {
+            ALOGE("incomplete media format received %s", msg);
+            AMediaFormat_delete(fmt);
+            return nullptr;
+        }
+        // value type
+        valueTypeStr = fmtMsg.substr(start, end - start);
+        start = end + limiter.length();
+        end = fmtMsg.find(limiter, start);
+        if (end == std::string::npos) {
+            ALOGE("incomplete media format received %s", msg);
+            AMediaFormat_delete(fmt);
+            return nullptr;
+        }
+
+        // value
+        valueStr = fmtMsg.substr(start, end - start);
+        start = end + limiter.length();
+        end = fmtMsg.find(limiter, start);
+
+        auto valueType = std::stoi(valueTypeStr);
+        if (valueType == TYPE_INTEGER) {
+            AMediaFormat_setInt32(fmt, keyStr.c_str(), std::stoi(valueStr));
+        } else if (valueType == TYPE_FLOAT) {
+            AMediaFormat_setFloat(fmt, keyStr.c_str(), std::stof(valueStr));
+        } else if (valueType == TYPE_STRING) {
+            AMediaFormat_setString(fmt, keyStr.c_str(), valueStr.c_str());
+        } else {
+            ALOGE("unrecognized type for key %s", keyStr.c_str());
+            AMediaFormat_delete(fmt);
+            return nullptr;
+        }
+    }
+    return fmt;
+}
diff --git a/tests/media/jni/NativeMediaCommon.h b/tests/media/jni/NativeMediaCommon.h
index d50d4fe..08708db 100644
--- a/tests/media/jni/NativeMediaCommon.h
+++ b/tests/media/jni/NativeMediaCommon.h
@@ -83,6 +83,7 @@
 // common utility functions
 bool isCSDIdentical(AMediaFormat* refFormat, AMediaFormat* testFormat);
 bool isFormatSimilar(AMediaFormat* refFormat, AMediaFormat* testFormat);
+AMediaFormat* deSerializeMediaFormat(const char* msg, const char* separator);
 bool isMediaTypeOutputUnAffectedBySeek(const char* mediaType);
 
 template <class T>
diff --git a/tests/media/src/android/mediav2/cts/AudioEncoderTest.java b/tests/media/src/android/mediav2/cts/AudioEncoderTest.java
index 12b53d4..f4f1899 100644
--- a/tests/media/src/android/mediav2/cts/AudioEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/AudioEncoderTest.java
@@ -27,8 +27,8 @@
 import android.media.MediaCodec;
 import android.media.MediaFormat;
 import android.mediav2.common.cts.CodecDecoderTestBase;
+import android.mediav2.common.cts.CodecEncoderTestBase;
 import android.mediav2.common.cts.EncoderConfigParams;
-import android.mediav2.common.cts.EncoderTestBase;
 import android.mediav2.common.cts.OutputManager;
 
 import androidx.test.filters.LargeTest;
@@ -61,7 +61,7 @@
  * </ul>
  */
 @RunWith(Parameterized.class)
-public class AudioEncoderTest extends EncoderTestBase {
+public class AudioEncoderTest extends CodecEncoderTestBase {
     public AudioEncoderTest(String encoder, String mediaType, EncoderConfigParams encCfgParams,
             @SuppressWarnings("unused") String testLabel, String allTestParams) {
         super(encoder, mediaType, new EncoderConfigParams[]{encCfgParams}, allTestParams);
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
index c058f5f..445642f 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderSurfaceTest.java
@@ -19,6 +19,10 @@
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
+import static android.mediav2.common.cts.CodecEncoderTestBase.ACCEPTABLE_WIRELESS_TX_QUALITY;
+import static android.mediav2.common.cts.CodecEncoderTestBase.colorFormatToString;
+import static android.mediav2.common.cts.CodecEncoderTestBase.getMuxerFormatForMediaType;
+import static android.mediav2.common.cts.CodecEncoderTestBase.getTempFilePath;
 import static android.mediav2.common.cts.CodecTestBase.hasSupportForColorFormat;
 import static android.mediav2.common.cts.CodecTestBase.isHardwareAcceleratedCodec;
 import static android.mediav2.common.cts.CodecTestBase.isSoftwareCodec;
@@ -37,7 +41,9 @@
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
 import android.mediav2.common.cts.CodecAsyncHandler;
+import android.mediav2.common.cts.CodecEncoderTestBase;
 import android.mediav2.common.cts.CodecTestBase;
+import android.mediav2.common.cts.EncoderConfigParams;
 import android.mediav2.common.cts.OutputManager;
 import android.util.Log;
 import android.util.Pair;
@@ -93,25 +99,23 @@
     private static final String MEDIA_DIR = WorkDir.getMediaDirString();
     private static final boolean ENABLE_LOGS = false;
 
-    private final String mCompName;
-    private final String mMime;
+    private final String mEncoderName;
+    private final String mEncMediaType;
     private final String mTestFile;
-    private final int mBitrate;
-    private final int mFrameRate;
-    private final int mMaxBFrames;
-    private final boolean mTestToneMap;
+    private final EncoderConfigParams mEncCfgParams;
     private final int mColorFormat;
-    private int mLatency;
-    private boolean mReviseLatency;
-    private MediaFormat mEncoderFormat;
+    private final boolean mTestToneMap;
+    private final String mTestArgs;
 
     private MediaExtractor mExtractor;
+    private String mTestFileMediaType;
     private MediaCodec mEncoder;
-    private CodecAsyncHandler mAsyncHandleEncoder;
+    private MediaFormat mEncoderFormat;
+    private final CodecAsyncHandler mAsyncHandleEncoder = new CodecAsyncHandler();
     private String mDecoderName;
     private MediaCodec mDecoder;
     private MediaFormat mDecoderFormat;
-    private CodecAsyncHandler mAsyncHandleDecoder;
+    private final CodecAsyncHandler mAsyncHandleDecoder = new CodecAsyncHandler();
     private boolean mIsCodecInAsyncMode;
     private boolean mSignalEOSWithLastFrame;
     private boolean mSawDecInputEOS;
@@ -120,10 +124,11 @@
     private int mDecInputCount;
     private int mDecOutputCount;
     private int mEncOutputCount;
+    private int mLatency;
+    private boolean mReviseLatency;
 
-    private String mTestArgs;
-    private StringBuilder mTestConfig = new StringBuilder();
-    private StringBuilder mTestEnv = new StringBuilder();
+    private final StringBuilder mTestConfig = new StringBuilder();
+    private final StringBuilder mTestEnv = new StringBuilder();
 
     private boolean mSaveToMem;
     private OutputManager mOutputBuff;
@@ -140,41 +145,33 @@
         CodecTestBase.mimeSelKeys = args.getString(CodecTestBase.MIME_SEL_KEY);
     }
 
-    public CodecEncoderSurfaceTest(String encoder, String mime, String testFile, int bitrate,
-            int frameRate, boolean testToneMap, int colorFormat, int maxBFrames,
-            String allTestParams) {
-        mCompName = encoder;
-        mMime = mime;
+    public CodecEncoderSurfaceTest(String encoder, String mediaType, String testFile,
+            EncoderConfigParams encCfgParams, int colorFormat, boolean testToneMap,
+            @SuppressWarnings("unused") String testLabel, String allTestParams) {
+        mEncoderName = encoder;
+        mEncMediaType = mediaType;
         mTestFile = MEDIA_DIR + testFile;
-        mBitrate = bitrate;
-        mFrameRate = frameRate;
-        mTestToneMap = testToneMap;
+        mEncCfgParams = encCfgParams;
         mColorFormat = colorFormat;
+        mTestToneMap = testToneMap;
         mTestArgs = allTestParams;
-        mMaxBFrames = maxBFrames;
-        mLatency = mMaxBFrames;
+        mLatency = mEncCfgParams.mMaxBFrames;
         mReviseLatency = false;
-        mAsyncHandleDecoder = new CodecAsyncHandler();
-        mAsyncHandleEncoder = new CodecAsyncHandler();
     }
 
     @Rule
     public TestName mTestName = new TestName();
 
     @Before
-    public void setUp() throws IOException {
+    public void setUp() throws IOException, CloneNotSupportedException {
         mTestConfig.setLength(0);
         mTestConfig.append("\n##################       Test Details        ####################\n");
         mTestConfig.append("Test Name :- ").append(mTestName.getMethodName()).append("\n");
         mTestConfig.append("Test Parameters :- ").append(mTestArgs).append("\n");
-        if (mCompName.startsWith(CodecTestBase.INVALID_CODEC)) {
+        if (mEncoderName.startsWith(CodecTestBase.INVALID_CODEC)) {
             fail("no valid component available for current test. \n" + mTestConfig);
         }
         mDecoderFormat = setUpSource(mTestFile);
-        if (mTestToneMap) {
-            mDecoderFormat.setInteger(MediaFormat.KEY_COLOR_TRANSFER_REQUEST,
-                    MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
-        }
         ArrayList<MediaFormat> decoderFormatList = new ArrayList<>();
         decoderFormatList.add(mDecoderFormat);
         String decoderMediaType = mDecoderFormat.getString(MediaFormat.KEY_MIME);
@@ -182,8 +179,8 @@
                 mTestFile.contains("10bit")) {
             // Check if encoder is capable of supporting HDR profiles.
             // Previous check doesn't verify this as profile isn't set in the format
-            Assume.assumeTrue(mCompName + " doesn't support HDR encoding",
-                    CodecTestBase.doesCodecSupportHDRProfile(mCompName, mMime));
+            Assume.assumeTrue(mEncoderName + " doesn't support HDR encoding",
+                    CodecTestBase.doesCodecSupportHDRProfile(mEncoderName, mEncMediaType));
         }
 
         MediaCodecList codecList = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
@@ -193,9 +190,9 @@
 
         if (mColorFormat == COLOR_FormatSurface) {
             // TODO(b/253492870) Remove the following assumption check once this is supported
-            Assume.assumeFalse(
-                    mDecoderName + "is hardware accelerated and " + mCompName + "is software only.",
-                    isHardwareAcceleratedCodec(mDecoderName) && isSoftwareCodec(mCompName));
+            Assume.assumeFalse(mDecoderName + "is hardware accelerated and " + mEncoderName
+                            + "is software only.",
+                    isHardwareAcceleratedCodec(mDecoderName) && isSoftwareCodec(mEncoderName));
         } else {
             // findDecoderForFormat() ignores color-format and decoder returned may not be
             // supporting the color format set in mDecoderFormat. Following check will
@@ -210,8 +207,21 @@
                         decoderSupportsColorFormat);
             }
         }
+        EncoderConfigParams.Builder foreman = mEncCfgParams.getBuilder()
+                .setWidth(mDecoderFormat.getInteger(MediaFormat.KEY_WIDTH))
+                .setHeight(mDecoderFormat.getInteger(MediaFormat.KEY_HEIGHT));
+        mEncoderFormat = foreman.build().getFormat();
+    }
 
-        mEncoderFormat = setUpEncoderFormat(mDecoderFormat);
+    private static EncoderConfigParams getVideoEncoderCfgParams(String mediaType, int bitRate,
+            int frameRate, int bitDepth, int maxBFrames) {
+        return new EncoderConfigParams.Builder(mediaType)
+                .setBitRate(bitRate)
+                .setFrameRate(frameRate)
+                .setColorFormat(COLOR_FormatSurface)
+                .setInputBitDepth(bitDepth)
+                .setMaxBFrames(maxBFrames)
+                .build();
     }
 
     @After
@@ -238,7 +248,7 @@
         }
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{5}_{7})")
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{6})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = false;
@@ -280,45 +290,58 @@
                         512000, 30, true},
         }));
 
-        int[] argsColorFormats = {COLOR_FormatSurface, COLOR_FormatYUV420Flexible};
+        int[] colorFormats = {COLOR_FormatSurface, COLOR_FormatYUV420Flexible};
         int[] maxBFrames = {0, 2};
-        int argLength = args.get(0).length;
         for (Object[] arg : args) {
-            for (int colorFormat : argsColorFormats) {
+            final String mediaType = (String) arg[0];
+            final int br = (int) arg[2];
+            final int fps = (int) arg[3];
+            for (int colorFormat : colorFormats) {
                 for (int maxBFrame : maxBFrames) {
-                    String mediaType = arg[0].toString();
                     if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)
                             && !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)
                             && maxBFrame != 0) {
                         continue;
                     }
-                    Object[] argUpdate = new Object[argLength + 2];
-                    System.arraycopy(arg, 0, argUpdate, 0, argLength);
-                    argUpdate[argLength] = colorFormat;
-                    argUpdate[argLength + 1] = maxBFrame;
-                    exhaustiveArgsList.add(argUpdate);
+                    Object[] testArgs = new Object[6];
+                    testArgs[0] = arg[0];
+                    testArgs[1] = arg[1];
+                    testArgs[2] = getVideoEncoderCfgParams(mediaType, br, fps, 8, maxBFrame);
+                    testArgs[3] = colorFormat;
+                    testArgs[4] = arg[4];
+                    testArgs[5] = String.format("%dkbps_%dfps_%s", br / 1000, fps,
+                            colorFormatToString(colorFormat, 8));
+                    exhaustiveArgsList.add(testArgs);
                 }
             }
         }
         // P010 support was added in Android T, hence limit the following tests to Android T and
         // above
         if (CodecTestBase.IS_AT_LEAST_T) {
-            int[] argsHighBitDepthColorFormats = {COLOR_FormatSurface, COLOR_FormatYUVP010};
-            int argsHighBitDepthLength = argsHighBitDepth.get(0).length;
+            int[] colorFormatsHbd = {COLOR_FormatSurface, COLOR_FormatYUVP010};
             for (Object[] arg : argsHighBitDepth) {
-                for (int colorFormat : argsHighBitDepthColorFormats) {
+                final String mediaType = (String) arg[0];
+                final int br = (int) arg[2];
+                final int fps = (int) arg[3];
+                final boolean toneMap = (boolean) arg[4];
+                for (int colorFormat : colorFormatsHbd) {
                     for (int maxBFrame : maxBFrames) {
-                        String mediaType = arg[0].toString();
                         if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)
                                 && !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)
                                 && maxBFrame != 0) {
                             continue;
                         }
-                        Object[] argUpdate = new Object[argsHighBitDepthLength + 2];
-                        System.arraycopy(arg, 0, argUpdate, 0, argsHighBitDepthLength);
-                        argUpdate[argsHighBitDepthLength] = colorFormat;
-                        argUpdate[argsHighBitDepthLength + 1] = maxBFrame;
-                        exhaustiveArgsList.add(argUpdate);
+                        Object[] testArgs = new Object[6];
+                        testArgs[0] = arg[0];
+                        testArgs[1] = arg[1];
+                        testArgs[2] = getVideoEncoderCfgParams(mediaType, br, fps, toneMap ? 8 : 10,
+                                maxBFrame);
+                        testArgs[3] = colorFormat;
+                        testArgs[4] = arg[4];
+                        testArgs[5] = String.format("%dkbps_%dfps_%s_%s", br / 1000, fps,
+                                colorFormatToString(colorFormat, 10),
+                                toneMap ? "tonemapyes" : "tonemapno");
+                        exhaustiveArgsList.add(testArgs);
                     }
                 }
             }
@@ -339,10 +362,13 @@
             MediaFormat format = mExtractor.getTrackFormat(trackID);
             String mime = format.getString(MediaFormat.KEY_MIME);
             if (mime.startsWith("video/")) {
+                mTestFileMediaType = mime;
                 mExtractor.selectTrack(trackID);
-                ArrayList<MediaFormat> formatList = new ArrayList<>();
-                formatList.add(format);
                 format.setInteger(MediaFormat.KEY_COLOR_FORMAT, mColorFormat);
+                if (mTestToneMap) {
+                    format.setInteger(MediaFormat.KEY_COLOR_TRANSFER_REQUEST,
+                            MediaFormat.COLOR_TRANSFER_SDR_VIDEO);
+                }
                 return format;
             }
         }
@@ -379,7 +405,7 @@
         mDecoder.configure(decFormat, mSurface, null, 0);
         mTestEnv.setLength(0);
         mTestEnv.append("###################      Test Environment       #####################\n");
-        mTestEnv.append(String.format("Encoder under test :- %s \n", mCompName));
+        mTestEnv.append(String.format("Encoder under test :- %s \n", mEncoderName));
         mTestEnv.append(String.format("Format under test :- %s \n", encFormat));
         mTestEnv.append(String.format("Encoder is fed with output of :- %s \n", mDecoderName));
         mTestEnv.append(String.format("Format of Decoder Input :- %s", decFormat));
@@ -633,21 +659,6 @@
         }
     }
 
-    private MediaFormat setUpEncoderFormat(MediaFormat decoderFormat) {
-        MediaFormat encoderFormat = new MediaFormat();
-        encoderFormat.setString(MediaFormat.KEY_MIME, mMime);
-        encoderFormat.setInteger(MediaFormat.KEY_WIDTH,
-                decoderFormat.getInteger(MediaFormat.KEY_WIDTH));
-        encoderFormat.setInteger(MediaFormat.KEY_HEIGHT,
-                decoderFormat.getInteger(MediaFormat.KEY_HEIGHT));
-        encoderFormat.setInteger(MediaFormat.KEY_FRAME_RATE, mFrameRate);
-        encoderFormat.setInteger(MediaFormat.KEY_BIT_RATE, mBitrate);
-        encoderFormat.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 1.0f);
-        encoderFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, COLOR_FormatSurface);
-        encoderFormat.setInteger(MediaFormat.KEY_MAX_B_FRAMES, mMaxBFrames);
-        return encoderFormat;
-    }
-
     private void validateToneMappedFormat(MediaFormat format, String descriptor) {
         assertEquals("unexpected color transfer in " + descriptor + " after tone mapping",
                 MediaFormat.COLOR_TRANSFER_SDR_VIDEO,
@@ -657,7 +668,7 @@
                 format.getInteger(MediaFormat.KEY_COLOR_STANDARD, 0));
 
         int profile = format.getInteger(MediaFormat.KEY_PROFILE, -1);
-        int[] profileArray = CodecTestBase.PROFILE_HDR_MAP.get(mMime);
+        int[] profileArray = CodecTestBase.PROFILE_HDR_MAP.get(mEncMediaType);
         assertFalse(descriptor + " must not contain HDR profile after tone mapping",
                 IntStream.of(profileArray).anyMatch(x -> x == profile));
     }
@@ -678,8 +689,11 @@
         mDecoder = MediaCodec.createByCodecName(mDecoderName);
         String tmpPath = null;
         boolean muxOutput = true;
+        if (mEncMediaType.equals(MediaFormat.MIMETYPE_VIDEO_AV1) && CodecTestBase.IS_BEFORE_U) {
+            muxOutput = false;
+        }
         {
-            mEncoder = MediaCodec.createByCodecName(mCompName);
+            mEncoder = MediaCodec.createByCodecName(mEncoderName);
             /* TODO(b/149027258) */
             mSaveToMem = false;
             OutputManager ref = new OutputManager();
@@ -691,15 +705,8 @@
                 mOutputBuff = loopCounter == 0 ? ref : test;
                 mOutputBuff.reset();
                 if (muxOutput && loopCounter == 0) {
-                    int muxerFormat;
-                    if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
-                            mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
-                        muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_WEBM;
-                        tmpPath = File.createTempFile("tmp", ".webm").getAbsolutePath();
-                    } else {
-                        muxerFormat = MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4;
-                        tmpPath = File.createTempFile("tmp", ".mp4").getAbsolutePath();
-                    }
+                    int muxerFormat = getMuxerFormatForMediaType(mEncMediaType);
+                    tmpPath = getTempFilePath(mEncCfgParams.mInputBitDepth > 8 ? "10bit" : "");
                     mMuxer = new MediaMuxer(tmpPath, muxerFormat);
                 }
                 configureCodec(mDecoderFormat, mEncoderFormat, isAsync, false);
@@ -758,11 +765,12 @@
                             + test.getErrMsg());
                 }
                 if (loopCounter == 0 &&
-                        !ref.isOutPtsListIdenticalToInpPtsList((mMaxBFrames != 0))) {
+                        !ref.isOutPtsListIdenticalToInpPtsList((mEncCfgParams.mMaxBFrames != 0))) {
                     fail("Input pts list and Output pts list are not identical \n" + mTestConfig
                             + mTestEnv + ref.getErrMsg());
                 }*/
-                if (mMaxBFrames == 0 && !mOutputBuff.isPtsStrictlyIncreasing(Long.MIN_VALUE)) {
+                if (mEncCfgParams.mMaxBFrames == 0 && !mOutputBuff.isPtsStrictlyIncreasing(
+                        Long.MIN_VALUE)) {
                     fail("Output timestamps are not strictly increasing \n" + mTestConfig + mTestEnv
                             + mOutputBuff.getErrMsg());
                 }
@@ -786,11 +794,16 @@
         }
         mDecoder.release();
         mExtractor.release();
+        // Skip stream validation as there is no reference for tone mapped input
+        if (muxOutput && !mTestToneMap) {
+            CodecEncoderTestBase.validateEncodedPSNR(mTestFileMediaType, mTestFile, mEncMediaType,
+                    tmpPath, false, false, ACCEPTABLE_WIRELESS_TX_QUALITY);
+        }
         if (muxOutput) new File(tmpPath).delete();
     }
 
     private native boolean nativeTestSimpleEncode(String encoder, String decoder, String mime,
-            String testFile, String muxFile, int bitrate, int framerate, int colorFormat,
+            String testFile, String muxFile, int colorFormat, String cfgParams, String separator,
             StringBuilder retMsg);
 
     /**
@@ -799,20 +812,22 @@
     @ApiTest(apis = {"MediaCodecInfo.CodecCapabilities#COLOR_FormatSurface"})
     @LargeTest
     @Test(timeout = CodecTestBase.PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testSimpleEncodeFromSurfaceNative() throws IOException {
+    public void testSimpleEncodeFromSurfaceNative() throws IOException, InterruptedException {
         assumeFalse("tone mapping tests are skipped in native mode", mTestToneMap);
-        {
-            String tmpPath;
-            if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP8) ||
-                    mMime.equals(MediaFormat.MIMETYPE_VIDEO_VP9)) {
-                tmpPath = File.createTempFile("tmp", ".webm").getAbsolutePath();
-            } else {
-                tmpPath = File.createTempFile("tmp", ".mp4").getAbsolutePath();
-            }
-            int colorFormat = mDecoderFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT, -1);
-            boolean isPass = nativeTestSimpleEncode(mCompName, mDecoderName, mMime, mTestFile,
-                    tmpPath, mBitrate, mFrameRate, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
+        String tmpPath = null;
+        if (!mEncMediaType.equals(MediaFormat.MIMETYPE_VIDEO_AV1) || CodecTestBase.IS_AT_LEAST_U) {
+            tmpPath = getTempFilePath(mEncCfgParams.mInputBitDepth > 8 ? "10bit" : "");
+        }
+        int colorFormat = mDecoderFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT, -1);
+        boolean isPass = nativeTestSimpleEncode(mEncoderName, mDecoderName, mEncMediaType,
+                mTestFile, tmpPath, colorFormat,
+                EncoderConfigParams.serializeMediaFormat(mEncoderFormat),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
+        if (tmpPath != null) {
+            CodecEncoderTestBase.validateEncodedPSNR(mTestFileMediaType, mTestFile, mEncMediaType,
+                    tmpPath, false, false, ACCEPTABLE_WIRELESS_TX_QUALITY);
+            new File(tmpPath).delete();
         }
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
index 06dc853..cc86e76 100644
--- a/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/CodecEncoderTest.java
@@ -17,13 +17,14 @@
 package android.mediav2.cts;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import android.media.MediaCodec;
-import android.media.MediaCodecInfo;
 import android.media.MediaFormat;
 import android.mediav2.common.cts.CodecEncoderTestBase;
+import android.mediav2.common.cts.EncoderConfigParams;
 import android.mediav2.common.cts.OutputManager;
 import android.os.Bundle;
 import android.util.Log;
@@ -34,6 +35,7 @@
 import com.android.compatibility.common.util.ApiTest;
 
 import org.junit.Assume;
+import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -71,26 +73,24 @@
 @RunWith(Parameterized.class)
 public class CodecEncoderTest extends CodecEncoderTestBase {
     private static final String LOG_TAG = CodecEncoderTest.class.getSimpleName();
-    private static ArrayList<String> sAdaptiveBitrateMimeList = new ArrayList<>();
+    private static final ArrayList<String> ABR_MEDIATYPE_LIST = new ArrayList<>();
 
     private int mNumSyncFramesReceived;
-    private ArrayList<Integer> mSyncFramesPos;
+    private final ArrayList<Integer> mSyncFramesPos = new ArrayList<>();
 
     static {
         System.loadLibrary("ctsmediav2codecenc_jni");
 
-        sAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_AVC);
-        sAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
-        sAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP8);
-        sAdaptiveBitrateMimeList.add(MediaFormat.MIMETYPE_VIDEO_VP9);
+        ABR_MEDIATYPE_LIST.add(MediaFormat.MIMETYPE_VIDEO_AVC);
+        ABR_MEDIATYPE_LIST.add(MediaFormat.MIMETYPE_VIDEO_HEVC);
+        ABR_MEDIATYPE_LIST.add(MediaFormat.MIMETYPE_VIDEO_VP8);
+        ABR_MEDIATYPE_LIST.add(MediaFormat.MIMETYPE_VIDEO_VP9);
+        ABR_MEDIATYPE_LIST.add(MediaFormat.MIMETYPE_VIDEO_AV1);
     }
 
-    public CodecEncoderTest(String encoder, String mime, int[] bitrates, int[] encoderInfo1,
-            int[] encoderInfo2, int maxBFrames, String allTestParams) {
-        super(encoder, mime, bitrates, encoderInfo1, encoderInfo2,
-                EncoderInput.getRawResource(mime, /* isHighBitDepth */ false), allTestParams);
-        mMaxBFrames = maxBFrames;
-        mSyncFramesPos = new ArrayList<>();
+    public CodecEncoderTest(String encoder, String mime, EncoderConfigParams[] cfgParams,
+            String allTestParams) {
+        super(encoder, mime, cfgParams, allTestParams);
     }
 
     @Override
@@ -126,62 +126,156 @@
         mCodec.setParameters(bitrateUpdate);
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{5})")
+    private static EncoderConfigParams getVideoEncoderCfgParam(String mediaType, int width,
+            int height, int bitRate, int maxBFrames) {
+        return new EncoderConfigParams.Builder(mediaType).setWidth(width).setHeight(height)
+                .setMaxBFrames(maxBFrames).setBitRate(bitRate).build();
+    }
+
+    private static EncoderConfigParams getAudioEncoderCfgParam(String mediaType, int sampleRate,
+            int channelCount, int qualityPreset) {
+        EncoderConfigParams.Builder foreman =
+                new EncoderConfigParams.Builder(mediaType).setSampleRate(sampleRate)
+                        .setChannelCount(channelCount);
+        if (mediaType.equals(MediaFormat.MIMETYPE_AUDIO_FLAC)) {
+            foreman = foreman.setCompressionLevel(qualityPreset);
+        } else {
+            foreman = foreman.setBitRate(qualityPreset);
+        }
+        return foreman.build();
+    }
+
+    private static EncoderConfigParams[] getAacCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AAC, 8000, 1, 128000);
+        params[1] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AAC, 48000, 2, 128000);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getOpusCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_OPUS, 16000, 1, 64000);
+        params[1] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_OPUS, 16000, 1, 128000);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getAmrnbCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AMR_NB, 8000, 1, 4750);
+        params[1] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AMR_NB, 8000, 1, 12200);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getAmrwbCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AMR_WB, 16000, 1, 6600);
+        params[1] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_AMR_WB, 16000, 1, 23850);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getFlacCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_FLAC, 8000, 1, 6);
+        params[1] = getAudioEncoderCfgParam(MediaFormat.MIMETYPE_AUDIO_FLAC, 48000, 2, 5);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getH263CfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_H263, 176, 144, 32000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_H263, 176, 144, 64000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getMpeg4CfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_MPEG4, 176, 144, 32000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_MPEG4, 176, 144, 64000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getAvcCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AVC, 176, 144, 512000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AVC, 352, 288, 512000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getHevcCfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_HEVC, 176, 144, 512000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_HEVC, 352, 288, 512000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getAvcCfgParamsWithBFrames() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AVC, 320, 240, 512000, 2);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AVC, 480, 360, 768000, 2);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getHevcCfgParamsWithBFrames() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_HEVC, 320, 240, 384000, 2);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_HEVC, 480, 360, 512000, 2);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getVp8CfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_VP8, 176, 144, 512000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_VP8, 352, 288, 512000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getVp9CfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_VP9, 176, 144, 512000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_VP9, 352, 288, 512000, 0);
+        return params;
+    }
+
+    private static EncoderConfigParams[] getAv1CfgParams() {
+        EncoderConfigParams[] params = new EncoderConfigParams[2];
+        params[0] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AV1, 176, 144, 512000, 0);
+        params[1] = getVideoEncoderCfgParam(MediaFormat.MIMETYPE_VIDEO_AV1, 352, 288, 512000, 0);
+        return params;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1})")
     public static Collection<Object[]> input() {
         final boolean isEncoder = true;
         final boolean needAudio = true;
         final boolean needVideo = true;
-        final List<Object[]> exhaustiveArgsList = new ArrayList<>();
-        final List<Object[]> args = new ArrayList<>(Arrays.asList(new Object[][]{
-                // Audio - CodecMime, arrays of bit-rates, sample rates, channel counts
-                {MediaFormat.MIMETYPE_AUDIO_AAC, new int[]{128000}, new int[]{8000, 48000},
-                        new int[]{1, 2}},
-                {MediaFormat.MIMETYPE_AUDIO_OPUS, new int[]{6600, 23850}, new int[]{16000},
-                        new int[]{1}},
-                {MediaFormat.MIMETYPE_AUDIO_AMR_NB, new int[]{4750, 12200}, new int[]{8000},
-                        new int[]{1}},
-                {MediaFormat.MIMETYPE_AUDIO_AMR_WB, new int[]{6600, 23850}, new int[]{16000},
-                        new int[]{1}},
-                {MediaFormat.MIMETYPE_AUDIO_FLAC, new int[]{5}, new int[]{8000, 48000},
-                        new int[]{1, 2}},
-
-                // Video - CodecMime, arrays of bit-rates, height, width
-                {MediaFormat.MIMETYPE_VIDEO_H263, new int[]{32000, 64000}, new int[]{176},
-                        new int[]{144}},
-                {MediaFormat.MIMETYPE_VIDEO_MPEG4, new int[]{32000, 64000}, new int[]{176},
-                        new int[]{144}},
-                {MediaFormat.MIMETYPE_VIDEO_AVC, new int[]{512000}, new int[]{176, 352},
-                        new int[]{144, 288}},
-                {MediaFormat.MIMETYPE_VIDEO_HEVC, new int[]{512000}, new int[]{176, 352},
-                        new int[]{144, 288}},
-                {MediaFormat.MIMETYPE_VIDEO_VP8, new int[]{512000}, new int[]{176, 352},
-                        new int[]{144, 288}},
-                {MediaFormat.MIMETYPE_VIDEO_VP9, new int[]{512000}, new int[]{176, 352},
-                        new int[]{144, 288}},
-                {MediaFormat.MIMETYPE_VIDEO_AV1, new int[]{512000}, new int[]{176, 352},
-                        new int[]{144, 288}},
+        final List<Object[]> exhaustiveArgsList = new ArrayList<>(Arrays.asList(new Object[][]{
+                // mediaType, cfg params
+                {MediaFormat.MIMETYPE_AUDIO_AAC, getAacCfgParams()},
+                {MediaFormat.MIMETYPE_AUDIO_OPUS, getOpusCfgParams()},
+                {MediaFormat.MIMETYPE_AUDIO_AMR_NB, getAmrnbCfgParams()},
+                {MediaFormat.MIMETYPE_AUDIO_AMR_WB, getAmrwbCfgParams()},
+                {MediaFormat.MIMETYPE_AUDIO_FLAC, getFlacCfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_H263, getH263CfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_MPEG4, getMpeg4CfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_AVC, getAvcCfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_AVC, getAvcCfgParamsWithBFrames()},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, getHevcCfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, getHevcCfgParamsWithBFrames()},
+                {MediaFormat.MIMETYPE_VIDEO_VP8, getVp8CfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, getVp9CfgParams()},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, getAv1CfgParams()},
         }));
-
-        int[] maxBFrames = {0, 2};
-        int argLength = args.get(0).length;
-        for (Object[] arg : args) {
-            for (int maxBFrame : maxBFrames) {
-                String mediaType = arg[0].toString();
-                if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)
-                        && !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)
-                        && maxBFrame != 0) {
-                    continue;
-                }
-                Object[] argUpdate = new Object[argLength + 1];
-                System.arraycopy(arg, 0, argUpdate, 0, argLength);
-                argUpdate[argLength] = maxBFrame;
-                exhaustiveArgsList.add(argUpdate);
-            }
-        }
-
         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, true);
     }
 
+    @Before
+    public void setUp() throws IOException {
+        mActiveEncCfg = mEncCfgParams[0];
+        mActiveRawRes = EncoderInput.getRawResource(mActiveEncCfg);
+        assertNotNull("no raw resource found for testing config : " + mActiveEncCfg + mTestConfig
+                + mTestEnv, mActiveRawRes);
+    }
+
     /**
      * Checks if the component under test can encode the test file correctly. The encoding
      * happens in synchronous, asynchronous mode, eos flag signalled with last raw frame and
@@ -198,7 +292,6 @@
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testSimpleEncode() throws IOException, InterruptedException {
-        setUpParams(1);
         boolean[] boolStates = {true, false};
         setUpSource(mActiveRawRes.mFileName);
         OutputManager ref = new OutputManager();
@@ -210,7 +303,8 @@
             assertTrue("error! codec canonical name is null or empty",
                     mCodec.getCanonicalName() != null && !mCodec.getCanonicalName().isEmpty());
             mSaveToMem = false; /* TODO(b/149027258) */
-            for (MediaFormat format : mFormats) {
+            MediaFormat format = mActiveEncCfg.getFormat();
+            {
                 int loopCounter = 0;
                 for (boolean eosType : boolStates) {
                     for (boolean isAsync : boolStates) {
@@ -240,7 +334,7 @@
     }
 
     private native boolean nativeTestSimpleEncode(String encoder, String file, String mime,
-            int[] list0, int[] list1, int[] list2, int colorFormat, StringBuilder retMsg);
+            String cfgParams, String separator, StringBuilder retMsg);
 
     /**
      * Test is similar to {@link #testSimpleEncode()} but uses ndk api
@@ -249,18 +343,18 @@
             "android.media.AudioFormat#ENCODING_PCM_16BIT"})
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testSimpleEncodeNative() throws IOException {
-        int colorFormat = -1;
-        {
-            if (mIsVideo) {
-                colorFormat = findByteBufferColorFormat(mCodecName, mMime);
-                assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
-                        colorFormat != -1);
-            }
-            boolean isPass = nativeTestSimpleEncode(mCodecName, mActiveRawRes.mFileName, mMime,
-                    mBitrates, mEncParamList1, mEncParamList2, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
+    public void testSimpleEncodeNative() throws IOException, CloneNotSupportedException {
+        MediaFormat format = mActiveEncCfg.getFormat();
+        if (mIsVideo) {
+            int colorFormat = findByteBufferColorFormat(mCodecName, mMime);
+            assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
+                    colorFormat != -1);
+            format = mActiveEncCfg.getBuilder().setColorFormat(colorFormat).build().getFormat();
         }
+        boolean isPass = nativeTestSimpleEncode(mCodecName, mActiveRawRes.mFileName, mMime,
+                EncoderConfigParams.serializeMediaFormat(format),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
     }
 
     /**
@@ -296,25 +390,23 @@
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testReconfigure() throws IOException, InterruptedException {
-        setUpParams(2);
-        setUpSource(mActiveRawRes.mFileName);
+
         boolean[] boolStates = {true, false};
         {
             boolean saveToMem = false; /* TODO(b/149027258) */
             OutputManager configRef = null;
             OutputManager configTest = null;
-            if (mFormats.size() > 1) {
-                MediaFormat format = mFormats.get(1);
-                encodeToMemory(mActiveRawRes.mFileName, mCodecName, Integer.MAX_VALUE,
-                        format, saveToMem);
+            if (mEncCfgParams.length > 1) {
+                encodeToMemory(mCodecName, mEncCfgParams[1], mActiveRawRes, Integer.MAX_VALUE,
+                        saveToMem, mMuxOutput);
                 configRef = mOutputBuff;
                 configTest = new OutputManager(configRef.getSharedErrorLogs());
             }
-            MediaFormat format = mFormats.get(0);
-            encodeToMemory(mActiveRawRes.mFileName, mCodecName, Integer.MAX_VALUE,
-                    format, saveToMem);
+            encodeToMemory(mCodecName, mEncCfgParams[0], mActiveRawRes, Integer.MAX_VALUE,
+                    saveToMem, mMuxOutput);
             OutputManager ref = mOutputBuff;
             OutputManager test = new OutputManager(ref.getSharedErrorLogs());
+            MediaFormat format = mEncCfgParams[0].getFormat();
             mCodec = MediaCodec.createByCodecName(mCodecName);
             for (boolean isAsync : boolStates) {
                 mOutputBuff = test;
@@ -363,9 +455,9 @@
                 }
 
                 /* test reconfigure codec for new format */
-                if (mFormats.size() > 1) {
+                if (mEncCfgParams.length > 1) {
                     mOutputBuff = configTest;
-                    reConfigureCodec(mFormats.get(1), isAsync, false, true);
+                    reConfigureCodec(mEncCfgParams[1].getFormat(), isAsync, false, true);
                     mCodec.start();
                     configTest.reset();
                     doWork(Integer.MAX_VALUE);
@@ -386,7 +478,7 @@
     }
 
     private native boolean nativeTestReconfigure(String encoder, String file, String mime,
-            int[] list0, int[] list1, int[] list2, int colorFormat, StringBuilder retMsg);
+            String cfgParams, String cfgReconfigParams, String separator, StringBuilder retMsg);
 
     /**
      * Test is similar to {@link #testReconfigure()} but uses ndk api
@@ -395,17 +487,24 @@
     @ApiTest(apis = {"android.media.MediaCodec#configure"})
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testReconfigureNative() throws IOException {
-        int colorFormat = -1;
-        {
-            if (mIsVideo) {
-                colorFormat = findByteBufferColorFormat(mCodecName, mMime);
-                assertTrue("no valid color formats received", colorFormat != -1);
+    public void testReconfigureNative() throws IOException, CloneNotSupportedException {
+        MediaFormat format = mEncCfgParams[0].getFormat();
+        MediaFormat reconfigFormat = mEncCfgParams.length > 1 ? mEncCfgParams[1].getFormat() : null;
+        if (mIsVideo) {
+            int colorFormat = findByteBufferColorFormat(mCodecName, mMime);
+            assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
+                    colorFormat != -1);
+            format = mEncCfgParams[0].getBuilder().setColorFormat(colorFormat).build().getFormat();
+            if (mEncCfgParams.length > 1) {
+                reconfigFormat = mEncCfgParams[1].getBuilder().setColorFormat(colorFormat).build()
+                        .getFormat();
             }
-            boolean isPass = nativeTestReconfigure(mCodecName, mActiveRawRes.mFileName, mMime,
-                    mBitrates, mEncParamList1, mEncParamList2, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
         }
+        boolean isPass = nativeTestReconfigure(mCodecName, mActiveRawRes.mFileName, mMime,
+                EncoderConfigParams.serializeMediaFormat(format), reconfigFormat == null ? null :
+                        EncoderConfigParams.serializeMediaFormat(reconfigFormat),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
     }
 
     /**
@@ -417,7 +516,6 @@
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
     public void testOnlyEos() throws IOException, InterruptedException {
-        setUpParams(1);
         boolean[] boolStates = {true, false};
         OutputManager ref = new OutputManager();
         OutputManager test = new OutputManager(ref.getSharedErrorLogs());
@@ -425,8 +523,9 @@
             mCodec = MediaCodec.createByCodecName(mCodecName);
             mSaveToMem = false; /* TODO(b/149027258) */
             int loopCounter = 0;
+            MediaFormat format = mActiveEncCfg.getFormat();
             for (boolean isAsync : boolStates) {
-                configureCodec(mFormats.get(0), isAsync, false, true);
+                configureCodec(format, isAsync, false, true);
                 mOutputBuff = loopCounter == 0 ? ref : test;
                 mOutputBuff.reset();
                 mInfoList.clear();
@@ -446,8 +545,8 @@
         }
     }
 
-    private native boolean nativeTestOnlyEos(String encoder, String mime, int[] list0, int[] list1,
-            int[] list2, int colorFormat, StringBuilder retMsg);
+    private native boolean nativeTestOnlyEos(String encoder, String mime, String cfgParams,
+            String separator, StringBuilder retMsg);
 
     /**
      * Test is similar to {@link #testOnlyEos()} but uses ndk api
@@ -455,17 +554,18 @@
     @ApiTest(apis = "android.media.MediaCodec#BUFFER_FLAG_END_OF_STREAM")
     @SmallTest
     @Test(timeout = PER_TEST_TIMEOUT_SMALL_TEST_MS)
-    public void testOnlyEosNative() throws IOException {
-        int colorFormat = -1;
-        {
-            if (mIsVideo) {
-                colorFormat = findByteBufferColorFormat(mCodecName, mMime);
-                assertTrue("no valid color formats received", colorFormat != -1);
-            }
-            boolean isPass = nativeTestOnlyEos(mCodecName, mMime, mBitrates, mEncParamList1,
-                    mEncParamList2, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
+    public void testOnlyEosNative() throws IOException, CloneNotSupportedException {
+        MediaFormat format = mActiveEncCfg.getFormat();
+        if (mIsVideo) {
+            int colorFormat = findByteBufferColorFormat(mCodecName, mMime);
+            assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
+                    colorFormat != -1);
+            format = mActiveEncCfg.getBuilder().setColorFormat(colorFormat).build().getFormat();
         }
+        boolean isPass = nativeTestOnlyEos(mCodecName, mMime,
+                EncoderConfigParams.serializeMediaFormat(format),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
     }
 
     /**
@@ -477,20 +577,20 @@
     @ApiTest(apis = "android.media.MediaCodec#PARAMETER_KEY_REQUEST_SYNC_FRAME")
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testSetForceSyncFrame() throws IOException, InterruptedException {
+    public void testSetForceSyncFrame()
+            throws IOException, InterruptedException, CloneNotSupportedException {
         Assume.assumeTrue("Test is applicable only for video encoders", mIsVideo);
+        EncoderConfigParams currCfg = mActiveEncCfg.getBuilder().setKeyFrameInterval(500.f).build();
+        MediaFormat format = currCfg.getFormat();
         // Maximum allowed key frame interval variation from the target value.
-        final int MAX_KEYFRAME_INTERVAL_VARIATION = 3;
-        setUpParams(1);
-        boolean[] boolStates = {true, false};
+        final int maxKeyframeIntervalVariation = 3;
+        final int keyFrameInterval = 2; // force key frame every 2 seconds.
+        final int keyFramePos = currCfg.mFrameRate * keyFrameInterval;
+        final int numKeyFrameRequests = 7;
+
         setUpSource(mActiveRawRes.mFileName);
-        MediaFormat format = mFormats.get(0);
-        format.removeKey(MediaFormat.KEY_I_FRAME_INTERVAL);
-        format.setFloat(MediaFormat.KEY_I_FRAME_INTERVAL, 500.f);
-        final int KEY_FRAME_INTERVAL = 2; // force key frame every 2 seconds.
-        final int KEY_FRAME_POS = mFrameRate * KEY_FRAME_INTERVAL;
-        final int NUM_KEY_FRAME_REQUESTS = 7;
         mOutputBuff = new OutputManager();
+        boolean[] boolStates = {true, false};
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
             for (boolean isAsync : boolStates) {
@@ -498,11 +598,11 @@
                 mInfoList.clear();
                 configureCodec(format, isAsync, false, true);
                 mCodec.start();
-                for (int i = 0; i < NUM_KEY_FRAME_REQUESTS; i++) {
-                    doWork(KEY_FRAME_POS);
+                for (int i = 0; i < numKeyFrameRequests; i++) {
+                    doWork(keyFramePos);
                     if (mSawInputEOS) {
                         fail(String.format("Unable to encode %d frames as the input resource "
-                                + "contains only %d frames \n", KEY_FRAME_POS, mInputCount));
+                                + "contains only %d frames \n", keyFramePos, mInputCount));
                     }
                     forceSyncFrame();
                     mInputBufferReadOffset = 0;
@@ -513,17 +613,17 @@
                 if (false) mCodec.stop();
                 else mCodec.reset();
                 String msg = String.format("Received only %d key frames for %d key frame "
-                        + "requests \n", mNumSyncFramesReceived, NUM_KEY_FRAME_REQUESTS);
+                        + "requests \n", mNumSyncFramesReceived, numKeyFrameRequests);
                 assertTrue(msg + mTestConfig + mTestEnv,
-                        mNumSyncFramesReceived >= NUM_KEY_FRAME_REQUESTS);
-                for (int i = 0, expPos = 0, index = 0; i < NUM_KEY_FRAME_REQUESTS; i++) {
+                        mNumSyncFramesReceived >= numKeyFrameRequests);
+                for (int i = 0, expPos = 0, index = 0; i < numKeyFrameRequests; i++) {
                     int j = index;
                     for (; j < mSyncFramesPos.size(); j++) {
                         // Check key frame intervals:
                         // key frame position should not be greater than target value + 3
                         // key frame position should not be less than target value - 3
                         if (Math.abs(expPos - mSyncFramesPos.get(j)) <=
-                                MAX_KEYFRAME_INTERVAL_VARIATION) {
+                                maxKeyframeIntervalVariation) {
                             index = j;
                             break;
                         }
@@ -532,7 +632,7 @@
                         Log.w(LOG_TAG, "requested key frame at frame index " + expPos +
                                 " none found near by");
                     }
-                    expPos += KEY_FRAME_POS;
+                    expPos += keyFramePos;
                 }
             }
             mCodec.release();
@@ -540,7 +640,7 @@
     }
 
     private native boolean nativeTestSetForceSyncFrame(String encoder, String file, String mime,
-            int[] list0, int[] list1, int[] list2, int colorFormat, StringBuilder retMsg);
+            String cfgParams, String separator, StringBuilder retMsg);
 
     /**
      * Test is similar to {@link #testSetForceSyncFrame()} but uses ndk api
@@ -548,18 +648,19 @@
     @ApiTest(apis = "android.media.MediaCodec#PARAMETER_KEY_REQUEST_SYNC_FRAME")
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testSetForceSyncFrameNative() throws IOException {
+    public void testSetForceSyncFrameNative() throws IOException, CloneNotSupportedException {
         Assume.assumeTrue("Test is applicable only for encoders", mIsVideo);
-        int colorFormat = -1;
-        {
-            if (mIsVideo) {
-                colorFormat = findByteBufferColorFormat(mCodecName, mMime);
-                assertTrue("no valid color formats received", colorFormat != -1);
-            }
-            boolean isPass = nativeTestSetForceSyncFrame(mCodecName, mActiveRawRes.mFileName, mMime,
-                    mBitrates, mEncParamList1, mEncParamList2, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
-        }
+
+        int colorFormat = findByteBufferColorFormat(mCodecName, mMime);
+        assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
+                colorFormat != -1);
+        MediaFormat format =
+                mActiveEncCfg.getBuilder().setColorFormat(colorFormat).setKeyFrameInterval(500.f)
+                        .build().getFormat();
+        boolean isPass = nativeTestSetForceSyncFrame(mCodecName, mActiveRawRes.mFileName, mMime,
+                EncoderConfigParams.serializeMediaFormat(format),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
     }
 
     /**
@@ -574,30 +675,20 @@
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
     public void testAdaptiveBitRate() throws IOException, InterruptedException {
         Assume.assumeTrue("Skipping AdaptiveBitrate test for " + mMime,
-                sAdaptiveBitrateMimeList.contains(mMime));
-        setUpParams(1);
+                ABR_MEDIATYPE_LIST.contains(mMime));
+        MediaFormat format = mActiveEncCfg.getFormat();
+        final int adaptiveBrInterval = 3; // change br every 3 seconds.
+        final int adaptiveBrDurFrm = mActiveEncCfg.mFrameRate * adaptiveBrInterval;
+        final int brChangeRequests = 7;
+        // TODO(b/251265293) Reduce the allowed deviation after improving the test conditions
+        final float maxBitrateDeviation = 60.0f; // allowed bitrate deviation in %
+
         boolean[] boolStates = {true, false};
         setUpSource(mActiveRawRes.mFileName);
-        MediaFormat format = mFormats.get(0);
-        final int ADAPTIVE_BR_INTERVAL = 3; // change br every 3 seconds.
-        final int ADAPTIVE_BR_DUR_FRM = mFrameRate * ADAPTIVE_BR_INTERVAL;
-        final int BR_CHANGE_REQUESTS = 7;
-        // TODO(b/251265293) Reduce the allowed deviation after improving the test conditions
-        final float MAX_BITRATE_DEVIATION = 60.0f; // allowed bitrate deviation in %
         mOutputBuff = new OutputManager();
         mSaveToMem = true;
         {
             mCodec = MediaCodec.createByCodecName(mCodecName);
-            format.removeKey(MediaFormat.KEY_BITRATE_MODE);
-            MediaCodecInfo.EncoderCapabilities cap =
-                    mCodec.getCodecInfo().getCapabilitiesForType(mMime).getEncoderCapabilities();
-            if (cap.isBitrateModeSupported(MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR)) {
-                format.setInteger(MediaFormat.KEY_BITRATE_MODE,
-                        MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR);
-            } else {
-                format.setInteger(MediaFormat.KEY_BITRATE_MODE,
-                        MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR);
-            }
             for (boolean isAsync : boolStates) {
                 mOutputBuff.reset();
                 mInfoList.clear();
@@ -605,13 +696,13 @@
                 mCodec.start();
                 int expOutSize = 0;
                 int bitrate = format.getInteger(MediaFormat.KEY_BIT_RATE);
-                for (int i = 0; i < BR_CHANGE_REQUESTS; i++) {
-                    doWork(ADAPTIVE_BR_DUR_FRM);
+                for (int i = 0; i < brChangeRequests; i++) {
+                    doWork(adaptiveBrDurFrm);
                     if (mSawInputEOS) {
                         fail(String.format("Unable to encode %d frames as the input resource "
-                                + "contains only %d frames \n", ADAPTIVE_BR_DUR_FRM, mInputCount));
+                                + "contains only %d frames \n", adaptiveBrDurFrm, mInputCount));
                     }
-                    expOutSize += ADAPTIVE_BR_INTERVAL * bitrate;
+                    expOutSize += adaptiveBrInterval * bitrate;
                     if ((i & 1) == 1) bitrate *= 2;
                     else bitrate /= 2;
                     updateBitrate(bitrate);
@@ -625,7 +716,7 @@
                 /* TODO: validate output br with sliding window constraints Sec 5.2 cdd */
                 int outSize = mOutputBuff.getOutStreamSize() * 8;
                 float brDev = Math.abs(expOutSize - outSize) * 100.0f / expOutSize;
-                if (brDev > MAX_BITRATE_DEVIATION) {
+                if (brDev > maxBitrateDeviation) {
                     fail("Relative Bitrate error is too large " + brDev + "\n" + mTestConfig
                             + mTestEnv);
                 }
@@ -635,7 +726,7 @@
     }
 
     private native boolean nativeTestAdaptiveBitRate(String encoder, String file, String mime,
-            int[] list0, int[] list1, int[] list2, int colorFormat, StringBuilder retMsg);
+            String cfgParams, String separator, StringBuilder retMsg);
 
     /**
      * Test is similar to {@link #testAdaptiveBitRate()} but uses ndk api
@@ -643,18 +734,17 @@
     @ApiTest(apis = "android.media.MediaCodec#PARAMETER_KEY_VIDEO_BITRATE")
     @LargeTest
     @Test(timeout = PER_TEST_TIMEOUT_LARGE_TEST_MS)
-    public void testAdaptiveBitRateNative() throws IOException {
+    public void testAdaptiveBitRateNative() throws IOException, CloneNotSupportedException {
         Assume.assumeTrue("Skipping Native AdaptiveBitrate test for " + mMime,
-                sAdaptiveBitrateMimeList.contains(mMime));
-        int colorFormat = -1;
-        {
-            if (mIsVideo) {
-                colorFormat = findByteBufferColorFormat(mCodecName, mMime);
-                assertTrue("no valid color formats received", colorFormat != -1);
-            }
-            boolean isPass = nativeTestAdaptiveBitRate(mCodecName, mActiveRawRes.mFileName, mMime,
-                    mBitrates, mEncParamList1, mEncParamList2, colorFormat, mTestConfig);
-            assertTrue(mTestConfig.toString(), isPass);
-        }
+                ABR_MEDIATYPE_LIST.contains(mMime));
+        int colorFormat = findByteBufferColorFormat(mCodecName, mMime);
+        assertTrue("no valid color formats received \n" + mTestConfig + mTestEnv,
+                colorFormat != -1);
+        MediaFormat format =
+                mActiveEncCfg.getBuilder().setColorFormat(colorFormat).build().getFormat();
+        boolean isPass = nativeTestAdaptiveBitRate(mCodecName, mActiveRawRes.mFileName, mMime,
+                EncoderConfigParams.serializeMediaFormat(format),
+                EncoderConfigParams.TOKEN_SEPARATOR, mTestConfig);
+        assertTrue(mTestConfig.toString(), isPass);
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
index 2c20d23..bac7169 100644
--- a/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/DecoderColorAspectsTest.java
@@ -143,6 +143,9 @@
                         "bikes_qcif_color_bt2020_smpte2086Hlg_bt2020Ncl_fr_hevc.mp4",
                         MediaFormat.COLOR_RANGE_FULL, MediaFormat.COLOR_STANDARD_BT2020,
                         MediaFormat.COLOR_TRANSFER_HLG, true, CODEC_OPTIONAL},
+                {MediaFormat.MIMETYPE_VIDEO_HEVC, "cosmat_352x288_hlg_hevc.mkv",
+                        MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_HLG, true, CODEC_OPTIONAL},
 
                 // Mpeg2 clips
                 {MediaFormat.MIMETYPE_VIDEO_MPEG2, "bbb_qcif_color_bt709_lr_sdr_mpeg2.mp4",
@@ -227,6 +230,9 @@
                         "bikes_qcif_color_bt2020_smpte2086Hlg_bt2020Ncl_fr_vp9.mkv",
                         MediaFormat.COLOR_RANGE_FULL, MediaFormat.COLOR_STANDARD_BT2020,
                         MediaFormat.COLOR_TRANSFER_HLG, false, CODEC_ANY},
+                {MediaFormat.MIMETYPE_VIDEO_VP9, "cosmat_352x288_hlg_vp9.mkv",
+                        MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_HLG, false, CODEC_OPTIONAL},
 
                 // AV1 clips
                 {MediaFormat.MIMETYPE_VIDEO_AV1, "bbb_qcif_color_bt709_lr_sdr_av1.mp4",
@@ -254,6 +260,9 @@
                         "bikes_qcif_color_bt2020_smpte2086Hlg_bt2020Ncl_fr_av1.mp4",
                         MediaFormat.COLOR_RANGE_FULL, MediaFormat.COLOR_STANDARD_BT2020,
                         MediaFormat.COLOR_TRANSFER_HLG, true, CODEC_OPTIONAL},
+                {MediaFormat.MIMETYPE_VIDEO_AV1, "cosmat_352x288_hlg_av1.mkv",
+                        MediaFormat.COLOR_RANGE_LIMITED, MediaFormat.COLOR_STANDARD_BT709,
+                        MediaFormat.COLOR_TRANSFER_HLG, true, CODEC_ALL},
         });
         return prepareParamList(exhaustiveArgsList, isEncoder, needAudio, needVideo, false);
     }
diff --git a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
index db0bf9e..df21ded 100644
--- a/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
+++ b/tests/media/src/android/mediav2/cts/EncodeDecodeAccuracyTest.java
@@ -19,7 +19,7 @@
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_Format32bitABGR2101010;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface;
 import static android.media.MediaCodecInfo.CodecCapabilities.COLOR_FormatYUVP010;
-import static android.mediav2.common.cts.EncoderTestBase.colorFormatToString;
+import static android.mediav2.common.cts.CodecEncoderTestBase.colorFormatToString;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
diff --git a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
index a07dc4d..a2f4b76 100644
--- a/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderColorAspectsTest.java
@@ -28,9 +28,9 @@
 import android.media.MediaCodecList;
 import android.media.MediaFormat;
 import android.mediav2.common.cts.CodecDecoderTestBase;
+import android.mediav2.common.cts.CodecEncoderTestBase;
 import android.mediav2.common.cts.CodecTestBase;
 import android.mediav2.common.cts.EncoderConfigParams;
-import android.mediav2.common.cts.EncoderTestBase;
 import android.mediav2.common.cts.OutputManager;
 import android.opengl.GLES20;
 import android.os.Build;
@@ -73,7 +73,7 @@
  * restricted to HLG/HDR profiles.
  */
 @RunWith(Parameterized.class)
-public class EncoderColorAspectsTest extends EncoderTestBase {
+public class EncoderColorAspectsTest extends CodecEncoderTestBase {
     private static final String LOG_TAG = EncoderColorAspectsTest.class.getSimpleName();
 
     private Surface mInpSurface;
@@ -285,11 +285,6 @@
     public void testColorAspects() throws IOException, InterruptedException {
         Assume.assumeTrue("Test introduced with Android 11", sIsAtLeastR);
 
-        if (mCodecName.equals("OMX.google.h264.encoder")) {  // TODO(b/189883530)
-            Log.d(LOG_TAG, "test skipped due to b/189883530");
-            return;
-        }
-
         mActiveEncCfg = mEncCfgParams[0];
         if (mActiveEncCfg.mInputBitDepth > 8) {
             // Check if encoder is capable of supporting HDR profiles.
diff --git a/tests/media/src/android/mediav2/cts/EncoderInput.java b/tests/media/src/android/mediav2/cts/EncoderInput.java
index 2b7daa8..7b879b8 100644
--- a/tests/media/src/android/mediav2/cts/EncoderInput.java
+++ b/tests/media/src/android/mediav2/cts/EncoderInput.java
@@ -85,18 +85,4 @@
         }
         return null;
     }
-
-    /**
-     * TODO (b/260533828) remove this once all encoders are update to use
-     * @deprecated This function is marked for future removal. Use
-     * {@link EncoderInput#getRawResource(EncoderConfigParams)} instead.
-     */
-    @Deprecated(forRemoval = true)
-    public static RawResource getRawResource(String mediaType, boolean isHighBitDepth) {
-        if (mediaType.startsWith("audio/")) {
-            return isHighBitDepth ? INPUT_AUDIO_FILE_HBD : INPUT_AUDIO_FILE;
-        } else {
-            return isHighBitDepth ? INPUT_VIDEO_FILE_HBD : INPUT_VIDEO_FILE;
-        }
-    }
 }
diff --git a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
index a5eb22c..c5c9a32 100644
--- a/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
+++ b/tests/media/src/android/mediav2/cts/EncoderProfileLevelTest.java
@@ -31,8 +31,8 @@
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
 import android.media.MediaMuxer;
+import android.mediav2.common.cts.CodecEncoderTestBase;
 import android.mediav2.common.cts.EncoderConfigParams;
-import android.mediav2.common.cts.EncoderTestBase;
 import android.mediav2.common.cts.OutputManager;
 import android.util.Log;
 import android.util.Pair;
@@ -75,7 +75,7 @@
  * handle certain profile and level configurations. This is verified as well.
  */
 @RunWith(Parameterized.class)
-public class EncoderProfileLevelTest extends EncoderTestBase {
+public class EncoderProfileLevelTest extends CodecEncoderTestBase {
     private static final String LOG_TAG = EncoderProfileLevelTest.class.getSimpleName();
     private static final HashMap<String, Pair<int[], Integer>> PROFILE_LEVEL_CDD = new HashMap<>();
 
diff --git a/tests/media/src/android/mediav2/cts/MuxerTest.java b/tests/media/src/android/mediav2/cts/MuxerTest.java
index 938df1b..7804408 100644
--- a/tests/media/src/android/mediav2/cts/MuxerTest.java
+++ b/tests/media/src/android/mediav2/cts/MuxerTest.java
@@ -16,7 +16,7 @@
 
 package android.mediav2.cts;
 
-import static android.mediav2.common.cts.EncoderTestBase.isMediaTypeContainerPairValid;
+import static android.mediav2.common.cts.CodecEncoderTestBase.isMediaTypeContainerPairValid;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/tests/media/src/android/mediav2/cts/VideoEncoderTest.java b/tests/media/src/android/mediav2/cts/VideoEncoderTest.java
index 8a94a85..82cfae0 100644
--- a/tests/media/src/android/mediav2/cts/VideoEncoderTest.java
+++ b/tests/media/src/android/mediav2/cts/VideoEncoderTest.java
@@ -24,8 +24,9 @@
 import static org.junit.Assert.assertTrue;
 
 import android.media.MediaFormat;
+import android.mediav2.common.cts.CodecEncoderTestBase;
+import android.mediav2.common.cts.CodecTestBase;
 import android.mediav2.common.cts.EncoderConfigParams;
-import android.mediav2.common.cts.EncoderTestBase;
 import android.mediav2.common.cts.RawResource;
 
 import androidx.test.filters.LargeTest;
@@ -55,7 +56,7 @@
  * </ul>
  */
 @RunWith(Parameterized.class)
-public class VideoEncoderTest extends EncoderTestBase {
+public class VideoEncoderTest extends CodecEncoderTestBase {
     public VideoEncoderTest(String encoder, String mediaType, EncoderConfigParams encCfgParams,
             @SuppressWarnings("unused") String testLabel, String allTestParams) {
         super(encoder, mediaType, new EncoderConfigParams[]{encCfgParams}, allTestParams);
@@ -170,10 +171,19 @@
         RawResource res = EncoderInput.getRawResource(mEncCfgParams[0]);
         assertNotNull("no raw resource found for testing config : " + mActiveEncCfg + mTestConfig
                 + mTestEnv, res);
-        encodeToMemory(mCodecName, mEncCfgParams[0], res, Integer.MAX_VALUE, false, false);
+
+        boolean muxOutput = true;
+        if (mMime.equals(MediaFormat.MIMETYPE_VIDEO_AV1) && CodecTestBase.IS_BEFORE_U) {
+            muxOutput = false;
+        }
+        encodeToMemory(mCodecName, mEncCfgParams[0], res, Integer.MAX_VALUE, false, muxOutput);
 
         // cleanup tmp files
-        if (mMuxOutput) {
+        if (muxOutput) {
+            // validate output
+            validateEncodedPSNR(res, mMime, mMuxedOutputFile, true, mIsLoopBack,
+                    ACCEPTABLE_WIRELESS_TX_QUALITY);
+
             File tmp = new File(mMuxedOutputFile);
             if (tmp.exists()) {
                 assertTrue("unable to delete tmp file" + mMuxedOutputFile, tmp.delete());
diff --git a/tests/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index a91a0f0..2a2bfab 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -39,7 +39,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="CtsMediaPerformanceClassTestCases-2.0" />
+        <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-2.1" />
         <option name="dynamic-config-module" value="CtsMediaPerformanceClassTestCases" />
     </target_preparer>
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/mediapc/DynamicConfig.xml b/tests/mediapc/DynamicConfig.xml
index 1d44a69..d1a7b1f 100644
--- a/tests/mediapc/DynamicConfig.xml
+++ b/tests/mediapc/DynamicConfig.xml
@@ -1,6 +1,6 @@
 <dynamicConfig>
     <entry key="media_files_url">
-      <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-2.0.zip</value>
+      <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-2.1.zip</value>
     </entry>
 </dynamicConfig>
 
diff --git a/tests/mediapc/README.md b/tests/mediapc/README.md
index f29aedd..d212c32 100644
--- a/tests/mediapc/README.md
+++ b/tests/mediapc/README.md
@@ -1,7 +1,7 @@
 ## Media Performance Class CTS Tests
 Current folder comprises of files necessary for testing media performance class.
 
-The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-2.0.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
+The test vectors used by the test suite is available at [link](https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-2.1.zip) and is downloaded automatically while running tests. Manual installation of these can be done using copy_media.sh script in this directory.
 
 ### Commands
 #### To run all tests in CtsMediaPerformanceClassTestCases
diff --git a/tests/mediapc/common/Android.bp b/tests/mediapc/common/Android.bp
index 663dabc..02fd714 100644
--- a/tests/mediapc/common/Android.bp
+++ b/tests/mediapc/common/Android.bp
@@ -25,7 +25,8 @@
         "compatibility-device-util-axt",
         "android.test.base",
         "auto_value_annotations",
-        "guava"
+        "guava",
+        "cts-verifier-framework",
     ],
     plugins: ["auto_value_plugin"],
 }
@@ -35,7 +36,7 @@
     compile_multilib: "both",
     static_libs: [
         "compatibility-device-util-axt",
-        "MediaPerformanceClassCommon"
+        "MediaPerformanceClassCommon",
     ],
     platform_apis: true,
     srcs: ["tests/src/**/*.java"],
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
index 91db865..1e803c2 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/PerformanceClassEvaluator.java
@@ -23,6 +23,12 @@
 import android.hardware.camera2.CameraMetadata;
 import android.media.MediaFormat;
 import android.os.Build;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.cts.verifier.CtsVerifierReportLog;
 
 import com.google.common.base.Preconditions;
 
@@ -1494,6 +1500,46 @@
         }
     }
 
+    public static class AudioTap2ToneLatencyRequirement extends Requirement {
+        private static final String TAG = AudioTap2ToneLatencyRequirement.class.getSimpleName();
+
+        private AudioTap2ToneLatencyRequirement(String id, RequiredMeasurement<?> ... reqs) {
+            super(id, reqs);
+        }
+
+        public void setNativeLatency(double latency) {
+            this.setMeasuredValue(RequirementConstants.API_NATIVE_LATENCY, latency);
+        }
+
+        public void setJavaLatency(double latency) {
+            this.setMeasuredValue(RequirementConstants.API_JAVA_LATENCY, latency);
+        }
+
+        public static AudioTap2ToneLatencyRequirement createR5_6__H_1_1() {
+            RequiredMeasurement<Double> apiNativeLatency = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.API_NATIVE_LATENCY)
+                .setPredicate(RequirementConstants.DOUBLE_LTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 80.0)
+                .addRequiredValue(Build.VERSION_CODES.S, 100.0)
+                .addRequiredValue(Build.VERSION_CODES.R, 100.0)
+                .build();
+            RequiredMeasurement<Double> apiJavaLatency = RequiredMeasurement
+                .<Double>builder()
+                .setId(RequirementConstants.API_JAVA_LATENCY)
+                .setPredicate(RequirementConstants.DOUBLE_LTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 80.0)
+                .addRequiredValue(Build.VERSION_CODES.S, 100.0)
+                .addRequiredValue(Build.VERSION_CODES.R, 100.0)
+                .build();
+
+            return new AudioTap2ToneLatencyRequirement(
+                    RequirementConstants.R5_6__H_1_1,
+                    apiNativeLatency,
+                    apiJavaLatency);
+        }
+    }
+
     public <R extends Requirement> R addRequirement(R req) {
         if (!this.mRequirements.add(req)) {
             throw new IllegalStateException("Requirement " + req.id() + " already added");
@@ -1725,21 +1771,51 @@
         return this.addRequirement(StreamUseCaseRequirement.createStreamUseCaseReq());
     }
 
+    public AudioTap2ToneLatencyRequirement addR5_6__H_1_1() {
+        return this.addRequirement(AudioTap2ToneLatencyRequirement.createR5_6__H_1_1());
+    }
+
+    private enum SubmitType {
+        TRADEFED, VERIFIER
+    }
+
     public void submitAndCheck() {
-        boolean perfClassMet = submit();
+        boolean perfClassMet = submit(SubmitType.TRADEFED);
 
         // check performance class
         assumeTrue("Build.VERSION.MEDIA_PERFORMANCE_CLASS is not declared", Utils.isPerfClass());
         assertThat(perfClassMet).isTrue();
     }
 
-    public boolean submit() {
+    public void submitAndVerify() {
+        boolean perfClassMet = submit(SubmitType.VERIFIER);
+
+        if (!perfClassMet && Utils.isPerfClass()) {
+            Log.w(TAG, "Device did not meet specified performance class: " + Utils.getPerfClass());
+        }
+    }
+
+    private boolean submit(SubmitType type) {
         boolean perfClassMet = true;
         for (Requirement req: this.mRequirements) {
-            perfClassMet &= req.writeLogAndCheck(this.mTestName);
+            switch (type) {
+                case VERIFIER:
+                    CtsVerifierReportLog verifierLog = new CtsVerifierReportLog(
+                            RequirementConstants.REPORT_LOG_NAME, req.id());
+                    perfClassMet &= req.writeLogAndCheck(verifierLog, this.mTestName);
+                    verifierLog.submit();
+                    break;
+
+                case TRADEFED:
+                default:
+                    DeviceReportLog tradefedLog = new DeviceReportLog(
+                            RequirementConstants.REPORT_LOG_NAME, req.id());
+                    perfClassMet &= req.writeLogAndCheck(tradefedLog, this.mTestName);
+                    tradefedLog.submit(InstrumentationRegistry.getInstrumentation());
+                    break;
+            }
         }
         this.mRequirements.clear(); // makes sure report isn't submitted twice
         return perfClassMet;
     }
-
 }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
index cf2633f..efa7e96 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequiredMeasurement.java
@@ -16,9 +16,10 @@
 
 package android.mediapc.cts.common;
 
-import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableMap;
 
@@ -113,7 +114,7 @@
             + "\n\tExpected Values: " + this.expectedValues();
     }
 
-    public void writeValue(DeviceReportLog log) throws IllegalStateException {
+    public void writeValue(ReportLog log) throws IllegalStateException {
 
         if (!this.measuredValueSet) {
             throw new IllegalStateException("measured value not set for required measurement "
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
index 445c5c6..2160b10 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/Requirement.java
@@ -18,15 +18,13 @@
 
 import android.util.Log;
 
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import com.android.compatibility.common.util.DeviceReportLog;
+import com.android.compatibility.common.util.ReportLog;
 import com.android.compatibility.common.util.ResultType;
 import com.android.compatibility.common.util.ResultUnit;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.collect.ImmutableMap;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -113,7 +111,7 @@
     /**
      * @return whether or not the requirement meets the device's specified performance class
      */
-    public boolean writeLogAndCheck(String testName) {
+    public boolean writeLogAndCheck(ReportLog log, String testName) {
         if (this.id == RequirementConstants.RTBD) {
             // skip upload on any requirement without a specified id
             Log.i(this.TAG, testName + "has requirement without set requirement id and test " +
@@ -123,7 +121,6 @@
 
         int perfClass = this.computePerformanceClass();
 
-        DeviceReportLog log = new DeviceReportLog(RequirementConstants.REPORT_LOG_NAME, this.id);
         log.addValue(RequirementConstants.TN_FIELD_NAME, testName, ResultType.NEUTRAL,
             ResultUnit.NONE);
         for (RequiredMeasurement rm: this.mRequiredMeasurements.values()) {
@@ -131,7 +128,6 @@
         }
         log.addValue(RequirementConstants.PC_FIELD_NAME, perfClass, ResultType.NEUTRAL,
             ResultUnit.NONE);
-        log.submit(InstrumentationRegistry.getInstrumentation());
 
         return this.checkPerformanceClass(Utils.getPerfClass());
     }
diff --git a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
index 7bccbeb..6893e62 100644
--- a/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
+++ b/tests/mediapc/common/src/android/mediapc/cts/common/RequirementConstants.java
@@ -50,8 +50,11 @@
     public static final String R7_5__H_1_2 = "r7_5__h_1_2"; // 7.5/H-1-2
     public static final String R7_5__H_1_3 = "r7_5__h_1_3"; // 7.5/H-1-3
     public static final String R7_5__H_1_4 = "r7_5__h_1_4"; // 7.5/H-1-4
-    public static final String R7_5__H_1_5 = "r7_5__h_1_5"; // 7.5/H-1-5
-    public static final String R7_5__H_1_6 = "r7_5__h_1_6"; // 7.5/H-1-6
+
+    // these includes "its" because the proto in google3 was originally implemented incorrectly
+    public static final String R7_5__H_1_5 = "r7_5__h_1_5__its"; // 7.5/H-1-5
+    public static final String R7_5__H_1_6 = "r7_5__h_1_6__its"; // 7.5/H-1-6
+
     public static final String R7_5__H_1_8 = "r7_5__h_1_8"; // 7.5/H-1-8
     public static final String R7_5__H_1_9 = "r7_5__h_1_9"; // 7.5/H-1-9
     public static final String R7_5__H_1_10 = "r7_5__h_1_10"; // 7.5/H-1-10
@@ -128,6 +131,8 @@
             "rear_camera_stream_usecase_supported";
     public static final String FRONT_CAMERA_STREAM_USECASE_SUPPORTED =
             "front_camera_stream_usecase_supported";
+    public static final String API_NATIVE_LATENCY = "native_latency_ms";
+    public static final String API_JAVA_LATENCY = "java_latency_ms";
 
     public enum Result {
         NA, MET, UNMET
@@ -140,6 +145,7 @@
     public static final BiPredicate<Integer, Integer> INTEGER_LTE = RequirementConstants.lte();
     public static final BiPredicate<Integer, Integer> INTEGER_EQ = RequirementConstants.eq();
     public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
+    public static final BiPredicate<Double, Double> DOUBLE_LTE = RequirementConstants.lte();
     public static final BiPredicate<Double, Double> DOUBLE_EQ = RequirementConstants.eq();
     public static final BiPredicate<Boolean, Boolean> BOOLEAN_EQ = RequirementConstants.eq();
 
diff --git a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
index daa9d27..1c5035b 100644
--- a/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
+++ b/tests/mediapc/common/tests/src/android/mediapc/cts/common/RequirementTest.java
@@ -22,6 +22,8 @@
 
 import android.os.Build;
 
+import com.android.compatibility.common.util.DeviceReportLog;
+
 import org.junit.Test;
 
 public class RequirementTest {
@@ -197,9 +199,10 @@
     @Test
     public void writeLogAndCheck_UnsetMeasurement() {
         TestReq testReq = TestReq.create();
+        DeviceReportLog testLog = new DeviceReportLog("test", "test");
 
         assertThrows(
             IllegalStateException.class,
-            () -> testReq.writeLogAndCheck("writeLogAndCheck_UnsetMeasurement"));
+            () -> testReq.writeLogAndCheck(testLog, "writeLogAndCheck_UnsetMeasurement"));
     }
 }
diff --git a/tests/mediapc/copy_media.sh b/tests/mediapc/copy_media.sh
index d63eb0a..25d98ce 100644
--- a/tests/mediapc/copy_media.sh
+++ b/tests/mediapc/copy_media.sh
@@ -17,7 +17,7 @@
 ## script to install media performance class test files manually
 
 adbOptions=" "
-resLabel=CtsMediaPerformanceClassTestCases-2.0
+resLabel=CtsMediaPerformanceClassTestCases-2.1
 srcDir="/tmp/$resLabel"
 tgtDir="/sdcard/test"
 usage="Usage: $0 [-h] [-s serial]"
diff --git a/tests/mediapc/src/android/mediapc/cts/WorkDir.java b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
index c9d689a..4076e88 100644
--- a/tests/mediapc/src/android/mediapc/cts/WorkDir.java
+++ b/tests/mediapc/src/android/mediapc/cts/WorkDir.java
@@ -40,7 +40,7 @@
             // user has specified the mediaDirString via instrumentation-arg
             return mediaDirString + ((mediaDirString.endsWith("/")) ? "" : "/");
         } else {
-            return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-2.0/");
+            return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-2.1/");
         }
     }
 }
diff --git a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
index 0e1bcd1..b2292f4 100644
--- a/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
+++ b/tests/providerui/src/android/providerui/cts/MediaStoreUiTest.java
@@ -281,6 +281,11 @@
     public void testOpenFile_onMediaDocumentsProvider_failsWithoutAccess() throws Exception {
         if (!supportsHardware()) return;
 
+        String rawText = "TEST";
+        // Read and write grants will be provided to the file associated with this pair.
+        // Stages a text file which contains raw text "TEST"
+        Pair<Uri, File> uriFilePairWithGrants =  prepareFileAndFetchDetails(rawText);
+
         clearDocumentsUi();
         final Intent intent = new Intent();
         intent.setAction(Intent.ACTION_OPEN_DOCUMENT);
@@ -289,10 +294,6 @@
         mActivity.startActivityForResult(intent, REQUEST_CODE);
         mDevice.waitForIdle();
 
-        String rawText = "TEST";
-        // Read and write grants will be provided to the file associated with this pair.
-        // Stages a text file which contains raw text "TEST"
-        Pair<Uri, File> uriFilePairWithGrants =  prepareFileAndFetchDetails(rawText);
         // Read and write grants will not be provided to the file associated with this pair
         // Stages a text file which contains raw text "TEST"
         Pair<Uri, File> uriFilePairWithoutGrants =  prepareFileAndFetchDetails(rawText);
diff --git a/tests/quickaccesswallet/OWNERS b/tests/quickaccesswallet/OWNERS
index 271c1e6..b633530 100644
--- a/tests/quickaccesswallet/OWNERS
+++ b/tests/quickaccesswallet/OWNERS
@@ -1,6 +1,8 @@
-# Bug component: 480956
+# Bug component: 802986
 seanpont@google.com
 steell@google.com
 granger@google.com
 sbasi@google.com
 franksalim@google.com
+juliacr@google.com
+asc@google.com
diff --git a/tests/signature/OWNERS b/tests/signature/OWNERS
new file mode 100644
index 0000000..0577cf8
--- /dev/null
+++ b/tests/signature/OWNERS
@@ -0,0 +1,6 @@
+# Bug component: 24949
+ngeoffray@google.com
+paulduffin@google.com
+andreionea@google.com
+
+include platform/art:/OWNERS
\ No newline at end of file
diff --git a/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java b/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
index 8bb3062..5d0e6a3 100644
--- a/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
+++ b/tests/signature/lib/common/src/android/signature/cts/DexApiDocumentParser.java
@@ -19,6 +19,7 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.nio.ByteBuffer;
+import java.text.ParseException;
 import java.util.Arrays;
 import java.util.function.BiFunction;
 import java.util.function.Function;
@@ -26,7 +27,6 @@
 import java.util.regex.Pattern;
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
-import java.text.ParseException;
 
 /**
  * Parses an API definition given as a text file with DEX signatures of class
@@ -38,8 +38,18 @@
  */
 public class DexApiDocumentParser {
 
-    // Regex patterns which match DEX signatures of methods and fields.
-    // See comment by next() for more details.
+    /*
+     * Regex patterns which match DEX signatures of methods and fields.
+     *
+     * The following two line formats are supported:
+     * 1) [class descriptor]->[field name]:[field type]
+     *      - e.g. Lcom/example/MyClass;->myField:I
+     *      - these lines are parsed as field signatures
+     * 2) [class descriptor]->[method name]([method parameter types])[method return type]
+     *      - e.g. Lcom/example/MyClass;->myMethod(Lfoo;Lbar;)J
+     *      - these lines are parsed as method signatures
+     * NB there are parens present in method signatures but not field signatures.
+     */
     private static final Pattern REGEX_FIELD = Pattern.compile("^(L[^>]*;)->(.*):(.*)$");
     private static final Pattern REGEX_METHOD =
             Pattern.compile("^(L[^>]*;)->(.*)(\\(.*\\).*)$");
@@ -83,7 +93,7 @@
         return parseAsStream(buffer, LINE_LENGTH_ESTIMATE);
     }
     public Stream<DexMember> parseAsStream(ByteBuffer buffer, int lineLengthEstimate) {
-        // TODO: Ensurance that the input conforms to ByteBufferLineSpliterator requirements.
+        // TODO: Ensure that the input conforms to ByteBufferLineSpliterator requirements.
         return StreamSupport.stream(new ByteBufferLineSpliterator<DexMember>(buffer,
                 lineLengthEstimate, DEX_MEMBER_CONVERTER), true);
     }
@@ -94,26 +104,21 @@
         String signature = splitLine[0];
         String[] flags = Arrays.copyOfRange(splitLine, 1, splitLine.length);
 
-        // Match line against regex patterns.
-        Matcher matchField = REGEX_FIELD.matcher(signature);
-        Matcher matchMethod = REGEX_METHOD.matcher(signature);
-
-        // Check that *exactly* one pattern matches.
-        int matchCount = (matchField.matches() ? 1 : 0) + (matchMethod.matches() ? 1 : 0);
-        if (matchCount == 0) {
-            throw new ParseException("Could not parse: \"" + line + "\"", lineNum);
-        } else if (matchCount > 1) {
-            throw new ParseException("Ambiguous parse: \"" + line + "\"", lineNum);
+        // Check if the signature has the form of a field signature (no parens present).
+        final boolean memberIsField = (signature.indexOf('(') < 0);
+        if (memberIsField) {
+            Matcher matchField = REGEX_FIELD.matcher(signature);
+            if (matchField.matches()) {
+                return new DexField(
+                        matchField.group(1), matchField.group(2), matchField.group(3), flags);
+            }
+        } else {
+            Matcher matchMethod = REGEX_METHOD.matcher(signature);
+            if (matchMethod.matches()) {
+                return new DexMethod(
+                        matchMethod.group(1), matchMethod.group(2), matchMethod.group(3), flags);
+            }
         }
-
-        // Extract information from the signature.
-        if (matchField.matches()) {
-            return new DexField(
-                    matchField.group(1), matchField.group(2), matchField.group(3), flags);
-        } else if (matchMethod.matches()) {
-            return new DexMethod(
-                    matchMethod.group(1),matchMethod.group(2), matchMethod.group(3), flags);
-        }
-        throw new IllegalStateException();
+        throw new ParseException("Could not parse: \"" + line + "\"", lineNum);
     }
 }
diff --git a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
index b642efa..a6614a3 100644
--- a/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
+++ b/tests/signature/lib/common/src/android/signature/cts/InterfaceChecker.java
@@ -83,6 +83,7 @@
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethod.setCurrentShowInputToken(android.os.IBinder)");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethodSession.notifyImeHidden()");
         HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.view.inputmethod.InputMethodSession.removeImeSurface()");
+        HIDDEN_INTERFACE_METHOD_ALLOW_LIST.add("public abstract void android.bluetooth.BluetoothProfile.close()");
     }
 
     private final ResultObserver resultObserver;
diff --git a/tests/tests/background/Android.bp b/tests/tests/background/Android.bp
index ad0efa0..03030212 100644
--- a/tests/tests/background/Android.bp
+++ b/tests/tests/background/Android.bp
@@ -25,7 +25,6 @@
         "mockito-target-minus-junit4",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
-        "ub-uiautomator",
     ],
     libs: ["android.test.runner"],
     srcs: ["src/**/*.java"],
diff --git a/tests/tests/bluetooth/AndroidTest.xml b/tests/tests/bluetooth/AndroidTest.xml
index caf9428..7b42874 100644
--- a/tests/tests/bluetooth/AndroidTest.xml
+++ b/tests/tests/bluetooth/AndroidTest.xml
@@ -25,6 +25,12 @@
         <option name="cleanup-apks" value="true" />
         <option name="test-file-name" value="CtsBluetoothTestCases.apk" />
     </target_preparer>
+    <target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
+        <option name="run-command" value="cmd bluetooth_manager enable" />
+        <option name="run-command" value="cmd bluetooth_manager wait-for-state:STATE_ON" />
+        <option name="teardown-command" value="cmd bluetooth_manager disable" />
+        <option name="teardown-command" value="cmd bluetooth_manager wait-for-state:STATE_OFF" />
+    </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.bluetooth.cts" />
         <option name="runtime-hint" value="1m11s" />
diff --git a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
index 6807c39..32d37fc 100644
--- a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
@@ -280,12 +280,7 @@
         try {
             adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
             bluetoothAdapter.disable();
-            if (waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter)) {
-                //TODO b/234892968
-                Thread.sleep(2000);
-                return true;
-            }
-            return false;
+            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
         } catch (InterruptedException e) {
             Log.w(TAG, "disableAdapter(): interrupted", e);
         } finally {
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
index 4f472c7..f351498 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertiseSettingsTest.java
@@ -49,6 +49,7 @@
         AdvertiseSettings settings = new AdvertiseSettings.Builder()
                 .setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_LOW_LATENCY)
                 .setConnectable(false)
+                .setDiscoverable(false)
                 .setTimeout(timeoutMillis)
                 .setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_MEDIUM)
                 .setOwnAddressType(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT)
@@ -61,6 +62,7 @@
                 settingsFromParcel.getTxPowerLevel());
         assertEquals(timeoutMillis, settingsFromParcel.getTimeout());
         assertFalse(settings.isConnectable());
+        assertFalse(settings.isDiscoverable());
         assertEquals(AdvertisingSetParameters.ADDRESS_TYPE_DEFAULT, settings.getOwnAddressType());
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertisingSetParametersTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertisingSetParametersTest.java
index a6ec271..6484f53 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertisingSetParametersTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/AdvertisingSetParametersTest.java
@@ -65,6 +65,7 @@
         AdvertisingSetParameters params = new AdvertisingSetParameters.Builder().build();
 
         assertFalse(params.isConnectable());
+        assertTrue(params.isDiscoverable());
         assertFalse(params.isScannable());
         assertFalse(params.isLegacy());
         assertFalse(params.isAnonymous());
@@ -84,6 +85,15 @@
     }
 
     @Test
+    public void testIsDiscoverable() {
+        AdvertisingSetParameters params = new AdvertisingSetParameters.Builder()
+                .setDiscoverable(false)
+                .build();
+        assertFalse(params.isDiscoverable());
+    }
+
+
+    @Test
     public void testIsScannable() {
         AdvertisingSetParameters params = new AdvertisingSetParameters.Builder()
                 .setScannable(true)
@@ -237,6 +247,7 @@
         }
 
         assertEquals(p.isConnectable(), other.isConnectable());
+        assertEquals(p.isDiscoverable(), other.isDiscoverable());
         assertEquals(p.isScannable(), other.isScannable());
         assertEquals(p.isLegacy(), other.isLegacy());
         assertEquals(p.isAnonymous(), other.isAnonymous());
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
index f9531fb..22d3447 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BasicBluetoothGattTest.java
@@ -16,6 +16,8 @@
 
 package android.bluetooth.cts;
 
+import static org.junit.Assert.assertThrows;
+
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothGatt;
@@ -23,6 +25,7 @@
 import android.bluetooth.BluetoothGattService;
 import android.bluetooth.BluetoothManager;
 import android.test.AndroidTestCase;
+import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 
@@ -33,6 +36,7 @@
  * Other tests that run with real bluetooth connections are located in CtsVerifier.
  */
 public class BasicBluetoothGattTest extends AndroidTestCase {
+    private static final String TAG = BasicBluetoothGattTest.class.getSimpleName();
 
     private BluetoothAdapter mBluetoothAdapter;
     private BluetoothDevice mBluetoothDevice;
@@ -53,6 +57,17 @@
         mBluetoothDevice = mBluetoothAdapter.getRemoteDevice("00:11:22:AA:BB:CC");
         mBluetoothGatt = mBluetoothDevice.connectGatt(
                 mContext, /*autoConnect=*/ true, new BluetoothGattCallback() {});
+        if (mBluetoothGatt == null) {
+            try {
+                Thread.sleep(500); // Bt is not binded yet. Wait and retry
+            } catch (InterruptedException e) {
+                Log.e(TAG, "delay connectGatt interrupted");
+            }
+            mBluetoothGatt = mBluetoothDevice.connectGatt(
+                    mContext, /*autoConnect=*/ true, new BluetoothGattCallback() {});
+        }
+        assertNotNull(mBluetoothGatt);
+
     }
 
     @Override
@@ -61,8 +76,9 @@
             // mBluetoothAdapter == null.
             return;
         }
-        mBluetoothGatt.disconnect();
-        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
+        if (mBluetoothGatt != null) {
+            mBluetoothGatt.disconnect();
+        }
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
             .dropShellPermissionIdentity();
     }
@@ -83,11 +99,7 @@
             return;
         }
 
-        try {
-            mBluetoothGatt.connect();
-        } catch (Exception e) {
-            fail("Exception caught from connect(): " + e.toString());
-        }
+        mBluetoothGatt.connect();
     }
 
     public void testSetPreferredPhy() throws Exception {
@@ -95,47 +107,34 @@
             return;
         }
 
-        try {
-            mBluetoothGatt.setPreferredPhy(BluetoothDevice.PHY_LE_1M, BluetoothDevice.PHY_LE_1M,
-                    BluetoothDevice.PHY_OPTION_NO_PREFERRED);
-        } catch (Exception e) {
-            fail("Exception caught from setPreferredPhy(): " + e.toString());
-        }
+        mBluetoothGatt.setPreferredPhy(BluetoothDevice.PHY_LE_1M, BluetoothDevice.PHY_LE_1M,
+                BluetoothDevice.PHY_OPTION_NO_PREFERRED);
     }
 
     public void testGetConnectedDevices() {
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        try {
-            mBluetoothGatt.getConnectedDevices();
-            fail("Should throw UnsupportedOperationException!");
-        } catch (UnsupportedOperationException ex) {
-            // Expected
-        }
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mBluetoothGatt.getConnectedDevices());
     }
 
     public void testGetConnectionState() {
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        try {
-            mBluetoothGatt.getConnectionState(null);
-            fail("Should throw UnsupportedOperationException!");
-        } catch (UnsupportedOperationException ex) {
-            // Expected
-        }
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mBluetoothGatt.getConnectionState(null));
     }
 
     public void testGetDevicesMatchingConnectionStates() {
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        try {
-            mBluetoothGatt.getDevicesMatchingConnectionStates(null);
-            fail("Should throw UnsupportedOperationException!");
-        } catch (UnsupportedOperationException ex) {
-            // Expected
-        }
+
+        assertThrows(UnsupportedOperationException.class,
+                () -> mBluetoothGatt.getDevicesMatchingConnectionStates(null));
     }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
index 7a20e9b..27708a6 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpSinkTest.java
@@ -88,10 +88,6 @@
             mBluetoothA2dpSink = null;
             mIsProfileReady = false;
         }
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mUiAutomation.dropShellPermissionIdentity();
         mAdapter = null;
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
index 515f0ef..21a5cad 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothA2dpTest.java
@@ -89,9 +89,6 @@
             mBluetoothA2dp = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         mUiAutomation.dropShellPermissionIdentity();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
index 0017efb..592bee7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothAdapterTest.java
@@ -36,6 +36,7 @@
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
 import android.os.Build;
+import android.os.Bundle;
 import android.test.AndroidTestCase;
 import android.util.Log;
 
@@ -89,8 +90,6 @@
     @Override
     public void tearDown() throws Exception {
         if (mHasBluetooth) {
-            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mUiAutomation.dropShellPermissionIdentity();
         }
     }
@@ -626,6 +625,109 @@
 
     }
 
+    public void test_setPreferredAudioProfiles_getPreferredAudioProfiles() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+
+        Bundle preferences = new Bundle();
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY, BluetoothProfile.HEADSET);
+
+        // Test invalid input
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.setPreferredAudioProfiles(device, null));
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.setPreferredAudioProfiles(device, preferences));
+        assertThrows(NullPointerException.class, () -> mAdapter.getPreferredAudioProfiles(null));
+
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY, BluetoothProfile.HID_HOST);
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.setPreferredAudioProfiles(device, preferences));
+
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_OUTPUT_ONLY, BluetoothProfile.LE_AUDIO);
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, BluetoothProfile.A2DP);
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.setPreferredAudioProfiles(device, preferences));
+
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, BluetoothProfile.GATT);
+        assertThrows(IllegalArgumentException.class,
+                () -> mAdapter.setPreferredAudioProfiles(device, preferences));
+
+        preferences.putInt(BluetoothAdapter.AUDIO_MODE_DUPLEX, BluetoothProfile.HEADSET);
+
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.setPreferredAudioProfiles(null, preferences));
+
+        // Check what happens when the device is not bonded
+        assertTrue(mAdapter.getPreferredAudioProfiles(device).isEmpty());
+        assertEquals(BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
+                mAdapter.setPreferredAudioProfiles(device, preferences));
+    }
+
+    public void test_preferredAudioProfileCallbacks() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+
+        Executor executor = mContext.getMainExecutor();
+        BluetoothAdapter.PreferredAudioProfilesChangedCallback callback =
+                new BluetoothAdapter.PreferredAudioProfilesChangedCallback() {
+            @Override
+            public void onPreferredAudioProfilesChanged(
+                    @androidx.annotation.NonNull BluetoothDevice device,
+                    @androidx.annotation.NonNull Bundle preferredAudioProfiles, int status) {}
+        };
+
+        callback.onPreferredAudioProfilesChanged(device, Bundle.EMPTY,
+                BluetoothStatusCodes.SUCCESS);
+
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.registerPreferredAudioProfilesChangedCallback(null, callback));
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.registerPreferredAudioProfilesChangedCallback(executor, null));
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.unregisterPreferredAudiProfilesChangedCallback(null));
+
+        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
+        assertThrows(SecurityException.class, () ->
+                mAdapter.registerPreferredAudioProfilesChangedCallback(executor, callback));
+        assertThrows(IllegalArgumentException.class, () ->
+                mAdapter.unregisterPreferredAudiProfilesChangedCallback(callback));
+
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+
+        // Try the happy path
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.registerPreferredAudioProfilesChangedCallback(executor, callback));
+        assertEquals(BluetoothStatusCodes.SUCCESS,
+                mAdapter.unregisterPreferredAudiProfilesChangedCallback(callback));
+    }
+
+    public void test_notifyPreferredAudioProfileChangeApplied() {
+        if (!mHasBluetooth) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+        assertTrue(BTAdapterUtils.enableAdapter(mAdapter, mContext));
+        String deviceAddress = "00:11:22:AA:BB:CC";
+        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
+
+        assertThrows(NullPointerException.class, () ->
+                mAdapter.notifyPreferredAudioProfileChangeApplied(null));
+
+
+        assertEquals(BluetoothStatusCodes.ERROR_BLUETOOTH_NOT_ALLOWED,
+                mAdapter.notifyPreferredAudioProfileChangeApplied(device));
+    }
+
     private static void sleep(long t) {
         try {
             Thread.sleep(t);
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
index f6336bf..4c641ac 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothConfigTest.java
@@ -60,7 +60,6 @@
         super.tearDown();
         if (!mHasBluetooth) return;
 
-        assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
         mAdapter = null;
         mUiAutomation.dropShellPermissionIdentity();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
index 9a43e6f..24f8c12 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothCsipSetCoordinatorTest.java
@@ -135,10 +135,7 @@
                 mTestCallback = null;
                 mTestExecutor = null;
             }
-            if (mAdapter != null ) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-                mAdapter = null;
-            }
+            mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
index 046acfc..ca5b4f3 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothDeviceTest.java
@@ -34,12 +34,10 @@
 import android.bluetooth.BluetoothAudioPolicy;
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothManager;
-import android.bluetooth.BluetoothProfile;
 import android.bluetooth.BluetoothStatusCodes;
 import android.bluetooth.OobData;
 import android.content.AttributionSource;
 import android.content.pm.PackageManager;
-import android.os.Bundle;
 import android.test.AndroidTestCase;
 
 import androidx.test.InstrumentationRegistry;
@@ -79,7 +77,6 @@
     public void tearDown() throws Exception {
         super.tearDown();
         if (mHasBluetooth && mHasCompanionDevice) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
             mUiAutomation.dropShellPermissionIdentity();
         }
@@ -145,8 +142,24 @@
         }
 
         // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
-        assertThrows("No BLUETOOTH_PRIVILEGED permission",
-                SecurityException.class, () -> mFakeDevice.getIdentityAddress());
+        assertThrows("No BLUETOOTH_PRIVILEGED permission", SecurityException.class,
+                () -> mFakeDevice.getIdentityAddress());
+    }
+
+    public void test_getConnectionHandle() {
+        if (!mHasBluetooth || !mHasCompanionDevice) {
+            // Skip the test if bluetooth or companion device are not present.
+            return;
+        }
+
+        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
+        assertThrows("No BLUETOOTH_PRIVILEGED permission", SecurityException.class,
+                () -> mFakeDevice.getConnectionHandle(TRANSPORT_LE));
+
+        // but it should work after we get the permission
+        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
+        var handle = mFakeDevice.getConnectionHandle(TRANSPORT_LE);
+        assertEquals(handle, BluetoothDevice.ERROR);
     }
 
     public void test_getAnonymizedAddress() {
@@ -511,39 +524,4 @@
         }
         return pinBytes;
     }
-
-    public void test_setPreferredAudioProfiles_getPreferredAudioProfiles() {
-        if (!mHasBluetooth || !mHasCompanionDevice) {
-            // Skip the test if bluetooth or companion device are not present.
-            return;
-        }
-        String deviceAddress = "00:11:22:AA:BB:CC";
-        BluetoothDevice device = mAdapter.getRemoteDevice(deviceAddress);
-
-        Bundle preferences = new Bundle();
-        preferences.putInt(BluetoothDevice.AUDIO_MODE_OUTPUT_ONLY, BluetoothProfile.HEADSET);
-
-        // Test invalid input
-        assertThrows(NullPointerException.class, () -> device.setPreferredAudioProfiles(null));
-        assertThrows(IllegalArgumentException.class,
-                () -> device.setPreferredAudioProfiles(preferences));
-
-        preferences.putInt(BluetoothDevice.AUDIO_MODE_OUTPUT_ONLY, BluetoothProfile.LE_AUDIO);
-        preferences.putInt(BluetoothDevice.AUDIO_MODE_DUPLEX, BluetoothProfile.A2DP);
-        assertThrows(IllegalArgumentException.class,
-                () -> device.setPreferredAudioProfiles(preferences));
-
-        preferences.putInt(BluetoothDevice.AUDIO_MODE_DUPLEX, BluetoothProfile.HEADSET);
-
-        // This should throw a SecurityException because no BLUETOOTH_PRIVILEGED permission
-        assertThrows(SecurityException.class, () -> device.setPreferredAudioProfiles(preferences));
-        assertThrows(SecurityException.class, () -> device.getPreferredAudioProfiles());
-
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
-
-        // Verify that the default is an empty bundle for an unknown device
-        assertTrue(device.getPreferredAudioProfiles().isEmpty());
-        assertEquals(BluetoothStatusCodes.ERROR_DEVICE_NOT_BONDED,
-                device.setPreferredAudioProfiles(preferences));
-    }
 }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerCallbackTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerCallbackTest.java
index f247d5e..4ee4038 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerCallbackTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerCallbackTest.java
@@ -122,8 +122,6 @@
     public void tearDown() throws Exception {
         super.tearDown();
         if (mHasBluetooth) {
-            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
             mBluetoothDevice = null;
             mBluetoothGattService = null;
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerTest.java
index 6c9959a..a859e73 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothGattServerTest.java
@@ -70,7 +70,6 @@
                 mBluetoothGattServer.close();
                 mBluetoothGattServer = null;
             }
-            assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
             mBluetoothAdapter = null;
             mUIAutomation.dropShellPermissionIdentity();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
index f7479e5..9a486a7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapClientTest.java
@@ -127,10 +127,7 @@
             mBluetoothHapClient = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            mAdapter = null;
-        }
+        mAdapter = null;
         TestUtils.dropPermissionAsShellUid();
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
index 80f4bbd..2f65320 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHapPresetInfoTest.java
@@ -77,9 +77,6 @@
         if (!(mHasBluetooth && mIsHapSupported)) {
             return;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         TestUtils.dropPermissionAsShellUid();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetClientTest.java
index 69b5747..439e217 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetClientTest.java
@@ -90,9 +90,6 @@
             mBluetoothHeadsetClient = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
index cb2c2b4..5315f33 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHeadsetTest.java
@@ -89,9 +89,6 @@
             mBluetoothHeadset = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         mUiAutomation.dropShellPermissionIdentity();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
index d94deab..f09ef85 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidDeviceTest.java
@@ -101,10 +101,6 @@
             mBluetoothHidDevice = null;
             mIsProfileReady = false;
         }
-        mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         mUiAutomation.dropShellPermissionIdentity();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidHostTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidHostTest.java
index 5c2e86e..f401ba7 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidHostTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothHidHostTest.java
@@ -90,9 +90,6 @@
             mHidHost = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java
index e7f59b8..6cf572b 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAdvertiserTest.java
@@ -73,7 +73,6 @@
             mAdvertiser.stopAdvertisingSet(mCallback);
             assertTrue(mCallback.mAdvertisingSetStoppedLatch.await(TIMEOUT_MS,
                     TimeUnit.MILLISECONDS));
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdvertiser = null;
             mAdapter = null;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
index b40b52d..21ad04f 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioCodecConfigMetadataTest.java
@@ -93,9 +93,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
index ddb6bca..0e156cf 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioContentMetadataTest.java
@@ -101,9 +101,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
index 9aba70c..f6e02de 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeAudioTest.java
@@ -151,9 +151,6 @@
             mBluetoothLeAudio = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         TestUtils.dropPermissionAsShellUid();
         mAdapter = null;
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
index 6138f38..bd49353 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastAssistantTest.java
@@ -147,9 +147,6 @@
                 mBluetoothLeBroadcastAssistant = null;
                 mIsProfileReady = false;
             }
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
index e4d0577..424a64e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastChannelTest.java
@@ -90,9 +90,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
index 7ff121a..5edeb38 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastMetadataTest.java
@@ -114,9 +114,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
index 8f9b0f7..fad215d 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastReceiveStateTest.java
@@ -105,9 +105,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
index 7279ef6..c87a95e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastSubgroupTest.java
@@ -104,9 +104,6 @@
     @After
     public void tearDown() {
         if (mHasBluetooth) {
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
index 64d3000..b69cfda 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeBroadcastTest.java
@@ -199,9 +199,6 @@
                 mBluetoothLeBroadcast = null;
                 mIsProfileReady = false;
             }
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
index 2278e86..f63e02e 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothLeScanTest.java
@@ -102,7 +102,6 @@
         if (!mLocationOn) {
             TestUtils.disableLocation(getContext());
         }
-        assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
                 .dropShellPermissionIdentity();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapClientTest.java
index 4a6cd06..c0a3037 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapClientTest.java
@@ -105,9 +105,6 @@
             mBluetoothMapClient = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapTest.java
index 6a7fe34..bdc5d42 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothMapTest.java
@@ -93,9 +93,6 @@
             mBluetoothMap = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java
index 733d9f3..11954a3 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPanTest.java
@@ -86,9 +86,6 @@
             mBluetoothPan = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         TestUtils.dropPermissionAsShellUid();
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapClientTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapClientTest.java
index 7b3df4e..1ce2b0b 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapClientTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapClientTest.java
@@ -89,9 +89,6 @@
             mBluetoothPbapClient = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapTest.java
index 382a292..fadffd9 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothPbapTest.java
@@ -91,9 +91,6 @@
             mBluetoothPbap = null;
             mIsProfileReady = false;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
index ad5cfff..9dad13a 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothSapTest.java
@@ -88,10 +88,6 @@
                 mBluetoothSap = null;
                 mIsProfileReady = false;
             }
-            mUiAutomation.adoptShellPermissionIdentity(BLUETOOTH_CONNECT);
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-            }
             mUiAutomation.dropShellPermissionIdentity();
             mAdapter = null;
         }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServerSocketTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServerSocketTest.java
index 134e4bd..ba3cc71 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServerSocketTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothServerSocketTest.java
@@ -60,7 +60,6 @@
             if (mHasBluetooth && mBluetoothServerSocket != null) {
                 mBluetoothServerSocket.close();
             }
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
             mAdapter = null;
             mBluetoothServerSocket = null;
             mUiAutomation.dropShellPermissionIdentity();
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
index 26237c1..32eeb02 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/BluetoothVolumeControlTest.java
@@ -117,10 +117,7 @@
                 mTestCallback = null;
                 mTestExecutor = null;
             }
-            if (mAdapter != null) {
-                assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-                mAdapter = null;
-            }
+            mAdapter = null;
             TestUtils.dropPermissionAsShellUid();
         }
     }
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
index 7818a04..945e6ee 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/HearingAidProfileTest.java
@@ -108,9 +108,6 @@
         if (!(mIsBleSupported && mIsHearingAidSupported)) {
             return;
         }
-        if (mBluetoothAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mBluetoothAdapter, mContext));
-        }
         mUiAutomation.dropShellPermissionIdentity();
     }
 
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
index 62d1c6a..7973808 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/LeL2capSocketTest.java
@@ -51,9 +51,6 @@
         if (!TestUtils.isBleSupported(getContext())) {
             return;
         }
-        if (mAdapter != null) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
         mAdapter = null;
         InstrumentationRegistry.getInstrumentation().getUiAutomation()
             .dropShellPermissionIdentity();
diff --git a/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java b/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java
index e9a9314..bfaf557 100644
--- a/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java
+++ b/tests/tests/bluetooth/src/android/bluetooth/cts/SystemBluetoothTest.java
@@ -82,9 +82,6 @@
     @Override
     public void tearDown() throws Exception {
         super.tearDown();
-        if (mHasBluetooth) {
-            assertTrue(BTAdapterUtils.disableAdapter(mAdapter, mContext));
-        }
     }
 
     /**
diff --git a/tests/tests/contactsproviderwipe/Android.bp b/tests/tests/contactsproviderwipe/Android.bp
index 2a82727..62cf0c0 100644
--- a/tests/tests/contactsproviderwipe/Android.bp
+++ b/tests/tests/contactsproviderwipe/Android.bp
@@ -25,7 +25,6 @@
         "mockito-target-minus-junit4",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
-        "ub-uiautomator",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/tests/content/Android.bp b/tests/tests/content/Android.bp
index 7a691f9..d7d1424 100644
--- a/tests/tests/content/Android.bp
+++ b/tests/tests/content/Android.bp
@@ -26,6 +26,7 @@
     // Include both the 32 and 64 bit versions
     compile_multilib: "both",
     jni_libs: [
+        "libcts_jni",
         "libnativecursorwindow_jni",
         "libnativehelper_compat_libc++",
     ],
diff --git a/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java b/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
index b519f7b..086c607 100644
--- a/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/ChecksumsTest.java
@@ -71,6 +71,8 @@
 import com.android.server.pm.PackageManagerShellCommandDataLoader;
 import com.android.server.pm.PackageManagerShellCommandDataLoader.Metadata;
 
+import com.android.compatibility.common.util.CpuFeatures;
+
 import org.junit.After;
 import org.junit.Assert;
 import org.junit.Assume;
@@ -157,8 +159,6 @@
             new Checksum(TYPE_WHOLE_SHA256, hexStringToBytes(TEST_FIXED_APK_SHA256)),
             new Checksum(TYPE_WHOLE_MD5, hexStringToBytes(TEST_FIXED_APK_MD5))};
 
-    private static final String PRIMARY_ABI = Build.SUPPORTED_ABIS[0];
-
     /** Default is to not use fs-verity since it depends on kernel support. */
     private static final int FSVERITY_DISABLED = 0;
 
@@ -338,19 +338,18 @@
         assertNotNull(checksums);
         assertEquals(checksums.length, 2);
         assertEquals(checksums[0].getType(), TYPE_WHOLE_MERKLE_ROOT_4K_SHA256);
-        if ("x86_64".equals(PRIMARY_ABI) || "x86".equals(PRIMARY_ABI)) {
-            assertEquals(bytesToHexString(checksums[0].getValue()),
-                    TEST_FIXED_APK_FSVERITY_SHA256_X86_64);
-            assertEquals(bytesToHexString(checksums[1].getValue()),
-                    "6f7cfa569c4a25d7241e26c1c8ff274badbdefd7854d91b842b1a97a985d5917");
-        } else if ("arm64-v8a".equals(PRIMARY_ABI) || "armeabi".equals(PRIMARY_ABI)
-                || "armeabi-v7a".equals(PRIMARY_ABI)) {
+        if (CpuFeatures.isArm64Cpu() || CpuFeatures.isArmCpu()) {
             assertEquals(bytesToHexString(checksums[0].getValue()),
                     TEST_FIXED_APK_FSVERITY_SHA256_ARM64);
             assertEquals(bytesToHexString(checksums[1].getValue()),
                     "8c61bc2548521aa0005276af68e42253957e1e24c122f7d8bf10f1832d4014e5");
+        } else if (CpuFeatures.isX86_64Cpu() || CpuFeatures.isX86Cpu()) {
+            assertEquals(bytesToHexString(checksums[0].getValue()),
+                    TEST_FIXED_APK_FSVERITY_SHA256_X86_64);
+            assertEquals(bytesToHexString(checksums[1].getValue()),
+                    "6f7cfa569c4a25d7241e26c1c8ff274badbdefd7854d91b842b1a97a985d5917");
         } else {
-            Assert.fail("Unsupported ABI: " + PRIMARY_ABI);
+            Assert.fail("Unsupported CPU ABI");
         }
         assertEquals(checksums[1].getType(), TYPE_PARTIAL_MERKLE_ROOT_1M_SHA256);
     }
@@ -373,15 +372,14 @@
         assertNotNull(checksums);
         assertEquals(checksums.length, 1);
         assertEquals(checksums[0].getType(), TYPE_WHOLE_MERKLE_ROOT_4K_SHA256);
-        if ("x86_64".equals(PRIMARY_ABI) || "x86".equals(PRIMARY_ABI)) {
-            assertEquals(bytesToHexString(checksums[0].getValue()),
-                    TEST_FIXED_APK_FSVERITY_SHA256_X86_64);
-        } else if ("arm64-v8a".equals(PRIMARY_ABI) || "armeabi".equals(PRIMARY_ABI)
-                || "armeabi-v7a".equals(PRIMARY_ABI)) {
+        if (CpuFeatures.isArm64Cpu() || CpuFeatures.isArmCpu()) {
             assertEquals(bytesToHexString(checksums[0].getValue()),
                     TEST_FIXED_APK_FSVERITY_SHA256_ARM64);
+        } else if (CpuFeatures.isX86_64Cpu() || CpuFeatures.isX86Cpu()) {
+            assertEquals(bytesToHexString(checksums[0].getValue()),
+                    TEST_FIXED_APK_FSVERITY_SHA256_X86_64);
         } else {
-            Assert.fail("Unsupported ABI: " + PRIMARY_ABI);
+            Assert.fail("Unsupported CPU ABI");
         }
     }
 
diff --git a/tests/tests/drm/TEST_MAPPING b/tests/tests/drm/TEST_MAPPING
index 437c95c..d2fb8f4 100644
--- a/tests/tests/drm/TEST_MAPPING
+++ b/tests/tests/drm/TEST_MAPPING
@@ -3,5 +3,16 @@
     {
       "name": "CtsDrmTestCases"
     }
+  ],
+  "kernel-presubmit": [
+    {
+      "name": "CtsDrmTestCases",
+      "options": [
+        {
+          // TODO(b/244594813)
+          "exclude-filter": "android.drm.cts.DRMTest#testForwardLockAccess"
+        }
+      ]
+    }
   ]
 }
diff --git a/tests/tests/gameservice/TEST_MAPPING b/tests/tests/gameservice/TEST_MAPPING
index 8d6b802..6a5661b 100644
--- a/tests/tests/gameservice/TEST_MAPPING
+++ b/tests/tests/gameservice/TEST_MAPPING
@@ -1,7 +1,12 @@
 {
   "presubmit": [
     {
-      "name": "CtsGameServiceTestCases"
+      "name": "CtsGameServiceTestCases",
+      "options": [
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/tests/gameservice/src/android/service/games/GameServiceTest.java b/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
index aada0a0..d31f61c 100644
--- a/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
+++ b/tests/tests/gameservice/src/android/service/games/GameServiceTest.java
@@ -60,6 +60,7 @@
 import android.view.WindowMetrics;
 
 import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.PollingCheck;
@@ -88,6 +89,7 @@
 /**
  * CTS tests for {@link android.service.games.GameService}.
  */
+@FlakyTest(bugId = 263181277)
 @RunWith(AndroidJUnit4.class)
 public final class GameServiceTest {
     static final String TAG = "GameServiceTest";
diff --git a/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
index 829855a..bb0c651 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_AImageDecoderTest.cpp
@@ -45,6 +45,8 @@
     AImageDecoder* decoderPtr = nullptr;
     for (AImageDecoder** outDecoder : { &decoderPtr, (AImageDecoder**) nullptr }) {
         for (AAsset* asset : { nullptr }) {
+            // Intentional negative test to pass nullptr.
+            // NOLINTNEXTLINE(clang-analyzer-nullability.NullPassedToNonnull)
             int result = AImageDecoder_createFromAAsset(asset, outDecoder);
             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
             if (outDecoder) {
@@ -53,6 +55,8 @@
         }
 
         for (int fd : { 0, -1 }) {
+            // Intentional negative test to pass nullptr.
+            // NOLINTNEXTLINE(clang-analyzer-nullability.NullPassedToNonnull)
             int result = AImageDecoder_createFromFd(fd, outDecoder);
             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
             if (outDecoder) {
@@ -61,6 +65,8 @@
         }
 
         auto testEmptyBuffer = [env, outDecoder](void* buffer, size_t length) {
+            // Intentional negative test to pass nullptr.
+            // NOLINTNEXTLINE(clang-analyzer-nullability.NullPassedToNonnull)
             int result = AImageDecoder_createFromBuffer(buffer, length, outDecoder);
             ASSERT_EQ(ANDROID_IMAGE_DECODER_BAD_PARAMETER, result);
             if (outDecoder) {
diff --git a/tests/tests/hardware/Android.bp b/tests/tests/hardware/Android.bp
index ad603cc..9d337e4 100644
--- a/tests/tests/hardware/Android.bp
+++ b/tests/tests/hardware/Android.bp
@@ -65,7 +65,6 @@
         "cts-wm-util",
         "mockito-target-minus-junit4",
         "platform-test-annotations",
-        "ub-uiautomator",
         "ctshardware-aidl-java",
     ],
     jni_libs: [
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/UsbVoiceCommandTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/UsbVoiceCommandTest.java
index a834b0d..2e13f30 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/UsbVoiceCommandTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/UsbVoiceCommandTest.java
@@ -31,7 +31,6 @@
 import android.hardware.input.cts.InputAssistantActivity;
 import android.server.wm.WindowManagerStateHelper;
 import android.speech.RecognizerIntent;
-import android.support.test.uiautomator.UiDevice;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -50,8 +49,6 @@
 public class UsbVoiceCommandTest extends InputHidTestCase {
     private static final String TAG = "UsbVoiceCommandTest";
 
-    private final UiDevice mUiDevice =
-            UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
     private final UiAutomation mUiAutomation =
             InstrumentationRegistry.getInstrumentation().getUiAutomation();
     private final PackageManager mPackageManager =
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c b/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
index 597f03b..2e41c93 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
+++ b/tests/tests/jni/libjnitest/android_jni_cts_InstanceNonce.c
@@ -31,56 +31,135 @@
     // This space intentionally left blank.
 }
 
+// public native void nopDlsym();
+JNIEXPORT void Java_android_jni_cts_InstanceNonce_nopDlsym(JNIEnv *env,
+        jobject this) {
+    // This space intentionally left blank.
+}
+
+// @FastNative
+// public native void nopFast();
+static void InstanceNonce_nopFast(JNIEnv *env, jobject this) {
+    // This space intentionally left blank.
+}
+
+// @FastNative
+// public native void nopFastDlsym();
+JNIEXPORT void Java_android_jni_cts_InstanceNonce_nopFastDlsym(JNIEnv *env,
+        jobject this) {
+    // This space intentionally left blank.
+}
+
 // public native boolean returnBoolean();
 static jboolean InstanceNonce_returnBoolean(JNIEnv *env, jobject this) {
     return (jboolean) false;
 }
 
+// @FastNative
+// public native boolean returnBooleanFast();
+static jboolean InstanceNonce_returnBooleanFast(JNIEnv *env, jobject this) {
+    return (jboolean) false;
+}
+
 // public native byte returnByte();
 static jbyte InstanceNonce_returnByte(JNIEnv *env, jobject this) {
     return (jbyte) 123;
 }
 
+// @FastNative
+// public native byte returnByteFast();
+static jbyte InstanceNonce_returnByteFast(JNIEnv *env, jobject this) {
+    return (jbyte) 123;
+}
+
 // public native short returnShort();
 static jshort InstanceNonce_returnShort(JNIEnv *env, jobject this) {
     return (jshort) -12345;
 }
 
+// @FastNative
+// public native short returnShortFast();
+static jshort InstanceNonce_returnShortFast(JNIEnv *env, jobject this) {
+    return (jshort) -12345;
+}
+
 // public native char returnChar();
 static jchar InstanceNonce_returnChar(JNIEnv *env, jobject this) {
     return (jchar) 34567;
 }
 
+// @FastNative
+// public native char returnCharFast();
+static jchar InstanceNonce_returnCharFast(JNIEnv *env, jobject this) {
+    return (jchar) 34567;
+}
+
 // public native int returnInt();
 static jint InstanceNonce_returnInt(JNIEnv *env, jobject this) {
     return 12345678;
 }
 
+// @FastNative
+// public native int returnIntFast();
+static jint InstanceNonce_returnIntFast(JNIEnv *env, jobject this) {
+    return 12345678;
+}
+
 // public native long returnLong();
 static jlong InstanceNonce_returnLong(JNIEnv *env, jobject this) {
     return (jlong) -1098765432109876543LL;
 }
 
+// @FastNative
+// public native long returnLongFast();
+static jlong InstanceNonce_returnLongFast(JNIEnv *env, jobject this) {
+    return (jlong) -1098765432109876543LL;
+}
+
 // public native float returnFloat();
 static jfloat InstanceNonce_returnFloat(JNIEnv *env, jobject this) {
     return (jfloat) -98765.4321F;
 }
 
+// @FastNative
+// public native float returnFloatFast();
+static jfloat InstanceNonce_returnFloatFast(JNIEnv *env, jobject this) {
+    return (jfloat) -98765.4321F;
+}
+
 // public native double returnDouble();
 static jdouble InstanceNonce_returnDouble(JNIEnv *env, jobject this) {
     return 12345678.9;
 }
 
+// @FastNative
+// public native double returnDoubleFast();
+static jdouble InstanceNonce_returnDoubleFast(JNIEnv *env, jobject this) {
+    return 12345678.9;
+}
+
 // public native Object returnNull();
 static jobject InstanceNonce_returnNull(JNIEnv *env, jobject this) {
     return NULL;
 }
 
+// @FastNative
+// public native Object returnNullFast();
+static jobject InstanceNonce_returnNullFast(JNIEnv *env, jobject this) {
+    return NULL;
+}
+
 // public native String returnString();
 static jstring InstanceNonce_returnString(JNIEnv *env, jobject this) {
     return (*env)->NewStringUTF(env, "blort");
 }
 
+// @FastNative
+// public native String returnStringFast();
+static jstring InstanceNonce_returnStringFast(JNIEnv *env, jobject this) {
+    return (*env)->NewStringUTF(env, "blort");
+}
+
 // public native short[] returnShortArray();
 static jshortArray InstanceNonce_returnShortArray(JNIEnv *env, jobject this) {
     static jshort contents[] = { 10, 20, 30 };
@@ -95,6 +174,13 @@
     return result;
 }
 
+// @FastNative
+// public native short[] returnShortArrayFast();
+static jshortArray InstanceNonce_returnShortArrayFast(JNIEnv *env,
+        jobject this) {
+    return InstanceNonce_returnShortArray(env, this);
+}
+
 // public String[] returnStringArray();
 static jobjectArray InstanceNonce_returnStringArray(JNIEnv *env,
         jobject this) {
@@ -136,58 +222,133 @@
     return result;
 }
 
+// @FastNative
+// public String[] returnStringArrayFast();
+static jobjectArray InstanceNonce_returnStringArrayFast(JNIEnv *env,
+        jobject this) {
+    return InstanceNonce_returnStringArray(env, this);
+}
+
 // public native Class returnThisClass();
 static jobject InstanceNonce_returnThis(JNIEnv *env, jobject this) {
     return this;
 }
 
+// @FastNative
+// public native Class returnThisClassFast();
+static jobject InstanceNonce_returnThisFast(JNIEnv *env, jobject this) {
+    return this;
+}
+
 // public native boolean takeBoolean(boolean v);
 static jboolean InstanceNonce_takeBoolean(JNIEnv *env, jobject this,
         jboolean v) {
     return v == false;
 }
 
+// @FastNative
+// public native boolean takeBooleanFast(boolean v);
+static jboolean InstanceNonce_takeBooleanFast(JNIEnv *env, jobject this,
+        jboolean v) {
+    return v == false;
+}
+
 // public native boolean takeByte(byte v);
 static jboolean InstanceNonce_takeByte(JNIEnv *env, jobject this, jbyte v) {
     return v == -99;
 }
 
+// @FastNative
+// public native boolean takeByteFast(byte v);
+static jboolean InstanceNonce_takeByteFast(JNIEnv *env, jobject this,
+        jbyte v) {
+    return v == -99;
+}
+
 // public native boolean takeShort(short v);
 static jboolean InstanceNonce_takeShort(JNIEnv *env, jobject this, jshort v) {
     return v == 19991;
 }
 
+// @FastNative
+// public native boolean takeShortFast(short v);
+static jboolean InstanceNonce_takeShortFast(JNIEnv *env, jobject this,
+        jshort v) {
+    return v == 19991;
+}
+
 // public native boolean takeChar(char v);
 static jboolean InstanceNonce_takeChar(JNIEnv *env, jobject this, jchar v) {
     return v == 999;
 }
 
+// @FastNative
+// public native boolean takeCharFast(char v);
+static jboolean InstanceNonce_takeCharFast(JNIEnv *env, jobject this,
+        jchar v) {
+    return v == 999;
+}
+
 // public native boolean takeInt(int v);
 static jboolean InstanceNonce_takeInt(JNIEnv *env, jobject this, jint v) {
     return v == -999888777;
 }
 
+// @FastNative
+// public native boolean takeIntFast(int v);
+static jboolean InstanceNonce_takeIntFast(JNIEnv *env, jobject this, jint v) {
+    return v == -999888777;
+}
+
 // public native boolean takeLong(long v);
 static jboolean InstanceNonce_takeLong(JNIEnv *env, jobject this, jlong v) {
     return v == 999888777666555444LL;
 }
 
+// @FastNative
+// public native boolean takeLongFast(long v);
+static jboolean InstanceNonce_takeLongFast(JNIEnv *env, jobject this,
+        jlong v) {
+    return v == 999888777666555444LL;
+}
+
 // public native boolean takeFloat(float v);
 static jboolean InstanceNonce_takeFloat(JNIEnv *env, jobject this, jfloat v) {
     return v == -9988.7766F;
 }
 
+// @FastNative
+// public native boolean takeFloatFast(float v);
+static jboolean InstanceNonce_takeFloatFast(JNIEnv *env, jobject this,
+        jfloat v) {
+    return v == -9988.7766F;
+}
+
 // public native boolean takeDouble(double v);
 static jboolean InstanceNonce_takeDouble(JNIEnv *env, jobject this,
         jdouble v) {
     return v == 999888777.666555;
 }
 
+// @FastNative
+// public native boolean takeDoubleFast(double v);
+static jboolean InstanceNonce_takeDoubleFast(JNIEnv *env, jobject this,
+        jdouble v) {
+    return v == 999888777.666555;
+}
+
 // public native boolean takeNull(Object v);
 static jboolean InstanceNonce_takeNull(JNIEnv *env, jobject this, jobject v) {
     return v == NULL;
 }
 
+// @FastNative
+// public native boolean takeNullFast(Object v);
+static jboolean InstanceNonce_takeNullFast(JNIEnv *env, jobject this,
+        jobject v) {
+    return v == NULL;
+}
+
 // public native boolean takeString(String v);
 static jboolean InstanceNonce_takeString(JNIEnv *env, jobject this,
         jstring v) {
@@ -202,23 +363,51 @@
     return result;
 }
 
+// @FastNative
+// public native boolean takeStringFast(String v);
+static jboolean InstanceNonce_takeStringFast(JNIEnv *env, jobject this,
+        jstring v) {
+    return InstanceNonce_takeString(env, this, v);
+}
+
 // public native boolean takeThis(InstanceNonce v);
 static jboolean InstanceNonce_takeThis(JNIEnv *env, jobject this, jobject v) {
     return (*env)->IsSameObject(env, this, v);
 }
 
+// @FastNative
+// public native boolean takeThisFast(InstanceNonce v);
+static jboolean InstanceNonce_takeThisFast(JNIEnv *env, jobject this,
+        jobject v) {
+    return (*env)->IsSameObject(env, this, v);
+}
+
 // public native boolean takeIntLong(int v1, long v2);
 static jboolean InstanceNonce_takeIntLong(JNIEnv *env, jobject this,
         jint v1, jlong v2) {
     return (v1 == 914) && (v2 == 9140914091409140914LL);
 }
 
+// @FastNative
+// public native boolean takeIntLongFast(int v1, long v2);
+static jboolean InstanceNonce_takeIntLongFast(JNIEnv *env, jobject this,
+        jint v1, jlong v2) {
+    return (v1 == 914) && (v2 == 9140914091409140914LL);
+}
+
 // public native boolean takeLongInt(long v1, int v2);
 static jboolean InstanceNonce_takeLongInt(JNIEnv *env, jobject this,
         jlong v1, jint v2) {
     return (v1 == -4321LL) && (v2 == 12341234);
 }
 
+// @FastNative
+// public native boolean takeLongIntFast(long v1, int v2);
+static jboolean InstanceNonce_takeLongIntFast(JNIEnv *env, jobject this,
+        jlong v1, jint v2) {
+    return (v1 == -4321LL) && (v2 == 12341234);
+}
+
 // public native boolean takeOneOfEach(boolean v0, byte v1, short v2,
 //         char v3, int v4, long v5, String v6, float v7, double v8,
 //         int[] v9);
@@ -262,6 +451,38 @@
     return result;
 }
 
+// public native boolean takeOneOfEachDlsym(boolean v0, byte v1, short v2,
+//         char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+JNIEXPORT jboolean Java_android_jni_cts_InstanceNonce_takeOneOfEachDlsym(
+        JNIEnv *env, jobject this, jboolean v0, jbyte v1, jshort v2, jchar v3,
+        jint v4, jlong v5, jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return InstanceNonce_takeOneOfEach(
+            env, this, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
+// @FastNative
+// public native boolean takeOneOfEachFast(boolean v0, byte v1, short v2,
+//         char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+static jboolean InstanceNonce_takeOneOfEachFast(JNIEnv *env, jobject this,
+        jboolean v0, jbyte v1, jshort v2, jchar v3, jint v4, jlong v5,
+        jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return InstanceNonce_takeOneOfEach(
+            env, this, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
+// @FastNative
+// public native boolean takeOneOfEachFastDlsym(boolean v0, byte v1, short v2,
+//         char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+JNIEXPORT jboolean Java_android_jni_cts_InstanceNonce_takeOneOfEachFastDlsym(
+        JNIEnv *env, jobject this, jboolean v0, jbyte v1, jshort v2, jchar v3,
+        jint v4, jlong v5, jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return InstanceNonce_takeOneOfEach(
+            env, this, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
 // public native boolean takeCoolHandLuke(
 //         int v1, int v2, int v3, int v4,
 //         int v5, int v6, int v7, int v8, int v9,
@@ -304,44 +525,116 @@
         (v50 == 50);
 }
 
+// @FastNative
+// public native boolean takeCoolHandLukeFast(
+//         int v1, int v2, int v3, int v4,
+//         int v5, int v6, int v7, int v8, int v9,
+//         int v10, int v11, int v12, int v13, int v14,
+//         int v15, int v16, int v17, int v18, int v19,
+//         int v20, int v21, int v22, int v23, int v24,
+//         int v25, int v26, int v27, int v28, int v29,
+//         int v30, int v31, int v32, int v33, int v34,
+//         int v35, int v36, int v37, int v38, int v39,
+//         int v40, int v41, int v42, int v43, int v44,
+//         int v45, int v46, int v47, int v48, int v49,
+//         int v50);
+static jboolean InstanceNonce_takeCoolHandLukeFast(JNIEnv *env, jobject this,
+        jint v1, jint v2, jint v3, jint v4,
+        jint v5, jint v6, jint v7, jint v8, jint v9,
+        jint v10, jint v11, jint v12, jint v13, jint v14,
+        jint v15, jint v16, jint v17, jint v18, jint v19,
+        jint v20, jint v21, jint v22, jint v23, jint v24,
+        jint v25, jint v26, jint v27, jint v28, jint v29,
+        jint v30, jint v31, jint v32, jint v33, jint v34,
+        jint v35, jint v36, jint v37, jint v38, jint v39,
+        jint v40, jint v41, jint v42, jint v43, jint v44,
+        jint v45, jint v46, jint v47, jint v48, jint v49,
+        jint v50) {
+    return InstanceNonce_takeCoolHandLuke(
+            env, this, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+            v11, v12, v13, v14, v15, v16, v17, v18, v19, v20,
+            v21, v22, v23, v24, v25, v26, v27, v28, v29, v30,
+            v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+            v41, v42, v43, v44, v45, v46, v47, v48, v49, v50);
+}
+
 static JNINativeMethod methods[] = {
     // name, signature, function
     { "nop",               "()V", InstanceNonce_nop },
+    { "nopFast",           "()V", InstanceNonce_nopFast },
     { "returnBoolean",     "()Z", InstanceNonce_returnBoolean },
+    { "returnBooleanFast", "()Z", InstanceNonce_returnBooleanFast },
     { "returnByte",        "()B", InstanceNonce_returnByte },
+    { "returnByteFast",    "()B", InstanceNonce_returnByteFast },
     { "returnShort",       "()S", InstanceNonce_returnShort },
+    { "returnShortFast",   "()S", InstanceNonce_returnShortFast },
     { "returnChar",        "()C", InstanceNonce_returnChar },
+    { "returnCharFast",    "()C", InstanceNonce_returnCharFast },
     { "returnInt",         "()I", InstanceNonce_returnInt },
+    { "returnIntFast",     "()I", InstanceNonce_returnIntFast },
     { "returnLong",        "()J", InstanceNonce_returnLong },
+    { "returnLongFast",    "()J", InstanceNonce_returnLongFast },
     { "returnFloat",       "()F", InstanceNonce_returnFloat },
+    { "returnFloatFast",   "()F", InstanceNonce_returnFloatFast },
     { "returnDouble",      "()D", InstanceNonce_returnDouble },
+    { "returnDoubleFast",  "()D", InstanceNonce_returnDoubleFast },
     { "returnNull",        "()Ljava/lang/Object;", InstanceNonce_returnNull },
+    { "returnNullFast",    "()Ljava/lang/Object;",
+      InstanceNonce_returnNullFast },
     { "returnString",      "()Ljava/lang/String;",
       InstanceNonce_returnString },
+    { "returnStringFast",  "()Ljava/lang/String;",
+      InstanceNonce_returnStringFast },
     { "returnShortArray",  "()[S", InstanceNonce_returnShortArray },
+    { "returnShortArrayFast", "()[S", InstanceNonce_returnShortArrayFast },
     { "returnStringArray", "()[Ljava/lang/String;",
       InstanceNonce_returnStringArray },
+    { "returnStringArrayFast", "()[Ljava/lang/String;",
+      InstanceNonce_returnStringArrayFast },
     { "returnThis",        "()Landroid/jni/cts/InstanceNonce;",
       InstanceNonce_returnThis },
+    { "returnThisFast",    "()Landroid/jni/cts/InstanceNonce;",
+      InstanceNonce_returnThisFast },
     { "takeBoolean",       "(Z)Z", InstanceNonce_takeBoolean },
+    { "takeBooleanFast",   "(Z)Z", InstanceNonce_takeBooleanFast },
     { "takeByte",          "(B)Z", InstanceNonce_takeByte },
+    { "takeByteFast",      "(B)Z", InstanceNonce_takeByteFast },
     { "takeShort",         "(S)Z", InstanceNonce_takeShort },
+    { "takeShortFast",     "(S)Z", InstanceNonce_takeShortFast },
     { "takeChar",          "(C)Z", InstanceNonce_takeChar },
+    { "takeCharFast",      "(C)Z", InstanceNonce_takeCharFast },
     { "takeInt",           "(I)Z", InstanceNonce_takeInt },
+    { "takeIntFast",       "(I)Z", InstanceNonce_takeIntFast },
     { "takeLong",          "(J)Z", InstanceNonce_takeLong },
+    { "takeLongFast",      "(J)Z", InstanceNonce_takeLongFast },
     { "takeFloat",         "(F)Z", InstanceNonce_takeFloat },
+    { "takeFloatFast",     "(F)Z", InstanceNonce_takeFloatFast },
     { "takeDouble",        "(D)Z", InstanceNonce_takeDouble },
+    { "takeDoubleFast",    "(D)Z", InstanceNonce_takeDoubleFast },
     { "takeNull",          "(Ljava/lang/Object;)Z", InstanceNonce_takeNull },
+    { "takeNullFast",      "(Ljava/lang/Object;)Z",
+      InstanceNonce_takeNullFast },
     { "takeString",        "(Ljava/lang/String;)Z", InstanceNonce_takeString },
+    { "takeStringFast",    "(Ljava/lang/String;)Z",
+      InstanceNonce_takeStringFast },
     { "takeThis",          "(Landroid/jni/cts/InstanceNonce;)Z",
       InstanceNonce_takeThis },
+    { "takeThisFast",      "(Landroid/jni/cts/InstanceNonce;)Z",
+      InstanceNonce_takeThisFast },
     { "takeIntLong",       "(IJ)Z", InstanceNonce_takeIntLong },
+    { "takeIntLongFast",   "(IJ)Z", InstanceNonce_takeIntLongFast },
     { "takeLongInt",       "(JI)Z", InstanceNonce_takeLongInt },
+    { "takeLongIntFast",   "(JI)Z", InstanceNonce_takeLongIntFast },
     { "takeOneOfEach",     "(ZBSCIJLjava/lang/String;FD[I)Z",
       InstanceNonce_takeOneOfEach },
+    { "takeOneOfEachFast", "(ZBSCIJLjava/lang/String;FD[I)Z",
+      InstanceNonce_takeOneOfEachFast },
     { "takeCoolHandLuke",
       "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z",
       InstanceNonce_takeCoolHandLuke },
+    { "takeCoolHandLukeFast",
+      "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z",
+      InstanceNonce_takeCoolHandLukeFast },
 };
 
 int register_InstanceNonce(JNIEnv *env) {
diff --git a/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c b/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
index 7fb7f11..f3ed593 100644
--- a/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
+++ b/tests/tests/jni/libjnitest/android_jni_cts_StaticNonce.c
@@ -31,56 +31,195 @@
     // This space intentionally left blank.
 }
 
+// public static native void nopDlsym();
+JNIEXPORT void Java_android_jni_cts_StaticNonce_nopDlsym(JNIEnv *env,
+        jclass clazz) {
+    // This space intentionally left blank.
+}
+
+// @FastNative
+// public static native void nopFast();
+static void StaticNonce_nopFast(JNIEnv *env, jclass clazz) {
+    // This space intentionally left blank.
+}
+
+// @FastNative
+// public static native void nopFastDlsym();
+JNIEXPORT void Java_android_jni_cts_StaticNonce_nopFastDlsym(JNIEnv *env,
+        jclass clazz) {
+    // This space intentionally left blank.
+}
+
+// @CriticalNative
+// public static native void nopCritical();
+static void StaticNonce_nopCritical() {
+    // This space intentionally left blank.
+}
+
+// @CriticalNative
+// public static native void nopCriticalDlsym();
+JNIEXPORT void Java_android_jni_cts_StaticNonce_nopCriticalDlsym() {
+    // This space intentionally left blank.
+}
+
 // public static native boolean returnBoolean();
 static jboolean StaticNonce_returnBoolean(JNIEnv *env, jclass clazz) {
     return (jboolean) true;
 }
 
+// @FastNative
+// public static native boolean returnBooleanFast();
+static jboolean StaticNonce_returnBooleanFast(JNIEnv *env, jclass clazz) {
+    return (jboolean) true;
+}
+
+// @CriticalNative
+// public static native boolean returnBooleanCritical();
+static jboolean StaticNonce_returnBooleanCritical() {
+    return (jboolean) true;
+}
+
 // public static native byte returnByte();
 static jbyte StaticNonce_returnByte(JNIEnv *env, jclass clazz) {
     return (jbyte) 123;
 }
 
+// @FastNative
+// public static native byte returnByteFast();
+static jbyte StaticNonce_returnByteFast(JNIEnv *env, jclass clazz) {
+    return (jbyte) 123;
+}
+
+// @CriticalNative
+// public static native byte returnByteCritical();
+static jbyte StaticNonce_returnByteCritical() {
+    return (jbyte) 123;
+}
+
 // public static native short returnShort();
 static jshort StaticNonce_returnShort(JNIEnv *env, jclass clazz) {
     return (jshort) -12345;
 }
 
+// @FastNative
+// public static native short returnShortFast();
+static jshort StaticNonce_returnShortFast(JNIEnv *env, jclass clazz) {
+    return (jshort) -12345;
+}
+
+// @CriticalNative
+// public static native short returnShortCritical();
+static jshort StaticNonce_returnShortCritical() {
+    return (jshort) -12345;
+}
+
 // public static native char returnChar();
 static jchar StaticNonce_returnChar(JNIEnv *env, jclass clazz) {
     return (jchar) 34567;
 }
 
+// @FastNative
+// public static native char returnCharFast();
+static jchar StaticNonce_returnCharFast(JNIEnv *env, jclass clazz) {
+    return (jchar) 34567;
+}
+
+// @CriticalNative
+// public static native char returnCharCritical();
+static jchar StaticNonce_returnCharCritical() {
+    return (jchar) 34567;
+}
+
 // public static native int returnInt();
 static jint StaticNonce_returnInt(JNIEnv *env, jclass clazz) {
     return 12345678;
 }
 
+// @FastNative
+// public static native int returnIntFast();
+static jint StaticNonce_returnIntFast(JNIEnv *env, jclass clazz) {
+    return 12345678;
+}
+
+// @CriticalNative
+// public static native int returnIntCritical();
+static jint StaticNonce_returnIntCritical() {
+    return 12345678;
+}
+
 // public static native long returnLong();
 static jlong StaticNonce_returnLong(JNIEnv *env, jclass clazz) {
     return (jlong) -1098765432109876543LL;
 }
 
+// @FastNative
+// public static native long returnLongFast();
+static jlong StaticNonce_returnLongFast(JNIEnv *env, jclass clazz) {
+    return (jlong) -1098765432109876543LL;
+}
+
+// @CriticalNative
+// public static native long returnLongCritical();
+static jlong StaticNonce_returnLongCritical() {
+    return (jlong) -1098765432109876543LL;
+}
+
 // public static native float returnFloat();
 static jfloat StaticNonce_returnFloat(JNIEnv *env, jclass clazz) {
     return (jfloat) -98765.4321F;
 }
 
+// @FastNative
+// public static native float returnFloatFast();
+static jfloat StaticNonce_returnFloatFast(JNIEnv *env, jclass clazz) {
+    return (jfloat) -98765.4321F;
+}
+
+// @CriticalNative
+// public static native float returnFloatCritical();
+static jfloat StaticNonce_returnFloatCritical() {
+    return (jfloat) -98765.4321F;
+}
+
 // public static native double returnDouble();
 static jdouble StaticNonce_returnDouble(JNIEnv *env, jclass clazz) {
     return 12345678.9;
 }
 
+// @FastNative
+// public static native double returnDoubleFast();
+static jdouble StaticNonce_returnDoubleFast(JNIEnv *env, jclass clazz) {
+    return 12345678.9;
+}
+
+// @CriticalNative
+// public static native double returnDoubleCritical();
+static jdouble StaticNonce_returnDoubleCritical() {
+    return 12345678.9;
+}
+
 // public static native Object returnNull();
 static jobject StaticNonce_returnNull(JNIEnv *env, jclass clazz) {
     return NULL;
 }
 
+// @FastNative
+// public static native Object returnNullFast();
+static jobject StaticNonce_returnNullFast(JNIEnv *env, jclass clazz) {
+    return NULL;
+}
+
 // public static native String returnString();
 static jstring StaticNonce_returnString(JNIEnv *env, jclass clazz) {
     return (*env)->NewStringUTF(env, "blort");
 }
 
+// @FastNative
+// public static native String returnStringFast();
+static jstring StaticNonce_returnStringFast(JNIEnv *env, jclass clazz) {
+    return (*env)->NewStringUTF(env, "blort");
+}
+
 // public static native short[] returnShortArray();
 static jshortArray StaticNonce_returnShortArray(JNIEnv *env, jclass clazz) {
     static jshort contents[] = { 10, 20, 30 };
@@ -95,6 +234,13 @@
     return result;
 }
 
+// @FastNative
+// public static native short[] returnShortArrayFast();
+static jshortArray StaticNonce_returnShortArrayFast(JNIEnv *env,
+        jclass clazz) {
+    return StaticNonce_returnShortArray(env, clazz);
+}
+
 // public static native String[] returnStringArray();
 static jobjectArray StaticNonce_returnStringArray(JNIEnv *env, jclass clazz) {
     static int indices[] = { 0, 50, 99 };
@@ -136,11 +282,24 @@
     return result;
 }
 
+// @FastNative
+// public static native String[] returnStringArrayFast();
+static jobjectArray StaticNonce_returnStringArrayFast(JNIEnv *env,
+        jclass clazz) {
+    return StaticNonce_returnStringArray(env, clazz);
+}
+
 // public static native Class returnThisClass();
 static jclass StaticNonce_returnThisClass(JNIEnv *env, jclass clazz) {
     return clazz;
 }
 
+// @FastNative
+// public static native Class returnThisClassFast();
+static jclass StaticNonce_returnThisClassFast(JNIEnv *env, jclass clazz) {
+    return clazz;
+}
+
 // public static native StaticNonce returnInstance();
 static jobject StaticNonce_returnInstance(JNIEnv *env, jclass clazz) {
     jmethodID id = (*env)->GetMethodID(env, clazz, "<init>", "()V");
@@ -158,52 +317,165 @@
     return (*env)->NewObjectA(env, clazz, id, NULL);
 }
 
+// @FastNative
+// public static native StaticNonce returnInstanceFast();
+static jobject StaticNonce_returnInstanceFast(JNIEnv *env, jclass clazz) {
+    return StaticNonce_returnInstance(env, clazz);
+}
+
 // public static native boolean takeBoolean(boolean v);
 static jboolean StaticNonce_takeBoolean(JNIEnv *env, jclass clazz,
         jboolean v) {
     return v == true;
 }
 
+// @FastNative
+// public static native boolean takeBooleanFast(boolean v);
+static jboolean StaticNonce_takeBooleanFast(JNIEnv *env, jclass clazz,
+        jboolean v) {
+    return v == true;
+}
+
+// @CriticalNative
+// public static native boolean takeBooleanCritical(boolean v);
+static jboolean StaticNonce_takeBooleanCritical(jboolean v) {
+    return v == true;
+}
+
 // public static native boolean takeByte(byte v);
 static jboolean StaticNonce_takeByte(JNIEnv *env, jclass clazz, jbyte v) {
     return v == -99;
 }
 
+// @FastNative
+// public static native boolean takeByteFast(byte v);
+static jboolean StaticNonce_takeByteFast(JNIEnv *env, jclass clazz, jbyte v) {
+    return v == -99;
+}
+
+// @CriticalNative
+// public static native boolean takeByteCritical(byte v);
+static jboolean StaticNonce_takeByteCritical(jbyte v) {
+    return v == -99;
+}
+
 // public static native boolean takeShort(short v);
 static jboolean StaticNonce_takeShort(JNIEnv *env, jclass clazz, jshort v) {
     return v == 19991;
 }
 
+// @FastNative
+// public static native boolean takeShortFast(short v);
+static jboolean StaticNonce_takeShortFast(JNIEnv *env, jclass clazz,
+        jshort v) {
+    return v == 19991;
+}
+
+// @CriticalNative
+// public static native boolean takeShortCritical(short v);
+static jboolean StaticNonce_takeShortCritical(jshort v) {
+    return v == 19991;
+}
+
 // public static native boolean takeChar(char v);
 static jboolean StaticNonce_takeChar(JNIEnv *env, jclass clazz, jchar v) {
     return v == 999;
 }
 
+// @FastNative
+// public static native boolean takeCharFast(char v);
+static jboolean StaticNonce_takeCharFast(JNIEnv *env, jclass clazz, jchar v) {
+    return v == 999;
+}
+
+// @CriticalNative
+// public static native boolean takeCharCritical(char v);
+static jboolean StaticNonce_takeCharCritical(jchar v) {
+    return v == 999;
+}
+
 // public static native boolean takeInt(int v);
 static jboolean StaticNonce_takeInt(JNIEnv *env, jclass clazz, jint v) {
     return v == -999888777;
 }
 
+// @FastNative
+// public static native boolean takeIntFast(int v);
+static jboolean StaticNonce_takeIntFast(JNIEnv *env, jclass clazz, jint v) {
+    return v == -999888777;
+}
+
+// @CriticalNative
+// public static native boolean takeIntCritical(int v);
+static jboolean StaticNonce_takeIntCritical(jint v) {
+    return v == -999888777;
+}
+
 // public static native boolean takeLong(long v);
 static jboolean StaticNonce_takeLong(JNIEnv *env, jclass clazz, jlong v) {
     return v == 999888777666555444LL;
 }
 
+// @FastNative
+// public static native boolean takeLongFast(long v);
+static jboolean StaticNonce_takeLongFast(JNIEnv *env, jclass clazz, jlong v) {
+    return v == 999888777666555444LL;
+}
+
+// @CriticalNative
+// public static native boolean takeLongCritical(long v);
+static jboolean StaticNonce_takeLongCritical(jlong v) {
+    return v == 999888777666555444LL;
+}
+
 // public static native boolean takeFloat(float v);
 static jboolean StaticNonce_takeFloat(JNIEnv *env, jclass clazz, jfloat v) {
     return v == -9988.7766F;
 }
 
+// @FastNative
+// public static native boolean takeFloatFast(float v);
+static jboolean StaticNonce_takeFloatFast(JNIEnv *env, jclass clazz,
+        jfloat v) {
+    return v == -9988.7766F;
+}
+
+// @CriticalNative
+// public static native boolean takeFloatCritical(float v);
+static jboolean StaticNonce_takeFloatCritical(jfloat v) {
+    return v == -9988.7766F;
+}
+
 // public static native boolean takeDouble(double v);
 static jboolean StaticNonce_takeDouble(JNIEnv *env, jclass clazz, jdouble v) {
     return v == 999888777.666555;
 }
 
+// @FastNative
+// public static native boolean takeDoubleFast(double v);
+static jboolean StaticNonce_takeDoubleFast(JNIEnv *env, jclass clazz,
+        jdouble v) {
+    return v == 999888777.666555;
+}
+
+// @CriticalNative
+// public static native boolean takeDoubleCritical(double v);
+static jboolean StaticNonce_takeDoubleCritical(jdouble v) {
+    return v == 999888777.666555;
+}
+
 // public static native boolean takeNull(Object v);
 static jboolean StaticNonce_takeNull(JNIEnv *env, jclass clazz, jobject v) {
     return v == NULL;
 }
 
+// @FastNative
+// public static native boolean takeNullFast(Object v);
+static jboolean StaticNonce_takeNullFast(JNIEnv *env, jclass clazz,
+        jobject v) {
+    return v == NULL;
+}
+
 // public static native boolean takeString(String v);
 static jboolean StaticNonce_takeString(JNIEnv *env, jclass clazz, jstring v) {
     if (v == NULL) {
@@ -217,24 +489,64 @@
     return result;
 }
 
+// @FastNative
+// public static native boolean takeStringFast(String v);
+static jboolean StaticNonce_takeStringFast(JNIEnv *env, jclass clazz,
+        jstring v) {
+    return StaticNonce_takeString(env, clazz, v);
+}
+
 // public static native boolean takeThisClass(Class v);
 static jboolean StaticNonce_takeThisClass(JNIEnv *env, jclass clazz,
         jclass v) {
     return (*env)->IsSameObject(env, clazz, v);
 }
 
+// @FastNative
+// public static native boolean takeThisClassFast(Class v);
+static jboolean StaticNonce_takeThisClassFast(JNIEnv *env, jclass clazz,
+        jclass v) {
+    return (*env)->IsSameObject(env, clazz, v);
+}
+
 // public static native boolean takeIntLong(int v1, long v2);
 static jboolean StaticNonce_takeIntLong(JNIEnv *env, jclass clazz,
         jint v1, jlong v2) {
     return (v1 == 914) && (v2 == 9140914091409140914LL);
 }
 
+// @FastNative
+// public static native boolean takeIntLongFast(int v1, long v2);
+static jboolean StaticNonce_takeIntLongFast(JNIEnv *env, jclass clazz,
+        jint v1, jlong v2) {
+    return (v1 == 914) && (v2 == 9140914091409140914LL);
+}
+
+// @CriticalNative
+// public static native boolean takeIntLongCritical(int v1, long v2);
+static jboolean StaticNonce_takeIntLongCritical(jint v1, jlong v2) {
+    return (v1 == 914) && (v2 == 9140914091409140914LL);
+}
+
 // public static native boolean takeLongInt(long v1, int v2);
 static jboolean StaticNonce_takeLongInt(JNIEnv *env, jclass clazz,
         jlong v1, jint v2) {
     return (v1 == -4321LL) && (v2 == 12341234);
 }
 
+// @FastNative
+// public static native boolean takeLongIntFast(long v1, int v2);
+static jboolean StaticNonce_takeLongIntFast(JNIEnv *env, jclass clazz,
+        jlong v1, jint v2) {
+    return (v1 == -4321LL) && (v2 == 12341234);
+}
+
+// @CriticalNative
+// public static native boolean takeLongIntCritical(long v1, int v2);
+static jboolean StaticNonce_takeLongIntCritical(jlong v1, jint v2) {
+    return (v1 == -4321LL) && (v2 == 12341234);
+}
+
 // public static native boolean takeOneOfEach(boolean v0, byte v1, short v2,
 //         char v3, int v4, long v5, String v6, float v7, double v8,
 //         int[] v9);
@@ -280,6 +592,57 @@
     return result;
 }
 
+// public static native boolean takeOneOfEachDlsym(boolean v0, byte v1,
+//         short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+JNIEXPORT jboolean Java_android_jni_cts_StaticNonce_takeOneOfEachDlsym(
+        JNIEnv *env, jclass clazz, jboolean v0, jbyte v1, jshort v2, jchar v3,
+        jint v4, jlong v5, jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return StaticNonce_takeOneOfEach(
+            env, clazz, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
+// @FastNative
+// public static native boolean takeOneOfEachFast(boolean v0, byte v1,
+//         short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+static jboolean StaticNonce_takeOneOfEachFast(JNIEnv *env, jclass clazz,
+        jboolean v0, jbyte v1, jshort v2, jchar v3, jint v4, jlong v5,
+        jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return StaticNonce_takeOneOfEach(
+            env, clazz, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
+// @FastNative
+// public static native boolean takeOneOfEachFastDlsym(boolean v0, byte v1,
+//         short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+//         int[] v9);
+JNIEXPORT jboolean Java_android_jni_cts_StaticNonce_takeOneOfEachFastDlsym(
+        JNIEnv *env, jclass clazz, jboolean v0, jbyte v1, jshort v2, jchar v3,
+        jint v4, jlong v5, jstring v6, jfloat v7, jdouble v8, jintArray v9) {
+    return StaticNonce_takeOneOfEach(
+            env, clazz, v0, v1, v2, v3, v4, v5, v6, v7, v8, v9);
+}
+
+// @CriticalNative
+// public static native boolean takeOneOfEachCritical(boolean v0, byte v1,
+//         short v2, char v3, int v4, long v5, float v6, double v7);
+static jboolean StaticNonce_takeOneOfEachCritical(
+        jboolean v0, jbyte v1, jshort v2, jchar v3, jint v4, jlong v5,
+        jfloat v6, jdouble v7) {
+    return (v0 == false) && (v1 == 1) && (v2 == 2) && (v3 == 3) &&
+            (v4 == 4) && (v5 == 5) && (v6 == 6.0f) && (v7 == 7.0);
+}
+
+// @CriticalNative
+// public static native boolean takeOneOfEachCriticalDlsym(boolean v0, byte v1,
+//         short v2, char v3, int v4, long v5, float v6, double v7);
+JNIEXPORT jboolean Java_android_jni_cts_StaticNonce_takeOneOfEachCriticalDlsym(
+        jboolean v0, jbyte v1, jshort v2, jchar v3, jint v4, jlong v5,
+        jfloat v6, jdouble v7) {
+    return StaticNonce_takeOneOfEachCritical(v0, v1, v2, v3, v4, v5, v6, v7);
+}
+
 // public static native boolean takeCoolHandLuke(
 //         int v1, int v2, int v3, int v4,
 //         int v5, int v6, int v7, int v8, int v9,
@@ -322,44 +685,174 @@
         (v50 == 50);
 }
 
+// @FastNative
+// public static native boolean takeCoolHandLukeFast(
+//         int v1, int v2, int v3, int v4,
+//         int v5, int v6, int v7, int v8, int v9,
+//         int v10, int v11, int v12, int v13, int v14,
+//         int v15, int v16, int v17, int v18, int v19,
+//         int v20, int v21, int v22, int v23, int v24,
+//         int v25, int v26, int v27, int v28, int v29,
+//         int v30, int v31, int v32, int v33, int v34,
+//         int v35, int v36, int v37, int v38, int v39,
+//         int v40, int v41, int v42, int v43, int v44,
+//         int v45, int v46, int v47, int v48, int v49,
+//         int v50);
+static jboolean StaticNonce_takeCoolHandLukeFast(JNIEnv *env, jclass clazz,
+        jint v1, jint v2, jint v3, jint v4,
+        jint v5, jint v6, jint v7, jint v8, jint v9,
+        jint v10, jint v11, jint v12, jint v13, jint v14,
+        jint v15, jint v16, jint v17, jint v18, jint v19,
+        jint v20, jint v21, jint v22, jint v23, jint v24,
+        jint v25, jint v26, jint v27, jint v28, jint v29,
+        jint v30, jint v31, jint v32, jint v33, jint v34,
+        jint v35, jint v36, jint v37, jint v38, jint v39,
+        jint v40, jint v41, jint v42, jint v43, jint v44,
+        jint v45, jint v46, jint v47, jint v48, jint v49,
+        jint v50) {
+    return StaticNonce_takeCoolHandLuke(
+            env, clazz, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+            v11, v12, v13, v14, v15, v16, v17, v18, v19, v20,
+            v21, v22, v23, v24, v25, v26, v27, v28, v29, v30,
+            v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+            v41, v42, v43, v44, v45, v46, v47, v48, v49, v50);
+}
+
+// @CriticalNative
+// public static native boolean takeCoolHandLukeCritical(
+//         int v1, int v2, int v3, int v4,
+//         int v5, int v6, int v7, int v8, int v9,
+//         int v10, int v11, int v12, int v13, int v14,
+//         int v15, int v16, int v17, int v18, int v19,
+//         int v20, int v21, int v22, int v23, int v24,
+//         int v25, int v26, int v27, int v28, int v29,
+//         int v30, int v31, int v32, int v33, int v34,
+//         int v35, int v36, int v37, int v38, int v39,
+//         int v40, int v41, int v42, int v43, int v44,
+//         int v45, int v46, int v47, int v48, int v49,
+//         int v50);
+static jboolean StaticNonce_takeCoolHandLukeCritical(
+        jint v1, jint v2, jint v3, jint v4,
+        jint v5, jint v6, jint v7, jint v8, jint v9,
+        jint v10, jint v11, jint v12, jint v13, jint v14,
+        jint v15, jint v16, jint v17, jint v18, jint v19,
+        jint v20, jint v21, jint v22, jint v23, jint v24,
+        jint v25, jint v26, jint v27, jint v28, jint v29,
+        jint v30, jint v31, jint v32, jint v33, jint v34,
+        jint v35, jint v36, jint v37, jint v38, jint v39,
+        jint v40, jint v41, jint v42, jint v43, jint v44,
+        jint v45, jint v46, jint v47, jint v48, jint v49,
+        jint v50) {
+    return StaticNonce_takeCoolHandLuke(
+            NULL, NULL, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10,
+            v11, v12, v13, v14, v15, v16, v17, v18, v19, v20,
+            v21, v22, v23, v24, v25, v26, v27, v28, v29, v30,
+            v31, v32, v33, v34, v35, v36, v37, v38, v39, v40,
+            v41, v42, v43, v44, v45, v46, v47, v48, v49, v50);
+}
+
 static JNINativeMethod methods[] = {
     // name, signature, function
     { "nop",               "()V", StaticNonce_nop },
+    { "nopFast",           "()V", StaticNonce_nopFast },
+    { "nopCritical",       "()V", StaticNonce_nopCritical },
     { "returnBoolean",     "()Z", StaticNonce_returnBoolean },
+    { "returnBooleanFast", "()Z", StaticNonce_returnBooleanFast },
+    { "returnBooleanCritical", "()Z", StaticNonce_returnBooleanCritical },
     { "returnByte",        "()B", StaticNonce_returnByte },
+    { "returnByteFast",    "()B", StaticNonce_returnByteFast },
+    { "returnByteCritical", "()B", StaticNonce_returnByteCritical },
     { "returnShort",       "()S", StaticNonce_returnShort },
+    { "returnShortFast",   "()S", StaticNonce_returnShortFast },
+    { "returnShortCritical", "()S", StaticNonce_returnShortCritical },
     { "returnChar",        "()C", StaticNonce_returnChar },
+    { "returnCharFast",    "()C", StaticNonce_returnCharFast },
+    { "returnCharCritical", "()C", StaticNonce_returnCharCritical },
     { "returnInt",         "()I", StaticNonce_returnInt },
+    { "returnIntFast",     "()I", StaticNonce_returnIntFast },
+    { "returnIntCritical", "()I", StaticNonce_returnIntCritical },
     { "returnLong",        "()J", StaticNonce_returnLong },
+    { "returnLongFast",    "()J", StaticNonce_returnLongFast },
+    { "returnLongCritical", "()J", StaticNonce_returnLongCritical },
     { "returnFloat",       "()F", StaticNonce_returnFloat },
+    { "returnFloatFast",   "()F", StaticNonce_returnFloatFast },
+    { "returnFloatCritical", "()F", StaticNonce_returnFloatCritical },
     { "returnDouble",      "()D", StaticNonce_returnDouble },
+    { "returnDoubleFast",  "()D", StaticNonce_returnDoubleFast },
+    { "returnDoubleCritical", "()D", StaticNonce_returnDoubleCritical },
     { "returnNull",        "()Ljava/lang/Object;", StaticNonce_returnNull },
+    { "returnNullFast",    "()Ljava/lang/Object;",
+      StaticNonce_returnNullFast },
     { "returnString",      "()Ljava/lang/String;", StaticNonce_returnString },
+    { "returnStringFast",  "()Ljava/lang/String;",
+      StaticNonce_returnStringFast },
     { "returnShortArray",  "()[S", StaticNonce_returnShortArray },
+    { "returnShortArrayFast", "()[S", StaticNonce_returnShortArrayFast },
     { "returnStringArray", "()[Ljava/lang/String;",
       StaticNonce_returnStringArray },
+    { "returnStringArrayFast", "()[Ljava/lang/String;",
+      StaticNonce_returnStringArrayFast },
     { "returnThisClass",   "()Ljava/lang/Class;",
       StaticNonce_returnThisClass },
+    { "returnThisClassFast", "()Ljava/lang/Class;",
+      StaticNonce_returnThisClassFast },
     { "returnInstance",    "()Landroid/jni/cts/StaticNonce;",
       StaticNonce_returnInstance },
+    { "returnInstanceFast", "()Landroid/jni/cts/StaticNonce;",
+      StaticNonce_returnInstanceFast },
     { "takeBoolean",       "(Z)Z", StaticNonce_takeBoolean },
+    { "takeBooleanFast",   "(Z)Z", StaticNonce_takeBooleanFast },
+    { "takeBooleanCritical", "(Z)Z", StaticNonce_takeBooleanCritical },
     { "takeByte",          "(B)Z", StaticNonce_takeByte },
+    { "takeByteFast",      "(B)Z", StaticNonce_takeByteFast },
+    { "takeByteCritical",  "(B)Z", StaticNonce_takeByteCritical },
     { "takeShort",         "(S)Z", StaticNonce_takeShort },
+    { "takeShortFast",     "(S)Z", StaticNonce_takeShortFast },
+    { "takeShortCritical", "(S)Z", StaticNonce_takeShortCritical },
     { "takeChar",          "(C)Z", StaticNonce_takeChar },
+    { "takeCharFast",      "(C)Z", StaticNonce_takeCharFast },
+    { "takeCharCritical",  "(C)Z", StaticNonce_takeCharCritical },
     { "takeInt",           "(I)Z", StaticNonce_takeInt },
+    { "takeIntFast",       "(I)Z", StaticNonce_takeIntFast },
+    { "takeIntCritical",   "(I)Z", StaticNonce_takeIntCritical },
     { "takeLong",          "(J)Z", StaticNonce_takeLong },
+    { "takeLongFast",      "(J)Z", StaticNonce_takeLongFast },
+    { "takeLongCritical",  "(J)Z", StaticNonce_takeLongCritical },
     { "takeFloat",         "(F)Z", StaticNonce_takeFloat },
+    { "takeFloatFast",     "(F)Z", StaticNonce_takeFloatFast },
+    { "takeFloatCritical", "(F)Z", StaticNonce_takeFloatCritical },
     { "takeDouble",        "(D)Z", StaticNonce_takeDouble },
+    { "takeDoubleFast",    "(D)Z", StaticNonce_takeDoubleFast },
+    { "takeDoubleCritical", "(D)Z", StaticNonce_takeDoubleCritical },
     { "takeNull",          "(Ljava/lang/Object;)Z", StaticNonce_takeNull },
+    { "takeNullFast",      "(Ljava/lang/Object;)Z", StaticNonce_takeNullFast },
     { "takeString",        "(Ljava/lang/String;)Z", StaticNonce_takeString },
+    { "takeStringFast",    "(Ljava/lang/String;)Z",
+      StaticNonce_takeStringFast },
     { "takeThisClass",     "(Ljava/lang/Class;)Z", StaticNonce_takeThisClass },
+    { "takeThisClassFast", "(Ljava/lang/Class;)Z",
+      StaticNonce_takeThisClassFast },
     { "takeIntLong",       "(IJ)Z", StaticNonce_takeIntLong },
+    { "takeIntLongFast",   "(IJ)Z", StaticNonce_takeIntLongFast },
+    { "takeIntLongCritical", "(IJ)Z", StaticNonce_takeIntLongCritical },
     { "takeLongInt",       "(JI)Z", StaticNonce_takeLongInt },
+    { "takeLongIntFast",   "(JI)Z", StaticNonce_takeLongIntFast },
+    { "takeLongIntCritical", "(JI)Z", StaticNonce_takeLongIntCritical },
     { "takeOneOfEach",     "(ZBSCIJLjava/lang/String;FD[I)Z",
       StaticNonce_takeOneOfEach },
+    { "takeOneOfEachFast", "(ZBSCIJLjava/lang/String;FD[I)Z",
+      StaticNonce_takeOneOfEachFast },
+    { "takeOneOfEachCritical", "(ZBSCIJFD)Z",
+      StaticNonce_takeOneOfEachCritical },
     { "takeCoolHandLuke",
       "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z",
       StaticNonce_takeCoolHandLuke },
+    { "takeCoolHandLukeFast",
+      "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z",
+      StaticNonce_takeCoolHandLukeFast },
+    { "takeCoolHandLukeCritical",
+      "(IIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIIII)Z",
+      StaticNonce_takeCoolHandLukeCritical },
 };
 
 int register_StaticNonce(JNIEnv *env) {
diff --git a/tests/tests/jni/src/android/jni/cts/InstanceNonce.java b/tests/tests/jni/src/android/jni/cts/InstanceNonce.java
index e1a7dea..82ead49 100644
--- a/tests/tests/jni/src/android/jni/cts/InstanceNonce.java
+++ b/tests/tests/jni/src/android/jni/cts/InstanceNonce.java
@@ -16,6 +16,8 @@
 
 package android.jni.cts;
 
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Class with a bunch of native instance methods. These methods are called by
  * the various tests in {@link JniInstanceTest}.
@@ -36,38 +38,137 @@
 
     // See JniInstanceTest for the expected behavior of these methods.
 
+    public static native void missing();
+    @FastNative
+    public static native void missingFast();
+
+    public static native void nopDlsym();
+    @FastNative
+    public static native void nopFastDlsym();
+
     public native void nop();
+    @FastNative
+    public native void nopFast();
 
     public native boolean returnBoolean();
+    @FastNative
+    public native boolean returnBooleanFast();
+
     public native byte returnByte();
+    @FastNative
+    public native byte returnByteFast();
+
     public native short returnShort();
+    @FastNative
+    public native short returnShortFast();
+
     public native char returnChar();
+    @FastNative
+    public native char returnCharFast();
+
     public native int returnInt();
+    @FastNative
+    public native int returnIntFast();
+
     public native long returnLong();
+    @FastNative
+    public native long returnLongFast();
+
     public native float returnFloat();
+    @FastNative
+    public native float returnFloatFast();
+
     public native double returnDouble();
+    @FastNative
+    public native double returnDoubleFast();
+
     public native Object returnNull();
+    @FastNative
+    public native Object returnNullFast();
+
     public native String returnString();
+    @FastNative
+    public native String returnStringFast();
+
     public native short[] returnShortArray();
+    @FastNative
+    public native short[] returnShortArrayFast();
+
     public native String[] returnStringArray();
+    @FastNative
+    public native String[] returnStringArrayFast();
+
     public native InstanceNonce returnThis();
+    @FastNative
+    public native InstanceNonce returnThisFast();
 
     public native boolean takeBoolean(boolean v);
+    @FastNative
+    public native boolean takeBooleanFast(boolean v);
+
     public native boolean takeByte(byte v);
+    @FastNative
+    public native boolean takeByteFast(byte v);
+
     public native boolean takeShort(short v);
+    @FastNative
+    public native boolean takeShortFast(short v);
+
     public native boolean takeChar(char v);
+    @FastNative
+    public native boolean takeCharFast(char v);
+
     public native boolean takeInt(int v);
+    @FastNative
+    public native boolean takeIntFast(int v);
+
     public native boolean takeLong(long v);
+    @FastNative
+    public native boolean takeLongFast(long v);
+
     public native boolean takeFloat(float v);
+    @FastNative
+    public native boolean takeFloatFast(float v);
+
     public native boolean takeDouble(double v);
+    @FastNative
+    public native boolean takeDoubleFast(double v);
+
     public native boolean takeNull(Object v);
+    @FastNative
+    public native boolean takeNullFast(Object v);
+
     public native boolean takeString(String v);
+    @FastNative
+    public native boolean takeStringFast(String v);
+
     public native boolean takeThis(InstanceNonce v);
+    @FastNative
+    public native boolean takeThisFast(InstanceNonce v);
+
     public native boolean takeIntLong(int v1, long v2);
+    @FastNative
+    public native boolean takeIntLongFast(int v1, long v2);
+
     public native boolean takeLongInt(long v1, int v2);
+    @FastNative
+    public native boolean takeLongIntFast(long v1, int v2);
+
     public native boolean takeOneOfEach(boolean v0, byte v1, short v2,
             char v3, int v4, long v5, String v6, float v7, double v8,
             int[] v9);
+    public native boolean takeOneOfEachDlsym(boolean v0, byte v1, short v2,
+            char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+    @FastNative
+    public native boolean takeOneOfEachFast(boolean v0, byte v1, short v2,
+            char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+    @FastNative
+    public native boolean takeOneOfEachFastDlsym(boolean v0, byte v1, short v2,
+            char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+
     public native boolean takeCoolHandLuke(
             int v1, int v2, int v3, int v4,
             int v5, int v6, int v7, int v8, int v9,
@@ -80,4 +181,17 @@
             int v40, int v41, int v42, int v43, int v44,
             int v45, int v46, int v47, int v48, int v49,
             int v50);
+    @FastNative
+    public native boolean takeCoolHandLukeFast(
+            int v1, int v2, int v3, int v4,
+            int v5, int v6, int v7, int v8, int v9,
+            int v10, int v11, int v12, int v13, int v14,
+            int v15, int v16, int v17, int v18, int v19,
+            int v20, int v21, int v22, int v23, int v24,
+            int v25, int v26, int v27, int v28, int v29,
+            int v30, int v31, int v32, int v33, int v34,
+            int v35, int v36, int v37, int v38, int v39,
+            int v40, int v41, int v42, int v43, int v44,
+            int v45, int v46, int v47, int v48, int v49,
+            int v50);
 }
diff --git a/tests/tests/jni/src/android/jni/cts/JniInstanceTest.java b/tests/tests/jni/src/android/jni/cts/JniInstanceTest.java
index 7c16a3a..b242519 100644
--- a/tests/tests/jni/src/android/jni/cts/JniInstanceTest.java
+++ b/tests/tests/jni/src/android/jni/cts/JniInstanceTest.java
@@ -32,11 +32,41 @@
     }
 
     /**
+     * Test native method call without implementation.
+     */
+    public void test_missing() {
+        try {
+            target.missing();
+            throw new Error("Unreachable");
+        } catch (UnsatisfiedLinkError expected) {
+        }
+    }
+    public void test_missingFast() {
+        try {
+            target.missingFast();
+            throw new Error("Unreachable");
+        } catch (UnsatisfiedLinkError expected) {
+        }
+    }
+
+    /**
      * Test a simple no-op and void-returning method call.
+     *
+     * The "Dlsym" versions use dynamic lookup instead of explicitly
+     * registering the native method implementation.
      */
     public void test_nop() {
         target.nop();
     }
+    public void test_nopDlsym() {
+        target.nopDlsym();
+    }
+    public void test_nopFast() {
+        target.nopFast();
+    }
+    public void test_nopFastDlsym() {
+        target.nopFastDlsym();
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -44,6 +74,9 @@
     public void test_returnBoolean() {
         assertEquals(false, target.returnBoolean());
     }
+    public void test_returnBooleanFast() {
+        assertEquals(false, target.returnBooleanFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -51,6 +84,10 @@
     public void test_returnByte() {
         assertEquals(123, target.returnByte());
     }
+    public void test_returnByteFast() {
+        assertEquals(123, target.returnByteFast());
+    }
+
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -58,6 +95,9 @@
     public void test_returnShort() {
         assertEquals(-12345, target.returnShort());
     }
+    public void test_returnShortFast() {
+        assertEquals(-12345, target.returnShortFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -65,6 +105,9 @@
     public void test_returnChar() {
         assertEquals(34567, target.returnChar());
     }
+    public void test_returnCharFast() {
+        assertEquals(34567, target.returnCharFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -72,6 +115,9 @@
     public void test_returnInt() {
         assertEquals(12345678, target.returnInt());
     }
+    public void test_returnIntFast() {
+        assertEquals(12345678, target.returnIntFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -79,6 +125,9 @@
     public void test_returnLong() {
         assertEquals(-1098765432109876543L, target.returnLong());
     }
+    public void test_returnLongFast() {
+        assertEquals(-1098765432109876543L, target.returnLongFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -86,6 +135,9 @@
     public void test_returnFloat() {
         assertEquals(-98765.4321F, target.returnFloat());
     }
+    public void test_returnFloatFast() {
+        assertEquals(-98765.4321F, target.returnFloatFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -93,6 +145,9 @@
     public void test_returnDouble() {
         assertEquals(12345678.9, target.returnDouble());
     }
+    public void test_returnDoubleFast() {
+        assertEquals(12345678.9, target.returnDoubleFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -100,6 +155,9 @@
     public void test_returnNull() {
         assertNull(target.returnNull());
     }
+    public void test_returnNullFast() {
+        assertNull(target.returnNullFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -107,12 +165,20 @@
     public void test_returnString() {
         assertEquals("blort", target.returnString());
     }
+    public void test_returnStringFast() {
+        assertEquals("blort", target.returnStringFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
      */
     public void test_returnShortArray() {
-        short[] array = target.returnShortArray();
+        checkShortArray(target.returnShortArray());
+    }
+    public void test_returnShortArrayFast() {
+        checkShortArray(target.returnShortArrayFast());
+    }
+    private void checkShortArray(short[] array) {
         assertSame(short[].class, array.getClass());
         assertEquals(3, array.length);
         assertEquals(10, array[0]);
@@ -124,7 +190,12 @@
      * Test a simple value-returning (but otherwise no-op) method call.
      */
     public void test_returnStringArray() {
-        String[] array = target.returnStringArray();
+        checkStringArray(target.returnStringArray());
+    }
+    public void test_returnStringArrayFast() {
+        checkStringArray(target.returnStringArrayFast());
+    }
+    private void checkStringArray(String[] array) {
         assertSame(String[].class, array.getClass());
         assertEquals(100, array.length);
         assertEquals("blort", array[0]);
@@ -140,6 +211,9 @@
     public void test_returnThis() {
         assertSame(target, target.returnThis());
     }
+    public void test_returnThisFast() {
+        assertSame(target, target.returnThis());
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -148,6 +222,9 @@
     public void test_takeBoolean() {
         assertTrue(target.takeBoolean(false));
     }
+    public void test_takeBooleanFast() {
+        assertTrue(target.takeBooleanFast(false));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -156,6 +233,9 @@
     public void test_takeByte() {
         assertTrue(target.takeByte((byte) -99));
     }
+    public void test_takeByteFast() {
+        assertTrue(target.takeByteFast((byte) -99));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -164,6 +244,9 @@
     public void test_takeShort() {
         assertTrue(target.takeShort((short) 19991));
     }
+    public void test_takeShortFast() {
+        assertTrue(target.takeShortFast((short) 19991));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -172,6 +255,9 @@
     public void test_takeChar() {
         assertTrue(target.takeChar((char) 999));
     }
+    public void test_takeCharFast() {
+        assertTrue(target.takeCharFast((char) 999));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -180,6 +266,9 @@
     public void test_takeInt() {
         assertTrue(target.takeInt(-999888777));
     }
+    public void test_takeIntFast() {
+        assertTrue(target.takeIntFast(-999888777));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -188,6 +277,9 @@
     public void test_takeLong() {
         assertTrue(target.takeLong(999888777666555444L));
     }
+    public void test_takeLongFast() {
+        assertTrue(target.takeLongFast(999888777666555444L));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -196,6 +288,9 @@
     public void test_takeFloat() {
         assertTrue(target.takeFloat(-9988.7766F));
     }
+    public void test_takeFloatFast() {
+        assertTrue(target.takeFloatFast(-9988.7766F));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -204,6 +299,9 @@
     public void test_takeDouble() {
         assertTrue(target.takeDouble(999888777.666555));
     }
+    public void test_takeDoubleFast() {
+        assertTrue(target.takeDoubleFast(999888777.666555));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -212,6 +310,9 @@
     public void test_takeNull() {
         assertTrue(target.takeNull(null));
     }
+    public void test_takeNullFast() {
+        assertTrue(target.takeNullFast(null));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -220,6 +321,9 @@
     public void test_takeString() {
         assertTrue(target.takeString("fuzzbot"));
     }
+    public void test_takeStringFast() {
+        assertTrue(target.takeStringFast("fuzzbot"));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -229,6 +333,9 @@
     public void test_takeThis() {
         assertTrue(target.takeThis(target));
     }
+    public void test_takeThisFast() {
+        assertTrue(target.takeThisFast(target));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -237,6 +344,9 @@
     public void test_takeIntLong() {
         assertTrue(target.takeIntLong(914, 9140914091409140914L));
     }
+    public void test_takeIntLongFast() {
+        assertTrue(target.takeIntLongFast(914, 9140914091409140914L));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -245,16 +355,37 @@
     public void test_takeLongInt() {
         assertTrue(target.takeLongInt(-4321L, 12341234));
     }
+    public void test_takeLongIntFast() {
+        assertTrue(target.takeLongIntFast(-4321L, 12341234));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
      * got the expected values.
+     *
+     * The "Dlsym" versions use dynamic lookup instead of explicitly
+     * registering the native method implementation.
      */
     public void test_takeOneOfEach() {
         assertTrue(target.takeOneOfEach((boolean) false, (byte) 1,
                         (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
                         new int[] { 9, 10 }));
     }
+    public void test_takeOneOfEachDlsym() {
+        assertTrue(target.takeOneOfEachDlsym((boolean) false, (byte) 1,
+                        (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
+                        new int[] { 9, 10 }));
+    }
+    public void test_takeOneOfEachFast() {
+        assertTrue(target.takeOneOfEachFast((boolean) false, (byte) 1,
+                        (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
+                        new int[] { 9, 10 }));
+    }
+    public void test_takeOneOfEachFastDlsym() {
+        assertTrue(target.takeOneOfEachFastDlsym((boolean) false, (byte) 1,
+                        (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
+                        new int[] { 9, 10 }));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -268,4 +399,12 @@
                         40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
                         50));
     }
+    public void test_takeCoolHandLukeFast() {
+        assertTrue(target.takeCoolHandLukeFast(1, 2, 3, 4, 5, 6, 7, 8, 9,
+                        10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+                        20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+                        30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+                        40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+                        50));
+    }
 }
diff --git a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
index e2bbcd7..d1bfac6 100644
--- a/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
+++ b/tests/tests/jni/src/android/jni/cts/JniStaticTest.java
@@ -18,7 +18,9 @@
 
 import android.os.Build;
 import android.os.Process;
+
 import com.android.compatibility.common.util.PropertyUtil;
+
 import java.io.File;
 import java.io.IOException;
 
@@ -69,11 +71,54 @@
     }
 
     /**
+     * Test native method call without implementation.
+     */
+    public void test_missing() {
+        try {
+            StaticNonce.missing();
+            throw new Error("Unreachable");
+        } catch (UnsatisfiedLinkError expected) {
+        }
+    }
+    public void test_missingFast() {
+        try {
+            StaticNonce.missingFast();
+            throw new Error("Unreachable");
+        } catch (UnsatisfiedLinkError expected) {
+        }
+    }
+    public void test_missingCritical() {
+        try {
+            StaticNonce.missingCritical();
+            throw new Error("Unreachable");
+        } catch (UnsatisfiedLinkError expected) {
+        }
+    }
+
+    /**
      * Test a simple no-op and void-returning method call.
+     *
+     * The "Dlsym" versions use dynamic lookup instead of explicitly
+     * registering the native method implementation.
      */
     public void test_nop() {
         StaticNonce.nop();
     }
+    public void test_nopDlsym() {
+        StaticNonce.nopDlsym();
+    }
+    public void test_nopFast() {
+        StaticNonce.nopFast();
+    }
+    public void test_nopFastDlsym() {
+        StaticNonce.nopFastDlsym();
+    }
+    public void test_nopCritical() {
+        StaticNonce.nopCritical();
+    }
+    public void test_nopCriticalDlsym() {
+        StaticNonce.nopCriticalDlsym();
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -81,6 +126,12 @@
     public void test_returnBoolean() {
         assertEquals(true, StaticNonce.returnBoolean());
     }
+    public void test_returnBooleanFast() {
+        assertEquals(true, StaticNonce.returnBooleanFast());
+    }
+    public void test_returnBooleanCritical() {
+        assertEquals(true, StaticNonce.returnBooleanCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -88,6 +139,12 @@
     public void test_returnByte() {
         assertEquals(123, StaticNonce.returnByte());
     }
+    public void test_returnByteFast() {
+        assertEquals(123, StaticNonce.returnByteFast());
+    }
+    public void test_returnByteCritical() {
+        assertEquals(123, StaticNonce.returnByteCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -95,6 +152,12 @@
     public void test_returnShort() {
         assertEquals(-12345, StaticNonce.returnShort());
     }
+    public void test_returnShortFast() {
+        assertEquals(-12345, StaticNonce.returnShortFast());
+    }
+    public void test_returnShortCritical() {
+        assertEquals(-12345, StaticNonce.returnShortCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -102,6 +165,12 @@
     public void test_returnChar() {
         assertEquals(34567, StaticNonce.returnChar());
     }
+    public void test_returnCharFast() {
+        assertEquals(34567, StaticNonce.returnCharFast());
+    }
+    public void test_returnCharCritical() {
+        assertEquals(34567, StaticNonce.returnCharCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -109,6 +178,12 @@
     public void test_returnInt() {
         assertEquals(12345678, StaticNonce.returnInt());
     }
+    public void test_returnIntFast() {
+        assertEquals(12345678, StaticNonce.returnIntFast());
+    }
+    public void test_returnIntCritical() {
+        assertEquals(12345678, StaticNonce.returnIntCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -116,6 +191,12 @@
     public void test_returnLong() {
         assertEquals(-1098765432109876543L, StaticNonce.returnLong());
     }
+    public void test_returnLongFast() {
+        assertEquals(-1098765432109876543L, StaticNonce.returnLongFast());
+    }
+    public void test_returnLongCritical() {
+        assertEquals(-1098765432109876543L, StaticNonce.returnLongCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -123,6 +204,12 @@
     public void test_returnFloat() {
         assertEquals(-98765.4321F, StaticNonce.returnFloat());
     }
+    public void test_returnFloatFast() {
+        assertEquals(-98765.4321F, StaticNonce.returnFloatFast());
+    }
+    public void test_returnFloatCritical() {
+        assertEquals(-98765.4321F, StaticNonce.returnFloatCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -130,6 +217,12 @@
     public void test_returnDouble() {
         assertEquals(12345678.9, StaticNonce.returnDouble());
     }
+    public void test_returnDoubleFast() {
+        assertEquals(12345678.9, StaticNonce.returnDoubleFast());
+    }
+    public void test_returnDoubleCritical() {
+        assertEquals(12345678.9, StaticNonce.returnDoubleCritical());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -137,6 +230,9 @@
     public void test_returnNull() {
         assertNull(StaticNonce.returnNull());
     }
+    public void test_returnNullFast() {
+        assertNull(StaticNonce.returnNullFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
@@ -144,12 +240,20 @@
     public void test_returnString() {
         assertEquals("blort", StaticNonce.returnString());
     }
+    public void test_returnStringFast() {
+        assertEquals("blort", StaticNonce.returnStringFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call.
      */
     public void test_returnShortArray() {
-        short[] array = StaticNonce.returnShortArray();
+        checkShortArray(StaticNonce.returnShortArray());
+    }
+    public void test_returnShortArrayFast() {
+        checkShortArray(StaticNonce.returnShortArrayFast());
+    }
+    private void checkShortArray(short[] array) {
         assertSame(short[].class, array.getClass());
         assertEquals(3, array.length);
         assertEquals(10, array[0]);
@@ -161,7 +265,12 @@
      * Test a simple value-returning (but otherwise no-op) method call.
      */
     public void test_returnStringArray() {
-        String[] array = StaticNonce.returnStringArray();
+        checkStringArray(StaticNonce.returnStringArray());
+    }
+    public void test_returnStringArrayFast() {
+        checkStringArray(StaticNonce.returnStringArrayFast());
+    }
+    private void checkStringArray(String[] array) {
         assertSame(String[].class, array.getClass());
         assertEquals(100, array.length);
         assertEquals("blort", array[0]);
@@ -177,6 +286,9 @@
     public void test_returnThisClass() {
         assertSame(StaticNonce.class, StaticNonce.returnThisClass());
     }
+    public void test_returnThisClassFast() {
+        assertSame(StaticNonce.class, StaticNonce.returnThisClassFast());
+    }
 
     /**
      * Test a simple value-returning (but otherwise no-op) method call,
@@ -186,6 +298,10 @@
         StaticNonce nonce = StaticNonce.returnInstance();
         assertSame(StaticNonce.class, nonce.getClass());
     }
+    public void test_returnInstanceFast() {
+        StaticNonce nonce = StaticNonce.returnInstanceFast();
+        assertSame(StaticNonce.class, nonce.getClass());
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -194,6 +310,12 @@
     public void test_takeBoolean() {
         assertTrue(StaticNonce.takeBoolean(true));
     }
+    public void test_takeBooleanFast() {
+        assertTrue(StaticNonce.takeBooleanFast(true));
+    }
+    public void test_takeBooleanCritical() {
+        assertTrue(StaticNonce.takeBooleanCritical(true));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -202,6 +324,12 @@
     public void test_takeByte() {
         assertTrue(StaticNonce.takeByte((byte) -99));
     }
+    public void test_takeByteFast() {
+        assertTrue(StaticNonce.takeByteFast((byte) -99));
+    }
+    public void test_takeByteCritical() {
+        assertTrue(StaticNonce.takeByteCritical((byte) -99));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -210,6 +338,12 @@
     public void test_takeShort() {
         assertTrue(StaticNonce.takeShort((short) 19991));
     }
+    public void test_takeShortFast() {
+        assertTrue(StaticNonce.takeShortFast((short) 19991));
+    }
+    public void test_takeShortCritical() {
+        assertTrue(StaticNonce.takeShortCritical((short) 19991));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -218,6 +352,12 @@
     public void test_takeChar() {
         assertTrue(StaticNonce.takeChar((char) 999));
     }
+    public void test_takeCharFast() {
+        assertTrue(StaticNonce.takeCharFast((char) 999));
+    }
+    public void test_takeCharCritical() {
+        assertTrue(StaticNonce.takeCharCritical((char) 999));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -226,6 +366,12 @@
     public void test_takeInt() {
         assertTrue(StaticNonce.takeInt(-999888777));
     }
+    public void test_takeIntFast() {
+        assertTrue(StaticNonce.takeIntFast(-999888777));
+    }
+    public void test_takeIntCritical() {
+        assertTrue(StaticNonce.takeIntCritical(-999888777));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -234,6 +380,12 @@
     public void test_takeLong() {
         assertTrue(StaticNonce.takeLong(999888777666555444L));
     }
+    public void test_takeLongFast() {
+        assertTrue(StaticNonce.takeLongFast(999888777666555444L));
+    }
+    public void test_takeLongCritical() {
+        assertTrue(StaticNonce.takeLongCritical(999888777666555444L));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -242,6 +394,12 @@
     public void test_takeFloat() {
         assertTrue(StaticNonce.takeFloat(-9988.7766F));
     }
+    public void test_takeFloatFast() {
+        assertTrue(StaticNonce.takeFloatFast(-9988.7766F));
+    }
+    public void test_takeFloatCritical() {
+        assertTrue(StaticNonce.takeFloatCritical(-9988.7766F));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -250,6 +408,12 @@
     public void test_takeDouble() {
         assertTrue(StaticNonce.takeDouble(999888777.666555));
     }
+    public void test_takeDoubleFast() {
+        assertTrue(StaticNonce.takeDoubleFast(999888777.666555));
+    }
+    public void test_takeDoubleCritical() {
+        assertTrue(StaticNonce.takeDoubleCritical(999888777.666555));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -258,6 +422,9 @@
     public void test_takeNull() {
         assertTrue(StaticNonce.takeNull(null));
     }
+    public void test_takeNullFast() {
+        assertTrue(StaticNonce.takeNullFast(null));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -266,6 +433,9 @@
     public void test_takeString() {
         assertTrue(StaticNonce.takeString("fuzzbot"));
     }
+    public void test_takeStringFast() {
+        assertTrue(StaticNonce.takeStringFast("fuzzbot"));
+    }
 
     /**
      * Test a simple value-taking method call, that returns whether it
@@ -275,6 +445,9 @@
     public void test_takeThisClass() {
         assertTrue(StaticNonce.takeThisClass(StaticNonce.class));
     }
+    public void test_takeThisClassFast() {
+        assertTrue(StaticNonce.takeThisClassFast(StaticNonce.class));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -283,6 +456,12 @@
     public void test_takeIntLong() {
         assertTrue(StaticNonce.takeIntLong(914, 9140914091409140914L));
     }
+    public void test_takeIntLongFast() {
+        assertTrue(StaticNonce.takeIntLongFast(914, 9140914091409140914L));
+    }
+    public void test_takeIntLongCritical() {
+        assertTrue(StaticNonce.takeIntLongCritical(914, 9140914091409140914L));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -291,16 +470,49 @@
     public void test_takeLongInt() {
         assertTrue(StaticNonce.takeLongInt(-4321L, 12341234));
     }
+    public void test_takeLongIntFast() {
+        assertTrue(StaticNonce.takeLongIntFast(-4321L, 12341234));
+    }
+    public void test_takeLongIntCritical() {
+        assertTrue(StaticNonce.takeLongIntCritical(-4321L, 12341234));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
      * got the expected values.
+     *
+     * The "Dlsym" versions use dynamic lookup instead of explicitly
+     * registering the native method implementation.
      */
     public void test_takeOneOfEach() {
         assertTrue(StaticNonce.takeOneOfEach((boolean) false, (byte) 1,
                         (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
                         new int[] { 9, 10 }));
     }
+    public void test_takeOneOfEachDlsym() {
+        assertTrue(StaticNonce.takeOneOfEachDlsym((boolean) false,
+                        (byte) 1, (short) 2, (char) 3, (int) 4, 5L, "six",
+                        7.0f, 8.0, new int[] { 9, 10 }));
+    }
+    public void test_takeOneOfEachFast() {
+        assertTrue(StaticNonce.takeOneOfEachFast((boolean) false, (byte) 1,
+                        (short) 2, (char) 3, (int) 4, 5L, "six", 7.0f, 8.0,
+                        new int[] { 9, 10 }));
+    }
+    public void test_takeOneOfEachFastDlsym() {
+        assertTrue(StaticNonce.takeOneOfEachFastDlsym((boolean) false,
+                        (byte) 1, (short) 2, (char) 3, (int) 4, 5L, "six",
+                        7.0f, 8.0, new int[] { 9, 10 }));
+    }
+    public void test_takeOneOfEachCritical() {
+        assertTrue(StaticNonce.takeOneOfEachCritical((boolean) false, (byte) 1,
+                        (short) 2, (char) 3, (int) 4, 5L, 6.0f, 7.0));
+    }
+    public void test_takeOneOfEachCriticalDlsym() {
+        assertTrue(StaticNonce.takeOneOfEachCriticalDlsym((boolean) false,
+                        (byte) 1, (short) 2, (char) 3, (int) 4, 5L, 6.0f,
+                        7.0));
+    }
 
     /**
      * Test a simple multiple value-taking method call, that returns whether it
@@ -314,6 +526,22 @@
                         40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
                         50));
     }
+    public void test_takeCoolHandLukeFast() {
+        assertTrue(StaticNonce.takeCoolHandLukeFast(1, 2, 3, 4, 5, 6, 7, 8, 9,
+                        10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
+                        20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
+                        30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
+                        40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
+                        50));
+    }
+    public void test_takeCoolHandLukeCritical() {
+        assertTrue(StaticNonce.takeCoolHandLukeCritical(
+                        1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
+                        11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
+                        21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
+                        31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+                        41, 42, 43, 44, 45, 46, 47, 48, 49, 50));
+    }
 
     /**
      * dlopen(3) any of the public lib via file name (non-absolute path) should succeed.
diff --git a/tests/tests/jni/src/android/jni/cts/StaticNonce.java b/tests/tests/jni/src/android/jni/cts/StaticNonce.java
index c84e899..071d52c 100644
--- a/tests/tests/jni/src/android/jni/cts/StaticNonce.java
+++ b/tests/tests/jni/src/android/jni/cts/StaticNonce.java
@@ -16,6 +16,9 @@
 
 package android.jni.cts;
 
+import dalvik.annotation.optimization.CriticalNative;
+import dalvik.annotation.optimization.FastNative;
+
 /**
  * Class with a bunch of native static methods. These methods are called by
  * the various tests in {@link JniStaticTest}.
@@ -36,39 +39,188 @@
 
     // See JniStaticTest for the expected behavior of these methods.
 
+    public static native void missing();
+    @FastNative
+    public static native void missingFast();
+    @CriticalNative
+    public static native void missingCritical();
+
     public static native void nop();
+    public static native void nopDlsym();
+    @FastNative
+    public static native void nopFast();
+    @FastNative
+    public static native void nopFastDlsym();
+    @CriticalNative
+    public static native void nopCritical();
+    @CriticalNative
+    public static native void nopCriticalDlsym();
 
     public static native boolean returnBoolean();
+    @FastNative
+    public static native boolean returnBooleanFast();
+    @CriticalNative
+    public static native boolean returnBooleanCritical();
+
     public static native byte returnByte();
+    @FastNative
+    public static native byte returnByteFast();
+    @CriticalNative
+    public static native byte returnByteCritical();
+
     public static native short returnShort();
+    @FastNative
+    public static native short returnShortFast();
+    @CriticalNative
+    public static native short returnShortCritical();
+
     public static native char returnChar();
+    @FastNative
+    public static native char returnCharFast();
+    @CriticalNative
+    public static native char returnCharCritical();
+
     public static native int returnInt();
+    @FastNative
+    public static native int returnIntFast();
+    @CriticalNative
+    public static native int returnIntCritical();
+
     public static native long returnLong();
+    @FastNative
+    public static native long returnLongFast();
+    @CriticalNative
+    public static native long returnLongCritical();
+
     public static native float returnFloat();
+    @FastNative
+    public static native float returnFloatFast();
+    @CriticalNative
+    public static native float returnFloatCritical();
+
     public static native double returnDouble();
+    @FastNative
+    public static native double returnDoubleFast();
+    @CriticalNative
+    public static native double returnDoubleCritical();
+
     public static native Object returnNull();
+    @FastNative
+    public static native Object returnNullFast();
+
     public static native String returnString();
+    @FastNative
+    public static native String returnStringFast();
+
     public static native short[] returnShortArray();
+    @FastNative
+    public static native short[] returnShortArrayFast();
+
     public static native String[] returnStringArray();
+    @FastNative
+    public static native String[] returnStringArrayFast();
+
     public static native Class returnThisClass();
+    @FastNative
+    public static native Class returnThisClassFast();
+
     public static native StaticNonce returnInstance();
+    @FastNative
+    public static native StaticNonce returnInstanceFast();
 
     public static native boolean takeBoolean(boolean v);
+    @FastNative
+    public static native boolean takeBooleanFast(boolean v);
+    @CriticalNative
+    public static native boolean takeBooleanCritical(boolean v);
+
     public static native boolean takeByte(byte v);
+    @FastNative
+    public static native boolean takeByteFast(byte v);
+    @CriticalNative
+    public static native boolean takeByteCritical(byte v);
+
     public static native boolean takeShort(short v);
+    @FastNative
+    public static native boolean takeShortFast(short v);
+    @CriticalNative
+    public static native boolean takeShortCritical(short v);
+
     public static native boolean takeChar(char v);
+    @FastNative
+    public static native boolean takeCharFast(char v);
+    @CriticalNative
+    public static native boolean takeCharCritical(char v);
+
     public static native boolean takeInt(int v);
+    @FastNative
+    public static native boolean takeIntFast(int v);
+    @CriticalNative
+    public static native boolean takeIntCritical(int v);
+
     public static native boolean takeLong(long v);
+    @FastNative
+    public static native boolean takeLongFast(long v);
+    @CriticalNative
+    public static native boolean takeLongCritical(long v);
+
     public static native boolean takeFloat(float v);
+    @FastNative
+    public static native boolean takeFloatFast(float v);
+    @CriticalNative
+    public static native boolean takeFloatCritical(float v);
+
     public static native boolean takeDouble(double v);
+    @FastNative
+    public static native boolean takeDoubleFast(double v);
+    @CriticalNative
+    public static native boolean takeDoubleCritical(double v);
+
     public static native boolean takeNull(Object v);
+    @FastNative
+    public static native boolean takeNullFast(Object v);
+
     public static native boolean takeString(String v);
+    @FastNative
+    public static native boolean takeStringFast(String v);
+
     public static native boolean takeThisClass(Class v);
+    @FastNative
+    public static native boolean takeThisClassFast(Class v);
+
     public static native boolean takeIntLong(int v1, long v2);
+    @FastNative
+    public static native boolean takeIntLongFast(int v1, long v2);
+    @CriticalNative
+    public static native boolean takeIntLongCritical(int v1, long v2);
+
     public static native boolean takeLongInt(long v1, int v2);
+    @FastNative
+    public static native boolean takeLongIntFast(long v1, int v2);
+    @CriticalNative
+    public static native boolean takeLongIntCritical(long v1, int v2);
+
     public static native boolean takeOneOfEach(boolean v0, byte v1, short v2,
             char v3, int v4, long v5, String v6, float v7, double v8,
             int[] v9);
+    public static native boolean takeOneOfEachDlsym(boolean v0, byte v1,
+            short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+    @FastNative
+    public static native boolean takeOneOfEachFast(boolean v0, byte v1,
+            short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+    @FastNative
+    public static native boolean takeOneOfEachFastDlsym(boolean v0, byte v1,
+            short v2, char v3, int v4, long v5, String v6, float v7, double v8,
+            int[] v9);
+    @CriticalNative
+    public static native boolean takeOneOfEachCritical(boolean v0, byte v1,
+            short v2, char v3, int v4, long v5, float v6, double v7);
+    @CriticalNative
+    public static native boolean takeOneOfEachCriticalDlsym(boolean v0,
+            byte v1, short v2, char v3, int v4, long v5, float v6, double v7);
+
     public static native boolean takeCoolHandLuke(
             int v1, int v2, int v3, int v4,
             int v5, int v6, int v7, int v8, int v9,
@@ -81,4 +233,30 @@
             int v40, int v41, int v42, int v43, int v44,
             int v45, int v46, int v47, int v48, int v49,
             int v50);
+    @FastNative
+    public static native boolean takeCoolHandLukeFast(
+            int v1, int v2, int v3, int v4,
+            int v5, int v6, int v7, int v8, int v9,
+            int v10, int v11, int v12, int v13, int v14,
+            int v15, int v16, int v17, int v18, int v19,
+            int v20, int v21, int v22, int v23, int v24,
+            int v25, int v26, int v27, int v28, int v29,
+            int v30, int v31, int v32, int v33, int v34,
+            int v35, int v36, int v37, int v38, int v39,
+            int v40, int v41, int v42, int v43, int v44,
+            int v45, int v46, int v47, int v48, int v49,
+            int v50);
+    @CriticalNative
+    public static native boolean takeCoolHandLukeCritical(
+            int v1, int v2, int v3, int v4,
+            int v5, int v6, int v7, int v8, int v9,
+            int v10, int v11, int v12, int v13, int v14,
+            int v15, int v16, int v17, int v18, int v19,
+            int v20, int v21, int v22, int v23, int v24,
+            int v25, int v26, int v27, int v28, int v29,
+            int v30, int v31, int v32, int v33, int v34,
+            int v35, int v36, int v37, int v38, int v39,
+            int v40, int v41, int v42, int v43, int v44,
+            int v45, int v46, int v47, int v48, int v49,
+            int v50);
 }
diff --git a/tests/tests/keystore/Android.bp b/tests/tests/keystore/Android.bp
index 8f7306c..27d3c16 100644
--- a/tests/tests/keystore/Android.bp
+++ b/tests/tests/keystore/Android.bp
@@ -64,6 +64,7 @@
         "DeviceAdminApp",
         "Harrier",
         "Nene",
+        "android-key-attestation",
         "androidx.test.rules",
         "compatibility-device-util-axt",
         "core-tests-support",
diff --git a/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java b/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
index 676793b..6d2e950 100644
--- a/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/DeviceOwnerKeyManagementTest.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyManager.ID_TYPE_MEID;
 import static android.app.admin.DevicePolicyManager.ID_TYPE_SERIAL;
 
+import static com.google.android.attestation.ParsedAttestationRecord.createParsedAttestationRecord;
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
@@ -47,10 +48,13 @@
 import com.android.bedstead.nene.permissions.PermissionContext;
 import com.android.compatibility.common.util.ApiTest;
 
+import com.google.android.attestation.ParsedAttestationRecord;
+
 import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.Test;
 
+import java.io.IOException;
 import java.security.GeneralSecurityException;
 import java.security.KeyPair;
 import java.security.PrivateKey;
@@ -138,6 +142,10 @@
         assertThat(teeAttestation.getImei()).isEqualTo(expectedImei);
         assertThat(teeAttestation.getMeid()).isEqualTo(expectedMeid);
 
+        validateSecondImei(teeAttestation.getSecondImei(), expectedSecondImei);
+    }
+
+    private void validateSecondImei(String attestedSecondImei, String expectedSecondImei) {
         /**
          * Test attestation support for 2nd IMEI:
          * * Attestation of 2nd IMEI (if present on the device) is required for devices shipping
@@ -155,25 +163,69 @@
         if (!isKeyMintV3) {
             // Earlier versions of KeyMint must not attest to second IMEI values as they are not
             // allowed to emit an attestation extension version that includes it.
-            assertThat(teeAttestation.getSecondImei()).isNull();
+            assertThat(attestedSecondImei).isNull();
         } else if (emptySecondImei) {
             // Device doesn't have a second IMEI, so none should be included in the attestation
             // extension.
-            assertThat(teeAttestation.getSecondImei()).isNull();
+            assertThat(attestedSecondImei).isNull();
         } else if (deviceShippedWithKeyMint3) {
             // The device has a second IMEI and should attest to it.
-            assertThat(teeAttestation.getSecondImei()).isEqualTo(expectedSecondImei);
+            assertThat(attestedSecondImei).isEqualTo(expectedSecondImei);
         } else {
             // Device has KeyMint 3, but originally shipped with an earlier KeyMint and
             // may not have provisioned the second IMEI as an attestation ID.
             // It does not have to support attesting to the second IMEI, but if there is something
             // in the attestation record, it must match the platform-provided second IMEI.
-            if (!TextUtils.isEmpty(teeAttestation.getSecondImei())) {
-                assertThat(teeAttestation.getSecondImei()).isEqualTo(expectedSecondImei);
+            if (!TextUtils.isEmpty(attestedSecondImei)) {
+                assertThat(attestedSecondImei).isEqualTo(expectedSecondImei);
             }
         }
     }
 
+    private void validateDeviceIdAttestationDataUsingExtLib(Certificate leaf,
+                                                            String expectedSerial,
+                                                            String expectedImei,
+                                                            String expectedMeid,
+                                                            String expectedSecondImei)
+            throws CertificateParsingException, IOException {
+        ParsedAttestationRecord parsedAttestationRecord =
+                createParsedAttestationRecord((X509Certificate) leaf);
+
+        com.google.android.attestation.AuthorizationList teeAttestation =
+                parsedAttestationRecord.teeEnforced;
+
+        assertThat(teeAttestation).isNotNull();
+        assertThat(new String(teeAttestation.attestationIdBrand.get())).isEqualTo(Build.BRAND);
+        assertThat(new String(teeAttestation.attestationIdDevice.get())).isEqualTo(Build.DEVICE);
+        assertThat(new String(teeAttestation.attestationIdProduct.get())).isEqualTo(Build.PRODUCT);
+        assertThat(new String(teeAttestation.attestationIdManufacturer.get()))
+                .isEqualTo(Build.MANUFACTURER);
+        assertThat(new String(teeAttestation.attestationIdModel.get())).isEqualTo(Build.MODEL);
+
+        assertThat(!TextUtils.isEmpty(expectedSerial))
+                .isEqualTo(teeAttestation.attestationIdSerial.isPresent());
+        if (!TextUtils.isEmpty(expectedSerial)) {
+            assertThat(new String(teeAttestation.attestationIdSerial.get()))
+                    .isEqualTo(expectedSerial);
+        }
+        assertThat(!TextUtils.isEmpty(expectedImei))
+                .isEqualTo(teeAttestation.attestationIdImei.isPresent());
+        if (!TextUtils.isEmpty(expectedImei)) {
+            assertThat(new String(teeAttestation.attestationIdImei.get()))
+                    .isEqualTo(expectedImei);
+        }
+        assertThat(!TextUtils.isEmpty(expectedMeid))
+                .isEqualTo(teeAttestation.attestationIdMeid.isPresent());
+        if (!TextUtils.isEmpty(expectedMeid)) {
+            assertThat(new String(teeAttestation.attestationIdMeid.get()))
+                    .isEqualTo(expectedMeid);
+        }
+        // TODO: Second IMEI parsing is not supported by external library yet,
+        //  hence skipping for now.
+        /* validateSecondImei(new String(teeAttestation.attestationIdSecondImei.get()),
+                expectedSecondImei); */
+    }
+
     private void validateAttestationRecord(List<Certificate> attestation, byte[] providedChallenge)
             throws CertificateParsingException {
         assertThat(attestation).isNotNull();
@@ -376,6 +428,10 @@
                         }
                         validateDeviceIdAttestationData(attestation, expectedSerial,
                                 expectedImei, expectedMeid, expectedSecondImei);
+                        // Validate attestation record using external library. As above validation
+                        // is successful external library validation should also pass.
+                        validateDeviceIdAttestationDataUsingExtLib(attestation, expectedSerial,
+                                expectedImei, expectedMeid, expectedSecondImei);
                     }
                 } catch (UnsupportedOperationException expected) {
                     // Make sure the test only fails if the device is not meant to support Device
diff --git a/tests/tests/libcorefileio/TEST_MAPPING b/tests/tests/libcorefileio/TEST_MAPPING
index 0ba15be..0a3423f 100644
--- a/tests/tests/libcorefileio/TEST_MAPPING
+++ b/tests/tests/libcorefileio/TEST_MAPPING
@@ -1,16 +1,7 @@
 {
-  "kernel-presubmit": [
+  "kernel-postsubmit": [
     {
-      "name": "CtsLibcoreFileIOTestCases",
-      "options": [
-        {
-          // TODO(b/236710517)
-          "exclude-filter": "android.cts.FileChannelInterProcessLockTest#test_lockJJZ_Exclusive_asyncChannel"
-        },
-        {
-          "exclude-filter": "android.cts.FileChannelInterProcessLockTest#test_tryLockJJZ_Exclusive_syncChannel"
-        }
-      ]
+      "name": "CtsLibcoreFileIOTestCases"
     }
   ]
 }
diff --git a/tests/tests/match_flags/src/android/matchflags/cts/MatchFlagTests.java b/tests/tests/match_flags/src/android/matchflags/cts/MatchFlagTests.java
index ddc8a63..aa9aa29 100644
--- a/tests/tests/match_flags/src/android/matchflags/cts/MatchFlagTests.java
+++ b/tests/tests/match_flags/src/android/matchflags/cts/MatchFlagTests.java
@@ -27,6 +27,7 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import com.android.compatibility.common.util.FeatureUtil;
 import com.android.compatibility.common.util.ShellUtils;
 
 import org.junit.After;
@@ -121,6 +122,7 @@
 
     @Test
     public void startNoBrowserRequireDefaultUnapproved() throws Exception {
+        assumeFalse("Skipping test for watch", FeatureUtil.isWatch());
         setDomainUserSelectionApproval(false);
         startNoBrowserRequireDefaultInternal(false);
     }
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
index 2faed09..212642b 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/DecodeEditEncodeTest.java
@@ -23,7 +23,6 @@
 import static android.media.MediaCodecInfo.CodecProfileLevel.VP9Profile2;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
@@ -230,17 +229,30 @@
         }
     }
 
-    @Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4})")
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{2}_{3}_{4}_{5})")
     public static Collection<Object[]> input() {
-        final List<Object[]> exhaustiveArgsList = Arrays.asList(new Object[][]{
-                // mediaType, width, height, bitrate, useHighBitDepth
-                {MediaFormat.MIMETYPE_VIDEO_AVC, 176, 144, 1000000, false},
-                {MediaFormat.MIMETYPE_VIDEO_AVC, 320, 240, 2000000, false},
-                {MediaFormat.MIMETYPE_VIDEO_AVC, 1280, 720, 6000000, false},
-                {MediaFormat.MIMETYPE_VIDEO_HEVC, 176, 144, 1000000, true},
-                {MediaFormat.MIMETYPE_VIDEO_HEVC, 320, 240, 2000000, true},
-                {MediaFormat.MIMETYPE_VIDEO_HEVC, 1280, 720, 6000000, true},
+        final List<Object[]> baseArgsList = Arrays.asList(new Object[][]{
+                // width, height, bitrate
+                {176, 144, 1000000},
+                {320, 240, 2000000},
+                {1280, 720, 6000000}
         });
+        final String[] mediaTypes = {MediaFormat.MIMETYPE_VIDEO_AVC,
+                MediaFormat.MIMETYPE_VIDEO_HEVC, MediaFormat.MIMETYPE_VIDEO_VP8,
+                MediaFormat.MIMETYPE_VIDEO_VP9, MediaFormat.MIMETYPE_VIDEO_AV1};
+        final boolean[] useHighBitDepthModes = {false, true};
+        final List<Object[]> exhaustiveArgsList = new ArrayList<>();
+        for (boolean useHighBitDepth : useHighBitDepthModes) {
+            for (String mediaType : mediaTypes) {
+                for (Object[] obj : baseArgsList) {
+                    if (mediaType.equals(MediaFormat.MIMETYPE_VIDEO_VP8) && useHighBitDepth) {
+                        continue;
+                    }
+                    exhaustiveArgsList.add(
+                            new Object[]{mediaType, obj[0], obj[1], obj[2], useHighBitDepth});
+                }
+            }
+        }
         return prepareParamList(exhaustiveArgsList);
     }
 
@@ -304,10 +316,7 @@
             throws IOException {
         VideoChunks sourceChunks = new VideoChunks();
 
-        if (!generateVideoFile(sourceChunks)) {
-            // No AVC codec?  Fail silently.
-            return;
-        }
+        generateVideoFile(sourceChunks);
 
         if (DEBUG_SAVE_FILE) {
             // Save a copy to a file.  We call it ".mp4", but it's actually just an elementary
@@ -333,10 +342,8 @@
     /**
      * Generates a test video file, saving it as VideoChunks.  We generate frames with GL to
      * avoid having to deal with multiple YUV formats.
-     *
-     * @return true on success, false on "soft" failure
      */
-    private boolean generateVideoFile(VideoChunks output)
+    private void generateVideoFile(VideoChunks output)
             throws IOException {
         if (VERBOSE) Log.d(TAG, "generateVideoFile " + mWidth + "x" + mHeight);
         MediaCodec encoder = null;
@@ -390,8 +397,6 @@
                 inputSurface.release();
             }
         }
-
-        return true;
     }
 
     /**
@@ -463,18 +468,15 @@
                         fail("encoderOutputBuffer " + encoderStatus + " was null");
                     }
 
-                    // Codec config flag must be set iff this is the first chunk of output.  This
-                    // may not hold for all codecs, but it appears to be the case for video/avc.
-                    assertTrue((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0 ||
-                            outputCount != 0);
-
                     if (info.size != 0) {
                         // Adjust the ByteBuffer values to match BufferInfo.
                         encodedData.position(info.offset);
                         encodedData.limit(info.offset + info.size);
 
                         output.addChunk(encodedData, info.flags, info.presentationTimeUs);
-                        outputCount++;
+                        if ((info.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) == 0) {
+                            outputCount++;
+                        }
                     }
 
                     encoder.releaseOutputBuffer(encoderStatus, false);
@@ -486,8 +488,7 @@
             }
         }
 
-        // One chunk per frame, plus one for the config data.
-        assertEquals("Frame count", NUM_FRAMES + 1, outputCount);
+        assertEquals("Frame count", NUM_FRAMES, outputCount);
     }
 
     /**
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
index b712fdf..30e8477 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeDecodeTest.java
@@ -708,7 +708,7 @@
                     if (VERBOSE) Log.d(TAG, "decoder output format changed: " +
                             decoderOutputFormat);
                 } else if (decoderStatus < 0) {
-                    fail("unexpected result from deocder.dequeueOutputBuffer: " + decoderStatus);
+                    fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
                 } else {  // decoderStatus >= 0
                     if (!toSurface) {
                         ByteBuffer outputFrame = decoderOutputBuffers[decoderStatus];
@@ -863,7 +863,7 @@
                     if (VERBOSE) Log.d(TAG, "decoder output format changed: " +
                             decoderOutputFormat);
                 } else if (decoderStatus < 0) {
-                    fail("unexpected result from deocder.dequeueOutputBuffer: " + decoderStatus);
+                    fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
                 } else {  // decoderStatus >= 0
                     if (VERBOSE) Log.d(TAG, "surface decoder given buffer " + decoderStatus +
                             " (size=" + info.size + ")");
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
index 2baad3f..96f05c6 100755
--- a/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/EncodeVirtualDisplayTest.java
@@ -359,7 +359,7 @@
                     if (VERBOSE) Log.d(TAG, "decoder output format changed: " +
                             decoderOutputFormat);
                 } else if (decoderStatus < 0) {
-                    fail("unexpected result from deocder.dequeueOutputBuffer: " + decoderStatus);
+                    fail("unexpected result from decoder.dequeueOutputBuffer: " + decoderStatus);
                 } else {  // decoderStatus >= 0
                     if (VERBOSE) Log.d(TAG, "surface decoder given buffer " + decoderStatus +
                             " (size=" + info.size + ")");
diff --git a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
index 32b0e3a..341c822 100644
--- a/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
+++ b/tests/tests/media/codec/src/android/media/codec/cts/MediaCodecCapabilitiesTest.java
@@ -747,7 +747,15 @@
             int minFrameRate = Math.max(vcaps.getSupportedFrameRatesFor(minWidth, minHeight)
                     .getLower().intValue(), 1);
             format = MediaFormat.createVideoFormat(mime, minWidth, minHeight);
-            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, caps.colorFormats[0]);
+            int colorFormat = caps.colorFormats[0];
+            for (int i = 0; i < caps.colorFormats.length; ++i) {
+                colorFormat = caps.colorFormats[i];
+                // Avoid COLOR_FormatSurface as we will be configuring the codec without a surface.
+                if (colorFormat != CodecCapabilities.COLOR_FormatSurface) {
+                    break;
+                }
+            }
+            format.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFormat);
             format.setInteger(MediaFormat.KEY_BIT_RATE, minBitrate);
             format.setInteger(MediaFormat.KEY_FRAME_RATE, minFrameRate);
             format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, IFRAME_INTERVAL);
diff --git a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
index 785c83d..97158b0 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaCodecClearKeyPlayer.java
@@ -15,6 +15,8 @@
  */
 package android.media.cts;
 
+import static org.junit.Assume.assumeFalse;
+
 import android.content.Context;
 import android.content.res.Resources;
 import android.media.AudioManager;
@@ -325,6 +327,8 @@
                     }
 
                     mMediaCas.provision(sProvisionStr);
+                    // If AIDL CAS service is being used, then setMediaCas will not work.
+                    assumeFalse(mMediaCas.isAidlHal());
                     extractor.setMediaCas(mMediaCas);
                     break;
                 }
diff --git a/tests/tests/media/decoder/jni/native-media-jni.cpp b/tests/tests/media/decoder/jni/native-media-jni.cpp
index d9a265e..236a97a 100755
--- a/tests/tests/media/decoder/jni/native-media-jni.cpp
+++ b/tests/tests/media/decoder/jni/native-media-jni.cpp
@@ -300,13 +300,12 @@
 
     int numtracks = AMediaExtractor_getTrackCount(ex);
 
-    AMediaCodec **codec = new AMediaCodec*[numtracks];
-    AMediaFormat **format = new AMediaFormat*[numtracks];
-    memset(format, 0, sizeof(AMediaFormat*) * numtracks);
-    bool *sawInputEOS = new bool[numtracks];
-    bool *sawOutputEOS = new bool[numtracks];
-    simplevector<int> *sizes = new simplevector<int>[numtracks];
-    CallbackData *callbackData = new CallbackData[numtracks];
+    std::unique_ptr<AMediaCodec*[]> codec(new AMediaCodec*[numtracks]());
+    std::unique_ptr<AMediaFormat*[]> format(new AMediaFormat*[numtracks]());
+    std::unique_ptr<bool[]> sawInputEOS(new bool[numtracks]);
+    std::unique_ptr<bool[]> sawOutputEOS(new bool[numtracks]);
+    std::unique_ptr<simplevector<int>[]> sizes(new simplevector<int>[numtracks]);
+    std::unique_ptr<CallbackData[]> callbackData(new CallbackData[numtracks]);
 
     ALOGV("input has %d tracks", numtracks);
     for (int i = 0; i < numtracks; i++) {
@@ -458,17 +457,11 @@
     }
     env->ReleaseIntArrayElements(ret, org, 0);
 
-    delete[] callbackData;
-    delete[] sizes;
-    delete[] sawOutputEOS;
-    delete[] sawInputEOS;
     for (int i = 0; i < numtracks; i++) {
         AMediaFormat_delete(format[i]);
         AMediaCodec_stop(codec[i]);
         AMediaCodec_delete(codec[i]);
     }
-    delete[] format;
-    delete[] codec;
     AMediaExtractor_delete(ex);
     AMediaDataSource_delete(ndkSrc);
     return ret;
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 48eaa42..9750f30 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
@@ -507,7 +507,7 @@
                 if (VERBOSE) Log.v(TAG, "decoder output format changed: " + outFormat);
             } else if (res < 0) {
                 // Should be decoding error.
-                fail("unexpected result from deocder.dequeueOutputBuffer: " + res);
+                fail("unexpected result from decoder.dequeueOutputBuffer: " + res);
             } else {
                 if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
                     sawOutputEOS = true;
diff --git a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
index f879528..3c2ca72 100644
--- a/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
+++ b/tests/tests/media/drmframework/src/android/media/drmframework/cts/MediaDrmClearkeyTest.java
@@ -20,6 +20,7 @@
 import android.media.MediaDrm.KeyStatus;
 import android.media.MediaDrm.MediaDrmStateException;
 import android.media.MediaDrmException;
+import android.media.MediaDrmThrowable;
 import android.media.MediaFormat;
 import android.media.NotProvisionedException;
 import android.media.ResourceBusyException;
@@ -51,6 +52,7 @@
 import org.json.JSONArray;
 import org.json.JSONException;
 import org.json.JSONObject;
+import org.junit.Assert;
 
 import java.nio.charset.Charset;
 import java.util.ArrayList;
@@ -968,6 +970,10 @@
             if (!Arrays.equals(deviceId, getByteArrayProperty(drm, DEVICEID_PROPERTY_KEY))) {
                 throw new Error("Failed to set byte array for key=" + DEVICEID_PROPERTY_KEY);
             }
+
+            for (String k: new String[] {"oemError", "errorContext"}) {
+                testIntegerProperties(drm, k);
+            }
         } finally {
             stopDrm(drm);
         }
@@ -1232,10 +1238,16 @@
 
         MediaDrm drm = null;
         boolean gotException = false;
+        final int OEM_ERROR = 123;
+        final int ERROR_CONTEXT = 456;
 
         try {
             drm = new MediaDrm(CLEARKEY_SCHEME_UUID);
             drm.setPropertyString("drmErrorTest", "resourceContention");
+            if (getClearkeyVersionInt(drm) >= 14) {
+                drm.setPropertyString("oemError", Integer.toString(OEM_ERROR));
+                drm.setPropertyString("errorContext", Integer.toString(ERROR_CONTEXT));
+            }
             byte[] sessionId = drm.openSession();
 
             try {
@@ -1248,6 +1260,13 @@
                 if(sIsAtLeastS && !e.isTransient()) {
                         throw new Error("Expected transient ERROR_RESOURCE_CONTENTION");
                 }
+                if (getClearkeyVersionInt(drm) >= 14) {
+                    final MediaDrmThrowable mdt = e;
+                    final int RESOURCE_CONTENTION_AIDL = 16;
+                    assertEquals("Vendor Error mismatch", mdt.getVendorError(), RESOURCE_CONTENTION_AIDL);
+                    assertEquals("OEM Error mismatch", mdt.getOemError(), OEM_ERROR);
+                    assertEquals("Error context mismatch", mdt.getErrorContext(), ERROR_CONTEXT);
+                }
                 gotException = true;
             }
         } catch(Exception e) {
@@ -1643,8 +1662,6 @@
             assertTrue("Expected ERROR_SESSION_NOT_OPENED value in info",
                     e.getDiagnosticInfo().contains(
                             String.valueOf(MediaDrm.ErrorCodes.ERROR_SESSION_NOT_OPENED)));
-            assertEquals("No vendor error expected from Clearkey", 0, e.getVendorError());
-            assertEquals("No OEM error expected from Clearkey", 0, e.getOemError());
         }  finally {
             if (drm != null) {
                 drm.close();
@@ -1652,6 +1669,25 @@
         }
     }
 
+    private void testIntegerProperties(MediaDrm drm, String testKey)
+            throws ResourceBusyException, UnsupportedSchemeException, NotProvisionedException {
+        if (getClearkeyVersionInt(drm) < 14) {
+            return;
+        }
+        String testValue = "123456";
+        assertEquals("Default value not 0", drm.getPropertyString(testKey), "0");
+        Assert.assertThrows("Non-numeric must throw", Exception.class, () -> {
+            drm.setPropertyString(testKey, "xyz"); });
+        Assert.assertThrows("Non-integral must throw", Exception.class, () -> {
+            drm.setPropertyString(testKey, "3.141"); });
+        Assert.assertThrows("Out-of-range (MAX) must throw", Exception.class, () -> {
+            drm.setPropertyString(testKey, Long.toString(Long.MAX_VALUE)); });
+        Assert.assertThrows("Out-of-range (MIN) must throw", Exception.class, () -> {
+            drm.setPropertyString(testKey, Long.toString(Long.MIN_VALUE)); });
+        drm.setPropertyString(testKey, testValue);
+        assertEquals("Property didn't match", drm.getPropertyString(testKey), testValue);
+    }
+
     private String getClearkeyVersion(MediaDrm drm) {
         try {
             return drm.getPropertyString("version");
@@ -1660,6 +1696,14 @@
         }
     }
 
+    private int getClearkeyVersionInt(MediaDrm drm) {
+        try {
+            return Integer.parseInt(drm.getPropertyString("version"));
+        } catch (Exception e) {
+            return Integer.MIN_VALUE;
+        }
+    }
+
     private boolean cannotHandleGetPropertyByteArray(MediaDrm drm) {
         boolean apiNotSupported = false;
         byte[] bytes = new byte[0];
diff --git a/tests/tests/ndef/OWNERS b/tests/tests/ndef/OWNERS
index d92b2ab..5a93fd0 100644
--- a/tests/tests/ndef/OWNERS
+++ b/tests/tests/ndef/OWNERS
@@ -2,4 +2,5 @@
 alisher@google.com
 jackcwyu@google.com
 georgekgchang@google.com
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
diff --git a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
index d114ab5..b527e77 100644
--- a/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
+++ b/tests/tests/networksecurityconfig/src/android/security/net/config/cts/TestUtils.java
@@ -18,28 +18,29 @@
 
 import android.net.http.AndroidHttpClient;
 
-import java.io.InputStream;
+import junit.framework.Assert;
+
+import org.apache.http.HttpResponse;
+import org.apache.http.client.methods.HttpGet;
+
 import java.io.IOException;
+import java.io.InputStream;
 import java.net.HttpURLConnection;
-import java.net.Socket;
 import java.net.URL;
 import java.security.KeyStore;
 import java.security.cert.Certificate;
 import java.security.cert.CertificateFactory;
 import java.security.cert.X509Certificate;
-import java.util.List;
 import java.util.ArrayList;
+import java.util.List;
+
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLHandshakeException;
+import javax.net.ssl.SSLSocket;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.TrustManagerFactory;
 import javax.net.ssl.X509TrustManager;
 
-import junit.framework.Assert;
-
-import org.apache.http.HttpResponse;
-import org.apache.http.client.methods.HttpGet;
-
 public final class TestUtils extends Assert {
 
     private TestUtils() {
@@ -91,8 +92,9 @@
     private static void assertSslSocketFails(String host, int port)
             throws Exception {
         try {
-            Socket s = SSLContext.getDefault().getSocketFactory().createSocket(host, port);
-            s.getInputStream();
+            SSLSocket s =
+                    (SSLSocket) SSLContext.getDefault().getSocketFactory().createSocket(host, port);
+            s.startHandshake();
             fail("Connection to " + host + ":" + port + " succeeded");
         } catch (SSLHandshakeException expected) {
         }
@@ -100,8 +102,9 @@
 
     private static void assertSslSocketSucceeds(String host, int port)
             throws Exception {
-        Socket s = SSLContext.getDefault().getSocketFactory().createSocket(host, port);
-        s.getInputStream();
+        SSLSocket s =
+                (SSLSocket) SSLContext.getDefault().getSocketFactory().createSocket(host, port);
+        s.startHandshake();
     }
 
     private static void assertUrlConnectionFails(String host, int port, boolean https)
diff --git a/tests/tests/nfc/AndroidManifest.xml b/tests/tests/nfc/AndroidManifest.xml
index 3e1d16a..ae7fa49 100644
--- a/tests/tests/nfc/AndroidManifest.xml
+++ b/tests/tests/nfc/AndroidManifest.xml
@@ -33,6 +33,9 @@
             <meta-data android:name="android.nfc.cardemulation.host_apdu_service"
                        android:resource="@xml/payment_aid_list"/>
         </service>
+        <activity android:name="android.nfc.cts.NfcFCardEmulationActivity"
+             android:exported="false">
+        </activity>
     </application>
 
     <!-- This is a self-instrumenting test package. -->
@@ -43,4 +46,4 @@
                    android:value="com.android.cts.runner.CtsTestRunListener"/>
     </instrumentation>
 
-</manifest>
\ No newline at end of file
+</manifest>
diff --git a/tests/tests/nfc/OWNERS b/tests/tests/nfc/OWNERS
index d92b2ab..5a93fd0 100644
--- a/tests/tests/nfc/OWNERS
+++ b/tests/tests/nfc/OWNERS
@@ -2,4 +2,5 @@
 alisher@google.com
 jackcwyu@google.com
 georgekgchang@google.com
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
diff --git a/tests/tests/nfc/src/android/nfc/cts/CardEmulationTest.java b/tests/tests/nfc/src/android/nfc/cts/CardEmulationTest.java
new file mode 100644
index 0000000..b1e83b4
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/CardEmulationTest.java
@@ -0,0 +1,281 @@
+package android.nfc.cts;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.nfc.cardemulation.*;
+import android.nfc.INfcCardEmulation;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.internal.util.reflection.FieldSetter;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@RunWith(JUnit4.class)
+public class CardEmulationTest {
+    private NfcAdapter mAdapter;
+    private static final ComponentName mService =
+        new ComponentName("android.nfc.cts", "android.nfc.cts.CtsMyHostApduService");
+
+    @Mock private INfcCardEmulation mEmulation;
+
+    private boolean supportsHardware() {
+        final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        assumeTrue(supportsHardware());
+        Context mContext = InstrumentationRegistry.getContext();
+        mAdapter = NfcAdapter.getDefaultAdapter(mContext);
+        Assert.assertNotNull(mAdapter);
+    }
+
+    @Test
+    public void getNonNullInstance() {
+        CardEmulation instance = CardEmulation.getInstance(mAdapter);
+        Assert.assertNotNull(instance);
+    }
+
+    @Test
+    public void testIsDefaultServiceForCategory() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.isDefaultServiceForCategory(anyInt(), any(ComponentName.class),
+            anyString())).thenReturn(true);
+        boolean result = instance.isDefaultServiceForCategory(mService,
+            CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsDefaultServiceForAid() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        String aid = "00000000000000";
+        when(mEmulation.isDefaultServiceForAid(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(true);
+        boolean result = instance.isDefaultServiceForAid(mService, aid);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testCategoryAllowsForegroundPreferenceWithCategoryPayment() {
+        CardEmulation instance = CardEmulation.getInstance(mAdapter);
+        boolean result
+            = instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testCategoryAllowsForegroundPrefenceWithCategoryOther() {
+        CardEmulation instance = CardEmulation.getInstance(mAdapter);
+        boolean result
+            = instance.categoryAllowsForegroundPreference(CardEmulation.CATEGORY_OTHER);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testGetSelectionModeForCategoryWithCategoryPaymentAndPaymentRegistered()
+        throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.isDefaultPaymentRegistered()).thenReturn(true);
+        int result = instance.getSelectionModeForCategory(CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertEquals(CardEmulation.SELECTION_MODE_PREFER_DEFAULT, result);
+    }
+
+    @Test
+    public void testGetSelectionModeForCategoryWithCategoryPaymentAndWithoutPaymentRegistered()
+        throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.isDefaultPaymentRegistered()).thenReturn(false);
+        int result = instance.getSelectionModeForCategory(CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertEquals(CardEmulation.SELECTION_MODE_ALWAYS_ASK, result);
+    }
+
+    @Test
+    public void testGetSelectionModeForCategoryWithCategoryOther() {
+        CardEmulation instance = CardEmulation.getInstance(mAdapter);
+        int result = instance.getSelectionModeForCategory(CardEmulation.CATEGORY_OTHER);
+        Assert.assertEquals(CardEmulation.SELECTION_MODE_ASK_IF_CONFLICT, result);
+    }
+
+    @Test
+    public void testRegisterAidsForService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        ArrayList<String> aids = new ArrayList<String>();
+        aids.add("00000000000000");
+        when(mEmulation.registerAidGroupForService(anyInt(), any(ComponentName.class),
+            any(AidGroup.class))).thenReturn(true);
+        boolean result
+            = instance.registerAidsForService(mService, CardEmulation.CATEGORY_PAYMENT, aids);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testUnsetOffHostForService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.unsetOffHostForService(anyInt(), any(ComponentName.class)))
+            .thenReturn(true);
+        boolean result = instance.unsetOffHostForService(mService);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testSetOffHostForService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        String offHostSecureElement = "eSE";
+        when(mEmulation.setOffHostForService(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(true);
+        boolean result = instance.setOffHostForService(mService, offHostSecureElement);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testGetAidsForService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        ArrayList<String> aids = new ArrayList<String>();
+        aids.add("00000000000000");
+        AidGroup aidGroup = new AidGroup(aids, CardEmulation.CATEGORY_PAYMENT);
+        when(mEmulation.getAidGroupForService(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(aidGroup);
+        List<String> result = instance.getAidsForService(mService, CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertEquals(aids, result);
+    }
+
+    @Test
+    public void testRemoveAidsForService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.removeAidGroupForService(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(true);
+        boolean result = instance.removeAidsForService(mService, CardEmulation.CATEGORY_PAYMENT);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testSetPreferredService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        Activity activity = createAndResumeActivity();
+        when(mEmulation.setPreferredService(any(ComponentName.class))).thenReturn(true);
+        boolean result = instance.setPreferredService(activity, mService);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testUnsetPreferredService() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        Activity activity = createAndResumeActivity();
+        when(mEmulation.unsetPreferredService()).thenReturn(true);
+        boolean result = instance.unsetPreferredService(activity);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testSupportsAidPrefixRegistration() throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        when(mEmulation.supportsAidPrefixRegistration()).thenReturn(true);
+        boolean result = instance.supportsAidPrefixRegistration();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testGetAidsForPreferredPaymentService() throws NoSuchFieldException,
+        RemoteException {
+        CardEmulation instance = createMockedInstance();
+        ArrayList<AidGroup> dynamicAidGroups = new ArrayList<AidGroup>();
+        ArrayList<String> aids = new ArrayList<String>();
+        aids.add("00000000000000");
+        AidGroup aidGroup = new AidGroup(aids, CardEmulation.CATEGORY_PAYMENT);
+        dynamicAidGroups.add(aidGroup);
+        ApduServiceInfo serviceInfo = new ApduServiceInfo(new ResolveInfo(), false, "",
+            new ArrayList<AidGroup>(), dynamicAidGroups, false, 0, 0, "", "", "");
+        when(mEmulation.getPreferredPaymentService(anyInt())).thenReturn(serviceInfo);
+        List<String> result = instance.getAidsForPreferredPaymentService();
+        Assert.assertEquals(aids, result);
+    }
+
+    @Test
+    public void testGetRouteDestinationForPreferredPaymentServiceWithOnHost()
+        throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        ApduServiceInfo serviceInfo = new ApduServiceInfo(new ResolveInfo(), /* onHost = */ true,
+            "", new ArrayList<AidGroup>(), new ArrayList<AidGroup>(), false, 0, 0, "", "", "");
+        when(mEmulation.getPreferredPaymentService(anyInt())).thenReturn(serviceInfo);
+        String result = instance.getRouteDestinationForPreferredPaymentService();
+        Assert.assertEquals("Host", result);
+    }
+
+    @Test
+    public void testGetRouteDestinationForPreferredPaymentServiceWithOffHostAndNoSecureElement()
+        throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        ApduServiceInfo serviceInfo = new ApduServiceInfo(new ResolveInfo(), /* onHost = */ false,
+            "", new ArrayList<AidGroup>(), new ArrayList<AidGroup>(), false, 0, 0, "",
+            /* offHost = */ null, "");
+        when(mEmulation.getPreferredPaymentService(anyInt())).thenReturn(serviceInfo);
+        String result = instance.getRouteDestinationForPreferredPaymentService();
+        Assert.assertEquals("OffHost", result);
+    }
+
+    @Test
+    public void testGetRouteDestinationForPreferredPaymentServiceWithOffHostAndSecureElement()
+        throws NoSuchFieldException, RemoteException {
+        CardEmulation instance = createMockedInstance();
+        String offHostSecureElement = "OffHost Secure Element";
+        ApduServiceInfo serviceInfo = new ApduServiceInfo(new ResolveInfo(), /* onHost = */ false,
+            "", new ArrayList<AidGroup>(), new ArrayList<AidGroup>(), false, 0, 0, "",
+            /* offHost = */ offHostSecureElement, "");
+        when(mEmulation.getPreferredPaymentService(anyInt())).thenReturn(serviceInfo);
+        String result = instance.getRouteDestinationForPreferredPaymentService();
+        Assert.assertEquals(offHostSecureElement, result);
+    }
+
+    @Test
+    public void testGetDescriptionForPreferredPaymentService() throws NoSuchFieldException,
+        RemoteException {
+        CardEmulation instance = createMockedInstance();
+        String description = "Preferred Payment Service Description";
+        ApduServiceInfo serviceInfo = new ApduServiceInfo(new ResolveInfo(), false,
+            /* description */ description, new ArrayList<AidGroup>(), new ArrayList<AidGroup>(),
+            false, 0, 0, "", "", "");
+        when(mEmulation.getPreferredPaymentService(anyInt())).thenReturn(serviceInfo);
+        CharSequence result = instance.getDescriptionForPreferredPaymentService();
+        Assert.assertEquals(description, result);
+    }
+
+    private Activity createAndResumeActivity() {
+        Intent intent
+            = new Intent(ApplicationProvider.getApplicationContext(),
+                NfcFCardEmulationActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+        InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        return activity;
+    }
+
+    private CardEmulation createMockedInstance() throws NoSuchFieldException {
+        CardEmulation instance = CardEmulation.getInstance(mAdapter);
+        FieldSetter.setField(instance, instance.getClass().getDeclaredField("sService"), mEmulation);
+        return instance;
+    }
+}
diff --git a/tests/tests/nfc/src/android/nfc/cts/CtsMyHostNfcFService.java b/tests/tests/nfc/src/android/nfc/cts/CtsMyHostNfcFService.java
new file mode 100644
index 0000000..32095ff
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/CtsMyHostNfcFService.java
@@ -0,0 +1,16 @@
+package android.nfc.cts;
+
+import android.nfc.cardemulation.*;
+import android.os.Bundle;
+
+public class CtsMyHostNfcFService extends HostNfcFService {
+    @Override
+    public byte[] processNfcFPacket(byte[] commandPacket, Bundle extras) {
+        return new byte[0];
+    }
+
+    @Override
+    public void onDeactivated(int reason) {
+        return;
+    }
+}
diff --git a/tests/tests/nfc/src/android/nfc/cts/HostNfcFServiceTest.java b/tests/tests/nfc/src/android/nfc/cts/HostNfcFServiceTest.java
new file mode 100644
index 0000000..cf41790
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/HostNfcFServiceTest.java
@@ -0,0 +1,56 @@
+package android.nfc.cts;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.os.Looper;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class HostNfcFServiceTest {
+    private CtsMyHostNfcFService service;
+
+    @Before
+    public void setUp() {
+        if (Looper.myLooper() == null) {
+            Looper.prepare();
+        }
+        service = new CtsMyHostNfcFService();
+    }
+
+    @Test
+    public void testOnBind() {
+        Intent serviceIntent
+            = new Intent(CtsMyHostNfcFService.SERVICE_INTERFACE);
+        Assert.assertNotNull(service.onBind(serviceIntent));
+    }
+
+    @Test
+    public void testSendResponsePacket() {
+        try {
+            byte[] responsePacket = new byte[0];
+            service.sendResponsePacket(responsePacket);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testProcessNfcFPacket() {
+        byte[] result = service.processNfcFPacket(new byte[0], new Bundle());
+        Assert.assertNotNull(result);
+        Assert.assertTrue(result.length == 0);
+    }
+
+    @Test
+    public void testOnDeactivated() {
+        try {
+            service.onDeactivated(CtsMyHostNfcFService.DEACTIVATION_LINK_LOSS);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+}
diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcAdapterTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcAdapterTest.java
new file mode 100644
index 0000000..5453adb
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/NfcAdapterTest.java
@@ -0,0 +1,249 @@
+package android.nfc.cts;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.anyBoolean;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.doNothing;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.nfc.*;
+import android.nfc.tech.*;
+import android.os.Bundle;
+import android.os.RemoteException;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
+
+import java.util.ArrayList;
+import java.util.concurrent.Executor;
+import java.util.HashMap;
+
+@RunWith(JUnit4.class)
+public class NfcAdapterTest {
+    @Mock private INfcAdapter mService;
+    private Context mContext;
+
+    private boolean supportsHardware() {
+        final PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_NFC);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = InstrumentationRegistry.getContext();
+        assumeTrue(supportsHardware());
+    }
+
+    @Test
+    public void testGetDefaultAdapter() {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        Assert.assertNotNull(adapter);
+    }
+
+    @Test
+    public void testAddNfcUnlockHandler() {
+        try {
+            NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+            adapter.addNfcUnlockHandler(new CtsNfcUnlockHandler(), new String[]{"IsoDep"});
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testDisableWithNoParams() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.disable(anyBoolean())).thenReturn(true);
+        boolean result = adapter.disable();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testDisableWithParam() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.disable(anyBoolean())).thenReturn(true);
+        boolean result = adapter.disable(true);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testDisableForegroundDispatch() {
+        try {
+            NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+            Activity activity = createAndResumeActivity();
+            adapter.disableForegroundDispatch(activity);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testDisableReaderMode() {
+        try {
+            NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+            Activity activity = createAndResumeActivity();
+            adapter.disableReaderMode(activity);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testEnable() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.enable()).thenReturn(true);
+        boolean result = adapter.enable();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testEnableForegroundDispatch() {
+        try {
+            NfcAdapter adapter = createMockedInstance();
+            Activity activity = createAndResumeActivity();
+            Intent intent = new Intent(ApplicationProvider.getApplicationContext(),
+                NfcFCardEmulationActivity.class);
+            PendingIntent pendingIntent
+                = PendingIntent.getActivity(ApplicationProvider.getApplicationContext(),
+                    0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
+            String[][] techLists = new String[][]{new String[]{}};
+            doNothing().when(mService).setForegroundDispatch(any(PendingIntent.class),
+                any(IntentFilter[].class), any(TechListParcel.class));
+            adapter.enableForegroundDispatch(activity, pendingIntent, null, techLists);
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testEnableReaderMode() {
+        try {
+            NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+            Activity activity = createAndResumeActivity();
+            adapter.enableReaderMode(activity, new CtsReaderCallback(),
+                NfcAdapter.FLAG_READER_NFC_A, new Bundle());
+        } catch (Exception e) {
+            throw new IllegalStateException("Unexpected Exception: " + e);
+        }
+    }
+
+    @Test
+    public void testEnableSecureNfc() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.setNfcSecure(anyBoolean())).thenReturn(true);
+        boolean result = adapter.enableSecureNfc(true);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testGetNfcAntennaInfo() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        NfcAntennaInfo info = new NfcAntennaInfo(0, 0, false,
+            new ArrayList<AvailableNfcAntenna>());
+        when(mService.getNfcAntennaInfo()).thenReturn(info);
+        NfcAntennaInfo result = adapter.getNfcAntennaInfo();
+        Assert.assertEquals(info, result);
+    }
+
+    @Test
+    public void testIgnore() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        Tag tag = new Tag(new byte[]{0x00}, new int[]{}, new Bundle[]{}, 0, 0L, null);
+        when(mService.ignore(anyInt(), anyInt(), eq(null))).thenReturn(true);
+        boolean result = adapter.ignore(tag, 0, null, null);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsControllerAlwaysOn() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.isControllerAlwaysOn()).thenReturn(true);
+        boolean result = adapter.isControllerAlwaysOn();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsControllerAlwaysOnSupported() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.isControllerAlwaysOnSupported()).thenReturn(true);
+        boolean result = adapter.isControllerAlwaysOnSupported();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsEnabled() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.getState()).thenReturn(NfcAdapter.STATE_ON);
+        boolean result = adapter.isEnabled();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsSecureNfcEnabled() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.isNfcSecureEnabled()).thenReturn(true);
+        boolean result = adapter.isSecureNfcEnabled();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testIsSecureNfcSupported() throws NoSuchFieldException, RemoteException {
+        NfcAdapter adapter = createMockedInstance();
+        when(mService.deviceSupportsNfcSecure()).thenReturn(true);
+        boolean result = adapter.isSecureNfcSupported();
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testRemoveNfcUnlockHandler() {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        boolean result = adapter.removeNfcUnlockHandler(new CtsNfcUnlockHandler());
+        Assert.assertTrue(result);
+    }
+
+    private class CtsReaderCallback implements NfcAdapter.ReaderCallback {
+        @Override
+        public void onTagDiscovered(Tag tag) {}
+    }
+
+    private class CtsNfcUnlockHandler implements NfcAdapter.NfcUnlockHandler {
+        @Override
+        public boolean onUnlockAttempted(Tag tag) {
+            return true;
+        }
+    }
+
+    private Activity createAndResumeActivity() {
+        Intent intent = new Intent(ApplicationProvider.getApplicationContext(),
+            NfcFCardEmulationActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+        InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        return activity;
+    }
+
+    private NfcAdapter createMockedInstance() throws NoSuchFieldException {
+        NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
+        FieldSetter.setField(adapter, adapter.getClass().getDeclaredField("sService"), mService);
+        return adapter;
+    }
+}
diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcAntennaLocationApiTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcAntennaLocationApiTest.java
index 7746d3a..18ca614 100644
--- a/tests/tests/nfc/src/android/nfc/cts/NfcAntennaLocationApiTest.java
+++ b/tests/tests/nfc/src/android/nfc/cts/NfcAntennaLocationApiTest.java
@@ -28,16 +28,16 @@
 
 import androidx.test.InstrumentationRegistry;
 
+import java.util.ArrayList;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
 public class NfcAntennaLocationApiTest {
-    private static int sDeviceWidth = 111;
-    private static int sDeviceHeight = 112;
-    private static boolean sDeviceFoldable = true;
-    private static int sAntennaX = 12;
-    private static int sAntennaY = 13;
+
+    private static final int ANTENNA_X = 12;
+    private static final int ANTENNA_Y = 13;
 
     private boolean supportsHardware() {
         final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
@@ -61,23 +61,41 @@
 
     /** Tests getNfcAntennaInfo API */
     @Test
-    public void testNfcAntennaInfoIsReturned() {
+    public void testGetNfcAntennaInfo() {
         NfcAntennaInfo nfcAntennaInfo = mAdapter.getNfcAntennaInfo();
 
-        assertEquals("Device widths do not match", sDeviceWidth,
+        assertEquals("Device widths do not match", 0,
                 nfcAntennaInfo.getDeviceWidth());
-        assertEquals("Device heights do not match", sDeviceHeight,
+        assertEquals("Device heights do not match", 0,
                 nfcAntennaInfo.getDeviceHeight());
-        assertEquals("Device foldable do not match", sDeviceFoldable,
+        assertEquals("Device foldable do not match", false,
                 nfcAntennaInfo.isDeviceFoldable());
-        assertEquals("Wrong number of available antennas", 1,
+        assertEquals("Wrong number of available antennas", 0,
                 nfcAntennaInfo.getAvailableNfcAntennas().size());
 
-        AvailableNfcAntenna availableNfcAntenna = nfcAntennaInfo.getAvailableNfcAntennas().get(0);
+        AvailableNfcAntenna availableNfcAntenna = new AvailableNfcAntenna(ANTENNA_X, ANTENNA_Y);
 
         assertEquals("Wrong nfc antenna X axis",
-                availableNfcAntenna.getLocationX(), sAntennaX);
+                availableNfcAntenna.getLocationX(), ANTENNA_X);
         assertEquals("Wrong nfc antenna Y axis",
-                availableNfcAntenna.getLocationY(), sAntennaY);
+                availableNfcAntenna.getLocationY(), ANTENNA_Y);
+    }
+
+    @Test
+    public void testNfcAntennaInfoConstructor() {
+	int deviceWidth = 0;
+	int deviceHeight = 0;
+	boolean deviceFoldable = false;
+        NfcAntennaInfo nfcAntennaInfo = new NfcAntennaInfo(deviceWidth, deviceHeight,
+            deviceFoldable, new ArrayList<AvailableNfcAntenna>());
+
+        assertEquals("Device widths do not match", deviceWidth,
+                nfcAntennaInfo.getDeviceWidth());
+        assertEquals("Device heights do not match", deviceHeight,
+                nfcAntennaInfo.getDeviceHeight());
+        assertEquals("Device foldable do not match", deviceFoldable,
+                nfcAntennaInfo.isDeviceFoldable());
+        assertEquals("Wrong number of available antennas", 0,
+                nfcAntennaInfo.getAvailableNfcAntennas().size());
     }
 }
diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationActivity.java b/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationActivity.java
new file mode 100644
index 0000000..ff9c115
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationActivity.java
@@ -0,0 +1,6 @@
+package android.nfc.cts;
+
+import android.app.Activity;
+
+public class NfcFCardEmulationActivity extends Activity {
+}
diff --git a/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationTest.java b/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationTest.java
new file mode 100644
index 0000000..0d3828a
--- /dev/null
+++ b/tests/tests/nfc/src/android/nfc/cts/NfcFCardEmulationTest.java
@@ -0,0 +1,142 @@
+package android.nfc.cts;
+
+import static org.junit.Assume.assumeTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.anyString;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.nfc.cardemulation.*;
+import android.nfc.INfcFCardEmulation;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import androidx.test.core.app.ApplicationProvider;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.internal.util.reflection.FieldSetter;
+
+import java.io.IOException;
+
+@RunWith(JUnit4.class)
+public class NfcFCardEmulationTest {
+    private NfcAdapter mAdapter;
+    private static final ComponentName mService =
+        new ComponentName("android.nfc.cts", "android.nfc.cts.CtsMyHostApduService");
+
+    @Mock private INfcFCardEmulation mockEmulation;
+
+    private boolean supportsHardware() {
+        final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF);
+    }
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        assumeTrue(supportsHardware());
+        Context mContext = InstrumentationRegistry.getContext();
+        mAdapter = NfcAdapter.getDefaultAdapter(mContext);
+        Assert.assertNotNull(mAdapter);
+    }
+
+    @Test
+    public void getNonNullInstance() {
+        NfcFCardEmulation instance = NfcFCardEmulation.getInstance(mAdapter);
+        Assert.assertNotNull(instance);
+    }
+
+    @Test
+    public void testGetSystemCodeForService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        String code = "System Code";
+        when(mockEmulation.getSystemCodeForService(anyInt(),any(ComponentName.class)))
+            .thenReturn(code);
+        String result = instance.getSystemCodeForService(mService);
+        Assert.assertEquals(result, code);
+    }
+
+    @Test
+    public void testRegisterCodeForService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        String code = "4000";
+        when(mockEmulation.registerSystemCodeForService(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(true);
+        boolean result = instance.registerSystemCodeForService(mService, code);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testUnregisterSystemCodeForService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        when(mockEmulation.removeSystemCodeForService(anyInt(), any(ComponentName.class)))
+            .thenReturn(true);
+        boolean result = instance.unregisterSystemCodeForService(mService);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testGetNfcid2ForService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        String testNfcid2 = "02FE000000000000";
+        when(mockEmulation.getNfcid2ForService(anyInt(), any(ComponentName.class)))
+            .thenReturn(testNfcid2);
+        String result = instance.getNfcid2ForService(mService);
+        Assert.assertEquals(result, testNfcid2);
+    }
+
+    @Test
+    public void testSetNfcid2ForService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        String testNfcid2 = "02FE000000000000";
+        when(mockEmulation.setNfcid2ForService(anyInt(), any(ComponentName.class), anyString()))
+            .thenReturn(true);
+        boolean result = instance.setNfcid2ForService(mService, testNfcid2);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testEnableService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        Activity activity = createAndResumeActivity();
+        when(mockEmulation.enableNfcFForegroundService(any(ComponentName.class))).thenReturn(true);
+        boolean result = instance.enableService(activity, mService);
+        Assert.assertTrue(result);
+    }
+
+    @Test
+    public void testDisableService() throws NoSuchFieldException, RemoteException {
+        NfcFCardEmulation instance = createMockedInstance();
+        Activity activity = createAndResumeActivity();
+        when(mockEmulation.disableNfcFForegroundService()).thenReturn(true);
+        boolean result = instance.disableService(activity);
+        Assert.assertTrue(result);
+    }
+
+    private Activity createAndResumeActivity() {
+        Intent intent
+            = new Intent(ApplicationProvider.getApplicationContext(),
+                NfcFCardEmulationActivity.class);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        Activity activity = InstrumentationRegistry.getInstrumentation().startActivitySync(intent);
+        InstrumentationRegistry.getInstrumentation().callActivityOnResume(activity);
+        return activity;
+    }
+
+    private NfcFCardEmulation createMockedInstance() throws NoSuchFieldException {
+        NfcFCardEmulation instance = NfcFCardEmulation.getInstance(mAdapter);
+        FieldSetter.setField(instance, instance.getClass().getDeclaredField("sService"), mockEmulation);
+        return instance;
+    }
+}
diff --git a/tests/tests/notificationlegacy/notificationlegacy30/src/android/app/notification/legacy30/cts/NotificationTemplateApi30Test.kt b/tests/tests/notificationlegacy/notificationlegacy30/src/android/app/notification/legacy30/cts/NotificationTemplateApi30Test.kt
index 29638bd..6a1077c 100644
--- a/tests/tests/notificationlegacy/notificationlegacy30/src/android/app/notification/legacy30/cts/NotificationTemplateApi30Test.kt
+++ b/tests/tests/notificationlegacy/notificationlegacy30/src/android/app/notification/legacy30/cts/NotificationTemplateApi30Test.kt
@@ -19,7 +19,6 @@
 import android.app.Notification
 import android.app.cts.NotificationTemplateTestBase
 import android.content.pm.PackageManager
-import android.util.Log
 import android.view.View
 import android.widget.ImageView
 import android.widget.TextView
@@ -58,11 +57,10 @@
     }
 
     fun testWideIcon_inBigPicture_isSquareForLegacyApps() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_isSquareForLegacyApps" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 100)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -92,11 +90,10 @@
     }
 
     fun testPromoteBigPicture_withoutLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withoutLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+                if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -111,8 +108,7 @@
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         // there should be no icon in the large state
         checkIconView(builder.createBigContentView()) { iconView ->
@@ -121,11 +117,10 @@
     }
 
     fun testPromoteBigPicture_withLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(80, 65)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -137,36 +132,26 @@
                         .showBigPictureWhenCollapsed(true)
                 )
 
-        // At really high densities the size of rendered icon can dip below the
-        // tested size - we allow rendering of smaller icon with the same
-        // aspect ratio then.
-        val expectedIconWidth = minOf(rightIconSize(), 80)
-        val expectedIconHeight = minOf(rightIconSize() * 65 / 80, 65)
-
         // the promoted big picture is shown with enlarged aspect ratio
         checkIconView(builder.createContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
         }
         // because it doesn't target S, the icon is still shown in a square
         checkIconView(builder.createBigContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width).isEqualTo(iconView.height)
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(expectedIconWidth)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(expectedIconHeight)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
     fun testPromoteBigPicture_withBigLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withBigLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
+        if (skipIfPlatformDoesNotSupportNotificationStyles()) {
             return
         }
+
         val picture = createBitmap(40, 30)
         val inputWidth = 400
         val inputHeight = 300
@@ -180,24 +165,19 @@
                         .showBigPictureWhenCollapsed(true)
                 )
 
-        val expectedIconWidth = minOf(rightIconSize(), inputWidth)
-        val expectedIconHeight = minOf(rightIconSize() * inputHeight / inputWidth, inputHeight)
-
         // the promoted big picture is shown with enlarged aspect ratio
         checkIconView(builder.createContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width.toFloat())
                     .isWithin(1f)
                     .of((iconView.height * 4 / 3).toFloat())
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(40)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(30)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
         // because it doesn't target S, the icon is still shown in a square
         checkIconView(builder.createBigContentView()) { iconView ->
             assertThat(iconView.visibility).isEqualTo(View.VISIBLE)
             assertThat(iconView.width).isEqualTo(iconView.height)
-            assertThat(iconView.drawable.intrinsicWidth).isEqualTo(expectedIconWidth)
-            assertThat(iconView.drawable.intrinsicHeight).isEqualTo(expectedIconHeight)
+            assertThat(iconView.scaleType).isEqualTo(ImageView.ScaleType.CENTER_CROP)
         }
     }
 
@@ -314,17 +294,18 @@
         }
     }
 
-    private fun rightIconSize(): Int {
-        return mContext.resources.getDimensionPixelSize(
-                getAndroidRDimen("notification_right_icon_size"))
-    }
-
-    private fun isPlatformAutomotive(): Boolean {
-        return mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+    /**
+     * Assume that we're running on the platform that supports styled notifications.
+     *
+     * If the current platform does not support notification styles, skip this test without failure.
+     */
+    private fun skipIfPlatformDoesNotSupportNotificationStyles(): Boolean {
+        return mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
+                        mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)
     }
 
     companion object {
         val TAG = NotificationTemplateApi30Test::class.java.simpleName
         const val NOTIFICATION_CHANNEL_ID = "NotificationTemplateApi30Test"
     }
-}
\ No newline at end of file
+}
diff --git a/tests/tests/opengl/src/android/opengl/cts/MatrixTest.java b/tests/tests/opengl/src/android/opengl/cts/MatrixTest.java
new file mode 100644
index 0000000..574905b
--- /dev/null
+++ b/tests/tests/opengl/src/android/opengl/cts/MatrixTest.java
@@ -0,0 +1,606 @@
+/*
+ * 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.graphics.cts;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assert.fail;
+
+import android.opengl.Matrix;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class MatrixTest {
+
+    @Test
+    public void testMultiplyMM() {
+        // Assert legal arguments
+        float[] mat = new float[16];
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM(null, 0,  mat, 0,  mat, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( mat, 0, null, 0,  mat, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( mat, 0,  mat, 0, null, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( mat, 1,  mat, 0,  mat, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( mat, 0,  mat, 1,  mat, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( mat, 0,  mat, 0,  mat, 1));
+
+        float[] matResult = new float[16];
+        float[] matLhs = new float[16];
+        float[] matRhs = new float[16];
+
+        // Test that identity = identity * identity
+        Matrix.setIdentityM(matLhs, 0);
+        Matrix.setIdentityM(matRhs, 0);
+        Matrix.multiplyMM(matResult, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matResult, new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f});
+
+        // Test that checks mult of two diagonal matrices
+        matLhs = new float[] {
+            2.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 3.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 5.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 7.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 2.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 3.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 5.0f,
+        };
+        Matrix.multiplyMM(matResult, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matResult, new float[] {
+            2.0f, 0.0f,  0.0f,  0.0f,
+            0.0f, 6.0f,  0.0f,  0.0f,
+            0.0f, 0.0f, 15.0f,  0.0f,
+            0.0f, 0.0f,  0.0f, 35.0f});
+
+        // Tests that checks mult of two triangular matrices
+        matLhs = new float[] {
+            1.0f, 2.0f, 3.0f, 4.0f,
+            0.0f, 5.0f, 6.0f, 7.0f,
+            0.0f, 0.0f, 8.0f, 9.0f,
+            0.0f, 0.0f, 0.0f, 10.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            2.0f, 5.0f, 0.0f, 0.0f,
+            3.0f, 6.0f, 8.0f, 0.0f,
+            4.0f, 7.0f, 9.0f, 10.0f,
+        };
+        Matrix.multiplyMM(matResult, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matResult, new float[] {
+            1.0f,  2.0f,   3.0f,   4.0f,
+            2.0f, 29.0f,  36.0f,  43.0f,
+            3.0f, 36.0f, 109.0f, 126.0f,
+            4.0f, 43.0f, 126.0f, 246.0f});
+
+        matLhs = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            2.0f, 5.0f, 0.0f, 0.0f,
+            3.0f, 6.0f, 8.0f, 0.0f,
+            4.0f, 7.0f, 9.0f, 10.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 2.0f, 3.0f, 4.0f,
+            0.0f, 5.0f, 6.0f, 7.0f,
+            0.0f, 0.0f, 8.0f, 9.0f,
+            0.0f, 0.0f, 0.0f, 10.0f,
+        };
+        Matrix.multiplyMM(matResult, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matResult, new float[] {
+            30.0f,  56.0f,  60.0f,  40.0f,
+            56.0f, 110.0f, 111.0f,  70.0f,
+            60.0f, 111.0f, 145.0f,  90.0f,
+            40.0f,  70.0f,  90.0f, 100.0f});
+
+        // Test that checks mult of two filled matrices
+        matLhs = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 5.0f,  9.0f, 13.0f,
+            2.0f, 6.0f, 10.0f, 14.0f,
+            3.0f, 7.0f, 11.0f, 15.0f,
+            4.0f, 8.0f, 12.0f, 16.0f,
+        };
+        Matrix.multiplyMM(matResult, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matResult, new float[] {
+            103.0f, 400.0f,  798.0f, 1240.0f,
+            114.0f, 448.0f,  900.0f, 1408.0f,
+            125.0f, 496.0f, 1002.0f, 1576.0f,
+            136.0f, 544.0f, 1104.0f, 1744.0f});
+    }
+
+    @Test
+    public void testMultiplyMMInPlace() {
+        float[] matLhs = new float[16];
+        float[] matRhs = new float[16];
+
+        // Multiply RHS in place
+        matLhs = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 5.0f,  9.0f, 13.0f,
+            2.0f, 6.0f, 10.0f, 14.0f,
+            3.0f, 7.0f, 11.0f, 15.0f,
+            4.0f, 8.0f, 12.0f, 16.0f,
+        };
+        Matrix.multiplyMM(matRhs, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matRhs, new float[] {
+            103.0f, 400.0f,  798.0f, 1240.0f,
+            114.0f, 448.0f,  900.0f, 1408.0f,
+            125.0f, 496.0f, 1002.0f, 1576.0f,
+            136.0f, 544.0f, 1104.0f, 1744.0f});
+
+        // Multiply LHS in place
+        matLhs = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        matRhs = new float[] {
+            1.0f, 5.0f,  9.0f, 13.0f,
+            2.0f, 6.0f, 10.0f, 14.0f,
+            3.0f, 7.0f, 11.0f, 15.0f,
+            4.0f, 8.0f, 12.0f, 16.0f,
+        };
+        Matrix.multiplyMM(matLhs, 0, matLhs, 0, matRhs, 0);
+        verifyMatrix(matLhs, new float[] {
+            103.0f, 400.0f,  798.0f, 1240.0f,
+            114.0f, 448.0f,  900.0f, 1408.0f,
+            125.0f, 496.0f, 1002.0f, 1576.0f,
+            136.0f, 544.0f, 1104.0f, 1744.0f});
+
+        // Multiply both in place
+        float[] mat = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        Matrix.multiplyMM(mat, 0, mat, 0, mat, 0);
+        verifyMatrix(mat, new float[] {
+            257.0f,  960.0f, 1878.0f, 2880.0f,
+            298.0f, 1131.0f, 2229.0f, 3441.0f,
+            331.0f, 1272.0f, 2530.0f, 3912.0f,
+            367.0f, 1424.0f, 2842.0f, 4424.0f});
+    }
+
+    @Test
+    public void testMultiplyMV() {
+        // Assert legal arguments
+        float[] mat = new float[16];
+        float[] vec = new float[4];
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMV(null, 0,  mat, 0,  vec, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( vec, 0, null, 0,  vec, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( vec, 0,  mat, 0, null, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( vec, 1,  mat, 0,  vec, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( vec, 0,  mat, 1,  vec, 0));
+        assertThrows(IllegalArgumentException.class,
+                () -> Matrix.multiplyMM( vec, 0,  mat, 0,  vec, 1));
+
+        float[] vecResult = new float[4];
+        float[] matLhs = new float[16];
+        float[] vecRhs = new float[4];
+
+        // Test that vector = identity * vector
+        Matrix.setIdentityM(matLhs, 0);
+        vecRhs = new float[] {1.0f, 2.0f, 3.0f, 4.0f};
+        Matrix.multiplyMV(vecResult, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecResult, new float[] {1.0f, 2.0f, 3.0f, 4.0f});
+
+        // Test that checks mult of a diagonal matrix with an arbitrary vector
+        matLhs = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 2.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 3.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 5.0f,
+        };
+        vecRhs = new float[] {2.0f, 3.0f, 5.0f, 7.0f};
+        Matrix.multiplyMV(vecResult, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecResult, new float[] {2.0f, 6.0f, 15.0f, 35.0f});
+
+        // Tests that checks mult of a triangular matrix with an arbitrary vector
+        matLhs = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            2.0f, 5.0f, 0.0f, 0.0f,
+            3.0f, 6.0f, 8.0f, 0.0f,
+            4.0f, 7.0f, 9.0f, 10.0f,
+        };
+        vecRhs = new float[] {1.0f, 2.0f, 3.0f, 5.0f};
+        Matrix.multiplyMV(vecResult, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecResult, new float[] {34.0f, 63.0f, 69.0f, 50.0f});
+
+        matLhs = new float[] {
+            1.0f, 2.0f, 3.0f, 4.0f,
+            0.0f, 5.0f, 6.0f, 7.0f,
+            0.0f, 0.0f, 8.0f, 9.0f,
+            0.0f, 0.0f, 0.0f, 10.0f,
+        };
+        vecRhs = new float[] {1.0f, 2.0f, 3.0f, 5.0f};
+        Matrix.multiplyMV(vecResult, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecResult, new float[] {1.0f, 12.0f, 39.0f, 95.0f});
+
+        // Arbitrary filled matrix times arbitrary vector
+        matLhs = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        vecRhs = new float[] {2.0f, 3.0f, 5.0f, 7.0f};
+        Matrix.multiplyMV(vecResult, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecResult, new float[] {58.0f, 231.0f, 469.0f, 741.0f});
+    }
+
+    @Test
+    public void testMultiplyMVInPlace() {
+        float[] matLhs = new float[] {
+            1.0f,  7.0f, 19.0f, 37.0f,
+            2.0f, 11.0f, 23.0f, 41.0f,
+            3.0f, 13.0f, 29.0f, 43.0f,
+            5.0f, 17.0f, 31.0f, 47.0f,
+        };
+        float[] vecRhs = new float[] {2.0f, 3.0f, 5.0f, 7.0f};
+        Matrix.multiplyMV(vecRhs, 0, matLhs, 0, vecRhs, 0);
+        verifyVector(vecRhs, new float[] {58.0f, 231.0f, 469.0f, 741.0f});
+    }
+
+    @Test
+    public void testTransposeM() {
+        /*  matrices are stored in column-major order.
+         *
+         *  | 1 0 0  0 |
+         *  | 2 5 0  0 |
+         *  | 3 6 8  0 |
+         *  | 4 7 9 10 |
+         *
+         *  is initialized as
+         */
+        float[] mat = new float[] {
+            1.0f, 2.0f, 3.0f, 4.0f,
+            0.0f, 5.0f, 6.0f, 7.0f,
+            0.0f, 0.0f, 8.0f, 9.0f,
+            0.0f, 0.0f, 0.0f, 10.0f,
+        };
+
+        /*  the matrix once transposed should be:
+         *  | 1 2 3  4 |
+         *  | 0 5 6  7 |
+         *  | 0 0 8  9 |
+         *  | 0 0 0 10 |
+         *
+         *  and represented as
+         */
+        float[] matTranspose = new float[] {
+            1.0f, 0.0f, 0.0f,  0.0f,
+            2.0f, 5.0f, 0.0f,  0.0f,
+            3.0f, 6.0f, 8.0f,  0.0f,
+            4.0f, 7.0f, 9.0f, 10.0f,
+        };
+
+        float[] matResult = new float[16];
+        Matrix.transposeM(matResult, 0, mat, 0);
+        verifyMatrix(matResult, matTranspose);
+    }
+
+    @Test
+    public void testInvertM() {
+        // Inverse of identity is identity
+        float[] matIden = new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f};
+
+        float[] mat = matIden;
+        float[] matResult = new float[16];
+
+        Matrix.invertM(matResult, 0, mat, 0);
+        verifyMatrix(matResult, matIden);
+
+        // Inverse of arbitrary nonsingular matrix
+        mat = new float[] {
+             0.814f,  4.976f, -3.858f,  7.206f,
+             5.112f, -2.420f,  8.791f,  6.426f,
+             2.945f,  1.801f, -2.594f,  2.663f,
+            -5.003f, -4.188f,  3.340f, -1.235f
+        };
+        float[] matInv = new float[] {
+            -0.112707f, 0.033867f,  0.189963f, -0.071792f,
+             0.158030f, 0.011872f, -0.603463f, -0.317385f,
+             0.056107f, 0.076268f, -0.406444f, -0.152194f,
+             0.072418f, 0.028810f,  0.177650f,  0.145793f,
+        };
+        Matrix.invertM(matResult, 0, mat, 0);
+        verifyMatrix(matResult, matInv, 0.001f);
+    }
+
+    @Test
+    public void testLength() {
+        float zeroLength = Matrix.length(0.0f, 0.0f, 0.0f);
+        assertEquals(zeroLength, 0.0f, 0.001f);
+
+        float unitLength = Matrix.length(1.0f, 0.0f, 0.0f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+        unitLength = Matrix.length(0.0f, 1.0f, 0.0f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+        unitLength = Matrix.length(0.0f, 0.0f, 1.0f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+
+        unitLength = Matrix.length(0.707107f, 0.707107f, 0.0f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+        unitLength = Matrix.length(0.0f, 0.707107f, 0.707107f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+        unitLength = Matrix.length(0.707107f, 0.0f, 0.707107f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+
+        unitLength = Matrix.length(0.577350f, 0.577350f, 0.577350f);
+        assertEquals(unitLength, 1.0f, 0.001f);
+
+        float length = Matrix.length(1.0f, 1.0f, 1.0f);
+        assertEquals(length, 1.732051f, 0.001f);
+
+        length = Matrix.length(2.0f, 3.0f, 4.0f);
+        assertEquals(length, 5.385165f, 0.001f);
+    }
+
+    @Test
+    public void testSetIdentityM() {
+        float[] mat = new float[16];
+        Matrix.setIdentityM(mat, 0);
+        verifyMatrix(mat, new float[] {
+            1.0f, 0.0f, 0.0f, 0.0f,
+            0.0f, 1.0f, 0.0f, 0.0f,
+            0.0f, 0.0f, 1.0f, 0.0f,
+            0.0f, 0.0f, 0.0f, 1.0f});
+    }
+
+    @Test
+    public void testRotateM() {
+        float[] mat = new float[16];
+        float[] matResult = new float[16];
+
+        // Rotate around X
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setIdentityM(matResult, 0);
+        Matrix.rotateM(matResult, 0, mat, 0, 45.0f, 1.0f, 0.0f, 0.0f);
+        float[] matRotate = new float[] {
+            1.0f,  0.0f,    0.0f,    0.0f,
+            0.0f,  0.7071f, 0.7071f, 0.0f,
+            0.0f, -0.7071f, 0.7071f, 0.0f,
+            0.0f,  0.0f,    0.0f,    1.0f
+        };
+        verifyMatrix(matResult, matRotate, 0.001f);
+
+        // Rotate around Y
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setIdentityM(matResult, 0);
+        Matrix.rotateM(matResult, 0, mat, 0, 45.0f, 0.0f, 1.0f, 0.0f);
+        matRotate = new float[] {
+            0.7071f, 0.0f, -0.7071f, 0.0f,
+            0.0f,    1.0f,  0.0f,    0.0f,
+            0.7071f, 0.0f,  0.7071f, 0.0f,
+            0.0f,    0.0f,  0.0f,    1.0f
+        };
+        verifyMatrix(matResult, matRotate, 0.001f);
+
+        // Rotate around Z
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setIdentityM(matResult, 0);
+        Matrix.rotateM(matResult, 0, mat, 0, 45.0f, 0.0f, 0.0f, 1.0f);
+        matRotate = new float[] {
+             0.7071f, 0.7071f, 0.0f, 0.0f,
+            -0.7071f, 0.7071f, 0.0f, 0.0f,
+             0.0f,    0.0f,    1.0f, 0.0f,
+             0.0f,    0.0f,    0.0f, 1.0f
+        };
+        verifyMatrix(matResult, matRotate, 0.001f);
+    }
+
+    @Test
+    public void testRotateMInPlace() {
+        float[] mat = new float[16];
+
+        // Rotate around X
+        Matrix.setIdentityM(mat, 0);
+        Matrix.rotateM(mat, 0, 45.0f, 1.0f, 0.0f, 0.0f);
+        float[] matRotate = new float[] {
+            1.0f,  0.0f,    0.0f,    0.0f,
+            0.0f,  0.7071f, 0.7071f, 0.0f,
+            0.0f, -0.7071f, 0.7071f, 0.0f,
+            0.0f,  0.0f,    0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around Y
+        Matrix.setIdentityM(mat, 0);
+        Matrix.rotateM(mat, 0, 45.0f, 0.0f, 1.0f, 0.0f);
+        matRotate = new float[] {
+            0.7071f, 0.0f, -0.7071f, 0.0f,
+            0.0f,    1.0f,  0.0f,    0.0f,
+            0.7071f, 0.0f,  0.7071f, 0.0f,
+            0.0f,    0.0f,  0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around Z
+        Matrix.setIdentityM(mat, 0);
+        Matrix.rotateM(mat, 0, 45.0f, 0.0f, 0.0f, 1.0f);
+        matRotate = new float[] {
+             0.7071f, 0.7071f, 0.0f, 0.0f,
+            -0.7071f, 0.7071f, 0.0f, 0.0f,
+             0.0f,    0.0f,    1.0f, 0.0f,
+             0.0f,    0.0f,    0.0f, 1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+    }
+
+    @Test
+    public void testSetRotateM() {
+        float[] mat = new float[16];
+
+        // Rotate around X
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateM(mat, 0, 45.0f, 1.0f, 0.0f, 0.0f);
+        float[] matRotate = new float[] {
+            1.0f,  0.0f,    0.0f,    0.0f,
+            0.0f,  0.7071f, 0.7071f, 0.0f,
+            0.0f, -0.7071f, 0.7071f, 0.0f,
+            0.0f,  0.0f,    0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around Y
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateM(mat, 0, 45.0f, 0.0f, 1.0f, 0.0f);
+        matRotate = new float[] {
+            0.7071f, 0.0f, -0.7071f, 0.0f,
+            0.0f,    1.0f,  0.0f,    0.0f,
+            0.7071f, 0.0f,  0.7071f, 0.0f,
+            0.0f,    0.0f,  0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around Z
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateM(mat, 0, 45.0f, 0.0f, 0.0f, 1.0f);
+        matRotate = new float[] {
+             0.7071f, 0.7071f, 0.0f, 0.0f,
+            -0.7071f, 0.7071f, 0.0f, 0.0f,
+             0.0f,    0.0f,    1.0f, 0.0f,
+             0.0f,    0.0f,    0.0f, 1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+    }
+
+    @Test
+    public void testSetRotateEulerM() {
+        float[] mat = new float[16];
+
+        // Rotate around X
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateEulerM(mat, 0, 45.0f, 0.0f, 0.0f);
+        float[] matRotate = new float[] {
+            1.0f, 0.0f,     0.0f,    0.0f,
+            0.0f, 0.7071f, -0.7071f, 0.0f,
+            0.0f, 0.7071f,  0.7071f, 0.0f,
+            0.0f, 0.0f,     0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // setRotateEulerM is broken around the Y axis
+
+        // Rotate around Z
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateEulerM(mat, 0, 0.0f, 0.0f, 45.0f);
+        matRotate = new float[] {
+            0.7071f, -0.7071f, 0.0f, 0.0f,
+            0.7071f,  0.7071f, 0.0f, 0.0f,
+            0.0f,     0.0f,    1.0f, 0.0f,
+            0.0f,     0.0f,    0.0f, 1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+    }
+
+    @Test
+    public void testSetRotateEulerM2() {
+        float[] mat = new float[16];
+
+        // Rotate around X
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateEulerM2(mat, 0, 45.0f, 0.0f, 0.0f);
+        float[] matRotate = new float[] {
+            1.0f, 0.0f,     0.0f,    0.0f,
+            0.0f, 0.7071f, -0.7071f, 0.0f,
+            0.0f, 0.7071f,  0.7071f, 0.0f,
+            0.0f, 0.0f,     0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around y
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateEulerM2(mat, 0, 0.0f, 45.0f, 0.0f);
+        matRotate = new float[] {
+             0.7071f, 0.0f, 0.7071f, 0.0f,
+             0.0f,    1.0f, 0.0f,    0.0f,
+            -0.7071f, 0.0f, 0.7071f, 0.0f,
+             0.0f,    0.0f, 0.0f,    1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+
+        // Rotate around Z
+        Matrix.setIdentityM(mat, 0);
+        Matrix.setRotateEulerM2(mat, 0, 0.0f, 0.0f, 45.0f);
+        matRotate = new float[] {
+            0.7071f, -0.7071f, 0.0f, 0.0f,
+            0.7071f,  0.7071f, 0.0f, 0.0f,
+            0.0f,     0.0f,    1.0f, 0.0f,
+            0.0f,     0.0f,    0.0f, 1.0f
+        };
+        verifyMatrix(mat, matRotate, 0.001f);
+    }
+
+    private void verifyMatrix(float[] actual, float[] expected) {
+        if ((expected == null) || (expected.length != 16)) {
+            fail("Expected does not have 16 elements");
+        }
+        assertArrayEquals(actual, expected, 0.0f);
+    }
+
+    private void verifyMatrix(float[] actual, float[] expected, float delta) {
+        if ((expected == null) || (expected.length != 16)) {
+            fail("Expected does not have 16 elements");
+        }
+        assertArrayEquals(actual, expected, delta);
+    }
+
+    private void verifyVector(float[] actual, float[] expected) {
+        if ((expected == null) || (expected.length != 4)) {
+            fail("Expected does not have 4 elements");
+        }
+        assertArrayEquals(actual, expected, 0.0f);
+    }
+}
diff --git a/tests/tests/packageinstaller/OWNERS b/tests/tests/packageinstaller/OWNERS
new file mode 100644
index 0000000..a370d8a
--- /dev/null
+++ b/tests/tests/packageinstaller/OWNERS
@@ -0,0 +1,2 @@
+# Bug component: 36137
+include platform/frameworks/base:/PACKAGE_MANAGER_OWNERS
diff --git a/tests/tests/packageinstaller/install_appop_denied/src/android/packageinstaller/install_appop_denied/cts/ExternalSourcesTestAppOpDenied.kt b/tests/tests/packageinstaller/install_appop_denied/src/android/packageinstaller/install_appop_denied/cts/ExternalSourcesTestAppOpDenied.kt
index 4c95738..1717f69 100644
--- a/tests/tests/packageinstaller/install_appop_denied/src/android/packageinstaller/install_appop_denied/cts/ExternalSourcesTestAppOpDenied.kt
+++ b/tests/tests/packageinstaller/install_appop_denied/src/android/packageinstaller/install_appop_denied/cts/ExternalSourcesTestAppOpDenied.kt
@@ -34,7 +34,7 @@
 import org.junit.runner.RunWith
 
 private const val INSTALL_CONFIRM_TEXT_ID = "install_confirm_question"
-private const val ALERT_DIALOG_TITLE_ID = "android:id/alertTitle"
+private const val ALERT_DIALOG_MESSAGE_ID = "android:id/message"
 
 @RunWith(AndroidJUnit4::class)
 @MediumTest
@@ -50,7 +50,7 @@
     }
 
     private fun assertInstallBlocked(errorMessage: String) {
-        assertUiObject(errorMessage, By.res(ALERT_DIALOG_TITLE_ID))
+        assertUiObject(errorMessage, By.res(ALERT_DIALOG_MESSAGE_ID))
         uiDevice.pressBack()
     }
 
diff --git a/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java b/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java
index c2eae01..1b3f65e 100644
--- a/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/NfcPermissionTest.java
@@ -19,6 +19,7 @@
 import static org.junit.Assert.fail;
 import static org.junit.Assume.assumeTrue;
 
+import android.app.ActivityManager;
 import android.content.pm.PackageManager;
 import android.nfc.NfcAdapter;
 import android.nfc.NfcAdapter.ControllerAlwaysOnListener;
@@ -37,6 +38,7 @@
 public final class NfcPermissionTest {
 
     private NfcAdapter mNfcAdapter;
+    private static final String PKG_NAME = "com.android.packagename";
 
     private boolean supportsHardware() {
         final PackageManager pm = InstrumentationRegistry.getContext().getPackageManager();
@@ -152,6 +154,58 @@
         }
     }
 
+    /**
+     * Verifies that isTagIntentAppPreferenceSupported() requires Permission.
+     * <p>
+     * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+     */
+    @Test
+    @AppModeFull
+    public void testIsTagIntentAppPreferenceSupported() {
+        try {
+            mNfcAdapter.isTagIntentAppPreferenceSupported();
+            fail("mNfcAdapter.isTagIntentAppPreferenceSupported() did not throw SecurityException"
+                    + " as expected");
+        } catch (SecurityException se) {
+            // Expected Exception
+        }
+    }
+
+    /**
+     * Verifies that getTagIntentAppPreferenceForUser() requires Permission.
+     * <p>
+     * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+     */
+    @Test
+    @AppModeFull
+    public void testGetTagIntentAppPreferenceForUser() {
+        try {
+            mNfcAdapter.getTagIntentAppPreferenceForUser(ActivityManager.getCurrentUser());
+            fail("mNfcAdapter.getTagIntentAppPreferenceForUser() did not throw SecurityException"
+                    + " as expected");
+        } catch (SecurityException se) {
+            // Expected Exception
+        }
+    }
+
+    /**
+     * Verifies that setTagIntentAppPreferenceForUser() requires Permission.
+     * <p>
+     * Requires Permission: {@link android.Manifest.permission.WRITE_SECURE_SETTINGS}.
+     */
+    @Test
+    @AppModeFull
+    public void testSetTagIntentAppPreferenceForUser() {
+        try {
+            mNfcAdapter.setTagIntentAppPreferenceForUser(ActivityManager.getCurrentUser(),
+                    PKG_NAME, true);
+            fail("mNfcAdapter.setTagIntentAppPreferenceForUser() did not throw SecurityException"
+                    + " as expected");
+        } catch (SecurityException se) {
+            // Expected Exception
+        }
+    }
+
     private class SynchronousExecutor implements Executor {
         public void execute(Runnable r) {
             r.run();
diff --git a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
index dfefabc..f2e6aff 100755
--- a/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/BaseUsePermissionTest.kt
@@ -597,8 +597,8 @@
                 button.click()
             }
 
-            val shouldShowStorageWarning = !isWatch &&
-                SdkLevel.isAtLeastT() && targetSdk <= Build.VERSION_CODES.S_V2 &&
+            val shouldShowStorageWarning = SdkLevel.isAtLeastT() &&
+                targetSdk <= Build.VERSION_CODES.S_V2 &&
                 permission in MEDIA_PERMISSIONS
             if (shouldShowStorageWarning) {
                 click(By.res(ALERT_DIALOG_OK_BUTTON))
diff --git a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
index 2a57406..0f80633 100644
--- a/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
+++ b/tests/tests/permission3/src/android/permission3/cts/PermissionHistoryTest.kt
@@ -28,6 +28,7 @@
 import org.junit.After
 import org.junit.Assume.assumeFalse
 import org.junit.Before
+import org.junit.Ignore
 import org.junit.Test
 import java.util.regex.Pattern
 
@@ -122,6 +123,7 @@
     }
 
     @Test
+    @Ignore
     fun testToggleSystemApps() {
         // I had some hard time mocking a system app.
         // Hence here I am only testing if the toggle is there.
@@ -191,6 +193,7 @@
     }
 
     @Test
+    @Ignore
     fun testToggleFrom24HoursTo7DaysInTimeline() {
         // Auto doesn't support the 7 day view
         assumeFalse(isAutomotive)
@@ -219,6 +222,7 @@
     }
 
     @Test
+    @Ignore
     fun testMicrophoneTimelineWithOneApp() {
         openMicrophoneApp(INTENT_ACTION_1)
         waitFindObject(By.textContains(APP_LABEL_1))
@@ -242,6 +246,7 @@
     }
 
     @Test
+    @Ignore
     fun testCameraTimelineWithMultipleApps() {
         openMicrophoneApp(INTENT_ACTION_1)
         waitFindObject(By.textContains(APP_LABEL_1))
diff --git a/tests/tests/print/printTestUtilLib/Android.bp b/tests/tests/print/printTestUtilLib/Android.bp
index 9abb4ee..da85b79 100644
--- a/tests/tests/print/printTestUtilLib/Android.bp
+++ b/tests/tests/print/printTestUtilLib/Android.bp
@@ -24,7 +24,6 @@
     static_libs: [
         "mockito-target-minus-junit4",
         "ctstestrunner-axt",
-        "ub-uiautomator",
         "compatibility-device-util-axt",
         "androidx.test.rules",
         "platformprotosnano",
diff --git a/tests/tests/resolverservice/OWNERS b/tests/tests/resolverservice/OWNERS
index 978b1b4..87f734b 100644
--- a/tests/tests/resolverservice/OWNERS
+++ b/tests/tests/resolverservice/OWNERS
@@ -1,4 +1,2 @@
-# Bug component: 24950
-kanlig@google.com
-patb@google.com
-chiuwinson@google.com
\ No newline at end of file
+# Bug component: 36137
+include platform/frameworks/base:/PACKAGE_MANAGER_OWNERS
\ No newline at end of file
diff --git a/tests/tests/secure_element/access_control/OWNERS b/tests/tests/secure_element/access_control/OWNERS
index 6c4d2b3..f568bc3 100644
--- a/tests/tests/secure_element/access_control/OWNERS
+++ b/tests/tests/secure_element/access_control/OWNERS
@@ -2,4 +2,5 @@
 alisher@google.com
 jackcwyu@google.com
 georgekgchang@google.com
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
diff --git a/tests/tests/secure_element/omapi/OWNERS b/tests/tests/secure_element/omapi/OWNERS
index 6c4d2b3..f568bc3 100644
--- a/tests/tests/secure_element/omapi/OWNERS
+++ b/tests/tests/secure_element/omapi/OWNERS
@@ -2,4 +2,5 @@
 alisher@google.com
 jackcwyu@google.com
 georgekgchang@google.com
-zachoverflow@google.com
+sattiraju@google.com
+henrichataing@google.com
diff --git a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
index 9243595..41c9683 100644
--- a/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
+++ b/tests/tests/security/native/verified_boot/VerifiedBootTest.cpp
@@ -97,6 +97,7 @@
 // as current recommendations from NIST for hashing algorithms (SHA-256).
 // @CddTest = 9.10/C-1-5
 TEST(VerifiedBootTest, avbHashtreeNotUsingSha1) {
+    GTEST_SKIP() << "Skipping due to broken test. See b/264937051";
     if (isExemptFromAVBTests()) {
         GTEST_SKIP();
     }
diff --git a/tests/tests/settings/src/android/settings/cts/AppLocaleSettingsTest.java b/tests/tests/settings/src/android/settings/cts/AppLocaleSettingsTest.java
index 85f5e5d..5bd31a7 100644
--- a/tests/tests/settings/src/android/settings/cts/AppLocaleSettingsTest.java
+++ b/tests/tests/settings/src/android/settings/cts/AppLocaleSettingsTest.java
@@ -17,6 +17,7 @@
 package android.settings.cts;
 
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
 
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -39,6 +40,9 @@
 public class AppLocaleSettingsTest {
     @Test
     public void testAppLocaleSettingsExist() throws RemoteException {
+        assumeFalse(
+                "Skipping test: AppLocaleSettings is not supported in Wear OS",
+                isWatch());
         final Intent intent = new Intent(Settings.ACTION_APP_LOCALE_SETTINGS);
         intent.setData(Uri.parse("package:com.my.app"));
         final ResolveInfo ri = InstrumentationRegistry.getTargetContext()
@@ -46,4 +50,9 @@
                 intent, PackageManager.MATCH_DEFAULT_ONLY);
         assertTrue(ri != null);
     }
+
+    private boolean isWatch() {
+        return InstrumentationRegistry.getTargetContext()
+                .getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+    }
 }
diff --git a/tests/tests/slice/Android.bp b/tests/tests/slice/Android.bp
index 891a682..d3d75f8 100644
--- a/tests/tests/slice/Android.bp
+++ b/tests/tests/slice/Android.bp
@@ -34,7 +34,6 @@
         "metrics-helper-lib",
         "mockito-target-inline-minus-junit4",
         "platform-test-annotations",
-        "ub-uiautomator",
     ],
     compile_multilib: "both",
     jni_libs: [
diff --git a/tests/tests/syncmanager/Android.bp b/tests/tests/syncmanager/Android.bp
index 2042319..b3d9216 100644
--- a/tests/tests/syncmanager/Android.bp
+++ b/tests/tests/syncmanager/Android.bp
@@ -26,7 +26,6 @@
         "mockito-target-minus-junit4",
         "compatibility-device-util-axt",
         "ctstestrunner-axt",
-        "ub-uiautomator",
     ],
     libs: [
         "android.test.runner",
diff --git a/tests/tests/syncmanager/apps/Android.bp b/tests/tests/syncmanager/apps/Android.bp
index cbcfe29..0cb4cb8 100644
--- a/tests/tests/syncmanager/apps/Android.bp
+++ b/tests/tests/syncmanager/apps/Android.bp
@@ -26,7 +26,6 @@
         "androidx.legacy_legacy-support-v4",
         "mockito-target-minus-junit4",
         "compatibility-device-util-axt",
-        "ub-uiautomator",
     ],
     sdk_version: "test_current",
     // tag this module as a cts test artifact
@@ -48,7 +47,6 @@
         "androidx.legacy_legacy-support-v4",
         "mockito-target-minus-junit4",
         "compatibility-device-util-axt",
-        "ub-uiautomator",
     ],
     sdk_version: "test_current",
     // tag this module as a cts test artifact
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
index 3f6d02f..f969182 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/VisualVoicemailServiceTest.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.internal.telephony.SmsConstants.ENCODING_8BIT;
+
 import static junit.framework.Assert.assertNotNull;
 
 import static org.junit.Assert.assertEquals;
@@ -425,7 +427,7 @@
     /**
      * Setup the SMS filter with only the {@code clientPrefix}, and sends {@code text} to the
      * device. The SMS sent should not be written to the SMS provider. <p> If {@code expectVvmSms}
-     * is {@code true}, the SMS should be be caught by the SMS filter. The user should not receive
+     * is {@code true}, the SMS should be caught by the SMS filter. The user should not receive
      * the text, and the parsed result will be returned.* <p> If {@code expectVvmSms} is {@code
      * false}, the SMS should pass through the SMS filter. The user should receive the text, and
      * {@code null} be returned.
@@ -461,7 +463,7 @@
                     future.get(EVENT_NOT_RECEIVED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
                     throw new RuntimeException("Unexpected visual voicemail SMS received");
                 } catch (TimeoutException e) {
-                    // expected
+                    Log.i(TAG, "Expected TimeoutException" + e);
                     return null;
                 } catch (ExecutionException | InterruptedException e) {
                     throw new RuntimeException(e);
@@ -473,7 +475,6 @@
     @Nullable
     private VisualVoicemailSms getSmsFromData(VisualVoicemailSmsFilterSettings settings, short port,
             String text, boolean expectVvmSms) {
-
         mTelephonyManager.setVisualVoicemailSmsFilterSettings(settings);
 
         CompletableFuture<VisualVoicemailSms> future = new CompletableFuture<>();
@@ -497,7 +498,7 @@
                 future.get(EVENT_NOT_RECEIVED_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS);
                 throw new RuntimeException("Unexpected visual voicemail SMS received");
             } catch (TimeoutException e) {
-                // expected
+                Log.i(TAG, "Expected TimeoutException!" + e);
                 return null;
             } catch (ExecutionException | InterruptedException e) {
                 throw new RuntimeException(e);
@@ -529,16 +530,28 @@
             StringBuilder messageBody = new StringBuilder();
             CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder();
             for (SmsMessage message : messages) {
-                if (message.getMessageBody() != null) {
-                    messageBody.append(message.getMessageBody());
-                } else if (message.getUserData() != null) {
+                String body = message.getMessageBody();
+
+                if ((body == null || (message.is3gpp()
+                        && message.getReceivedEncodingType() == ENCODING_8BIT))
+                        && message.getUserData() != null) {
+                    Log.d(TAG, "onReceive decode using UTF-8");
+                    // Attempt to interpret the user data as UTF-8. UTF-8 string over data SMS using
+                    // 8BIT data coding scheme is our recommended way to send VVM SMS and is used in
+                    // CTS Tests. The OMTP visual voicemail specification does not specify the SMS
+                    // type and encoding.
                     ByteBuffer byteBuffer = ByteBuffer.wrap(message.getUserData());
                     try {
-                        messageBody.append(decoder.decode(byteBuffer).toString());
+                        body = decoder.decode(byteBuffer).toString();
                     } catch (CharacterCodingException e) {
+                        Log.e(TAG, "onReceive: got CharacterCodingException"
+                                + " when decoding with UTF-8, e = " + e);
                         return;
                     }
                 }
+                if (body != null) {
+                    messageBody.append(body);
+                }
             }
             if (!TextUtils.equals(mText, messageBody.toString())) {
                 return;
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
index 2256374..a268ea8558 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputManagerTest.java
@@ -20,6 +20,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningAppProcessInfo;
 import android.app.Instrumentation;
+import android.content.AttributionSource;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -29,7 +30,6 @@
 import android.media.AudioDeviceInfo;
 import android.media.AudioFormat;
 import android.media.AudioManager;
-import android.media.tv.cts.TvViewTest.MockCallback;
 import android.media.tv.TunedInfo;
 import android.media.tv.TvContentRating;
 import android.media.tv.TvContract;
@@ -43,6 +43,7 @@
 import android.media.tv.TvInputService;
 import android.media.tv.TvStreamConfig;
 import android.media.tv.TvView;
+import android.media.tv.cts.TvViewTest.MockCallback;
 import android.media.tv.tunerresourcemanager.TunerResourceManager;
 import android.net.Uri;
 import android.os.Binder;
@@ -52,11 +53,8 @@
 import android.os.Looper;
 import android.test.ActivityInstrumentationTestCase2;
 import android.tv.cts.R;
-
-import com.android.compatibility.common.util.PollingCheck;
-
 import androidx.test.InstrumentationRegistry;
-
+import com.android.compatibility.common.util.PollingCheck;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -64,7 +62,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.Executor;
-
 import org.xmlpull.v1.XmlPullParserException;
 
 /**
@@ -119,6 +116,7 @@
     };
 
     private String mStubId;
+    private Context mContext;
     private TvInputManager mManager;
     private LoggingCallback mCallback = new LoggingCallback();
     private TvInputInfo mStubTvInputInfo;
@@ -215,6 +213,7 @@
                 .adoptShellPermissionIdentity(BASE_SHELL_PERMISSIONS);
 
         mInstrumentation = getInstrumentation();
+        mContext = mInstrumentation.getTargetContext();
         mTvView = findTvViewById(R.id.tvview);
         mManager = (TvInputManager) mActivity.getSystemService(Context.TV_INPUT_SERVICE);
         mStubId = getInfoForClassName(
@@ -702,7 +701,7 @@
 
         Handler handler = new Handler(Looper.getMainLooper());
         final SessionCallback sessionCallback = new SessionCallback();
-        mManager.createSession(mStubId, sessionCallback, handler);
+        mManager.createSession(mStubId, mContext.getAttributionSource(), sessionCallback, handler);
         PollingCheck.waitFor(TIME_OUT_MS, () -> sessionCallback.getSession() != null);
         Session session = sessionCallback.getSession();
         String sessionId = StubTvInputService2.getSessionId();
@@ -743,7 +742,7 @@
 
         Handler handler = new Handler(Looper.getMainLooper());
         final SessionCallback sessionCallback = new SessionCallback();
-        mManager.createSession(mStubId, sessionCallback, handler);
+        mManager.createSession(mStubId, mContext.getAttributionSource(), sessionCallback, handler);
         PollingCheck.waitFor(TIME_OUT_MS, () -> sessionCallback.getSession() != null);
         Session session = sessionCallback.getSession();
         String sessionId = StubTvInputService2.getSessionId();
diff --git a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
index cd70293..e0b63b1 100644
--- a/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
+++ b/tests/tests/tv/src/android/media/tv/cts/TvInputServiceTest.java
@@ -17,13 +17,13 @@
 package android.media.tv.cts;
 
 import static androidx.test.ext.truth.view.MotionEventSubject.assertThat;
-
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Instrumentation;
+import android.content.AttributionSource;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.PlaybackParams;
@@ -50,30 +50,25 @@
 import android.view.SurfaceView;
 import android.view.View;
 import android.widget.LinearLayout;
-
 import androidx.test.core.app.ActivityScenario;
 import androidx.test.ext.junit.rules.ActivityScenarioRule;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
-
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.RequiredFeatureRule;
-
 import com.google.common.truth.Truth;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
 
 /**
  * Test {@link android.media.tv.TvInputService}.
@@ -104,6 +99,7 @@
 
     private TvRecordingClient mTvRecordingClient;
     private Instrumentation mInstrumentation;
+    private Context mContext;
     private TvInputManager mManager;
     private TvInputInfo mStubInfo;
     private TvInputInfo mFaultyStubInfo;
@@ -244,11 +240,10 @@
     public void setUp() {
         mInstrumentation = InstrumentationRegistry
                 .getInstrumentation();
-        mTvRecordingClient = new TvRecordingClient(mInstrumentation.getTargetContext(),
-                "TvInputServiceTest",
-                mRecordingCallback, null);
-        mManager = (TvInputManager) mInstrumentation.getTargetContext().getSystemService(
-                Context.TV_INPUT_SERVICE);
+        mContext = mInstrumentation.getTargetContext();
+        mTvRecordingClient =
+                new TvRecordingClient(mContext, "TvInputServiceTest", mRecordingCallback, null);
+        mManager = (TvInputManager) mContext.getSystemService(Context.TV_INPUT_SERVICE);
         for (TvInputInfo info : mManager.getTvInputList()) {
             if (info.getServiceInfo().name.equals(CountingTvInputService.class.getName())) {
                 mStubInfo = info;
@@ -1037,6 +1032,7 @@
     private CountingSession tune(Uri uri) {
         onTvView(tvView -> {
             tvView.setCallback(mCallback);
+            tvView.overrideTvAppAttributionSource(mContext.getAttributionSource());
             tvView.tune(mStubInfo.getId(), CHANNEL_0);
         });
         return waitForSessionCheck(session -> session.mTuneCount > 0);
@@ -1095,6 +1091,13 @@
         }
 
         @Override
+        public Session onCreateSession(
+                String inputId, String tvInputSessionId, AttributionSource tvAppAttributionSource) {
+            // todo: add AttributionSource equal check
+            return onCreateSession(inputId, tvInputSessionId);
+        }
+
+        @Override
         public RecordingSession onCreateRecordingSession(String inputId) {
             return onCreateRecordingSession(inputId, null);
         }
@@ -1169,7 +1172,6 @@
             public volatile Integer mOverlayViewSizeChangedHeight;
             public volatile Boolean mInteractiveAppNotificationEnabled;
 
-
             CountingSession(Context context, @Nullable String sessionId) {
 
                 super(context);
diff --git a/tests/tests/uiautomation/Android.bp b/tests/tests/uiautomation/Android.bp
index b4d80a8..b41d2fb 100644
--- a/tests/tests/uiautomation/Android.bp
+++ b/tests/tests/uiautomation/Android.bp
@@ -27,7 +27,6 @@
     static_libs: [
         "CtsAccessibilityCommon",
         "ctstestrunner-axt",
-        "ub-uiautomator",
     ],
     libs: ["android.test.base"],
     srcs: ["src/**/*.java"],
diff --git a/tests/tests/usb/src/android/usb/cts/UsbManagerApiTest.java b/tests/tests/usb/src/android/usb/cts/UsbManagerApiTest.java
index beac44d..edb8131 100644
--- a/tests/tests/usb/src/android/usb/cts/UsbManagerApiTest.java
+++ b/tests/tests/usb/src/android/usb/cts/UsbManagerApiTest.java
@@ -105,7 +105,9 @@
         // Should pass with permission.
         int version = mUsbManagerSys.getGadgetHalVersion();
         int usbBandwidth = mUsbManagerSys.getUsbBandwidthMbps();
-        if (version > UsbManager.GADGET_HAL_V1_1) {
+        if (version > UsbManager.GADGET_HAL_V1_2) {
+            Assert.assertTrue(usbBandwidth >= UsbManager.USB_DATA_TRANSFER_RATE_UNKNOWN);
+        } else if (version > UsbManager.GADGET_HAL_V1_1) {
             Assert.assertTrue(usbBandwidth > UsbManager.USB_DATA_TRANSFER_RATE_UNKNOWN);
         } else {
             Assert.assertEquals(usbBandwidth, UsbManager.USB_DATA_TRANSFER_RATE_UNKNOWN);
diff --git a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
index 68c4a77..20f7283 100644
--- a/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
+++ b/tests/tests/view/src/android/view/cts/ViewUnbufferedTest.java
@@ -246,7 +246,7 @@
         }
 
         mReceivedEvents.add(new ReceivedEvent(event.getEventTime(), event.getAction(),
-                (int) event.getX(), (int) event.getY(), event.getSource()));
+                Math.round(event.getX()), Math.round(event.getY()), event.getSource()));
 
         // Always return true to make sure the event has been handled.
         return true;
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index 82ee4d3..f7edd76 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -21,6 +21,7 @@
 
 import static com.google.common.truth.Truth.assertWithMessage;
 
+import static org.junit.Assume.assumeFalse;
 import static org.junit.Assume.assumeTrue;
 
 import android.Manifest;
@@ -114,6 +115,10 @@
                     DeviceConfig.getProperty(DeviceConfig.NAMESPACE_PRIVACY, INDICATORS_FLAG);
             Log.v(TAG, "setup(): mOriginalIndicatorsState=" + mOriginalIndicatorsState);
         });
+
+        // TODO(http://b/259941077): Remove once privacy indicators are implemented.
+        assumeFalse("Privacy indicators not supported", isWatch());
+
         setIndicatorsEnabledState(Boolean.toString(true));
         // Wait for any privacy indicator to disappear to avoid the test becoming flaky.
         SystemClock.sleep(INDICATOR_DISMISS_TIMEOUT);
@@ -286,4 +291,9 @@
         PackageManager pm = mContext.getPackageManager();
         return pm.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
     }
+
+    private boolean isWatch() {
+        PackageManager pm = mContext.getPackageManager();
+        return pm.hasSystemFeature(PackageManager.FEATURE_WATCH);
+    }
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/PacProcessorTest.java b/tests/tests/webkit/src/android/webkit/cts/PacProcessorTest.java
index ee6f11f..26f699d 100644
--- a/tests/tests/webkit/src/android/webkit/cts/PacProcessorTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/PacProcessorTest.java
@@ -20,11 +20,13 @@
 import android.net.ConnectivityManager;
 import android.net.Network;
 import android.webkit.PacProcessor;
+import com.android.compatibility.common.util.NullWebViewUtils;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.After;
 import org.junit.Assert;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -79,6 +81,7 @@
      */
     @Test
     public void testCreatePacProcessor() throws Throwable {
+        Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
         mProcess.run(TestCreatePacProcessor.class);
     }
 
@@ -97,6 +100,7 @@
      */
     @Test
     public void testDefaultNetworkIsNull() throws Throwable {
+        Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
         mProcess.run(TestDefaultNetworkIsNull.class);
     }
 
@@ -131,6 +135,7 @@
      */
     @Test
     public void testSetNetwork() throws Throwable {
+        Assume.assumeTrue("WebView is not available", NullWebViewUtils.isWebViewAvailable());
         mProcess.run(TestSetNetwork.class);
     }
 }
diff --git a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
index dd10626..01d866a 100644
--- a/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
+++ b/tests/tests/webkit/src/android/webkit/cts/WebViewClientTest.java
@@ -38,6 +38,8 @@
 import android.webkit.cts.WebViewSyncLoader.WaitForLoadedClient;
 import android.util.Pair;
 
+import androidx.test.filters.FlakyTest;
+
 import com.android.compatibility.common.util.NullWebViewUtils;
 import com.android.compatibility.common.util.PollingCheck;
 import com.google.common.util.concurrent.SettableFuture;
@@ -141,6 +143,7 @@
 
     // Verify shouldoverrideurlloading called on webview called via onCreateWindow
     // TODO(sgurun) upstream this test to Aw.
+    @FlakyTest(bugId = 253448914)
     public void testShouldOverrideUrlLoadingOnCreateWindow() throws Exception {
         if (!NullWebViewUtils.isWebViewAvailable()) {
             return;
diff --git a/tests/tests/widget/res/layout-round/edittext_layout.xml b/tests/tests/widget/res/layout-round/edittext_layout.xml
index 4f7f62b..1213d65 100644
--- a/tests/tests/widget/res/layout-round/edittext_layout.xml
+++ b/tests/tests/widget/res/layout-round/edittext_layout.xml
@@ -56,5 +56,12 @@
             android:autoSizeTextType="uniform"
             android:textSize="50dp"
             android:autoSizeStepGranularity="2dp" />
+
+        <EditText
+            android:id="@+id/edittext_conversion_suggestion"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:inputType="textEnableTextConversionSuggestions"
+            android:text="@string/edit_text" />
     </LinearLayout>
 </ScrollView>
diff --git a/tests/tests/widget/res/values/themes.xml b/tests/tests/widget/res/values/themes.xml
index bbce31f..938452e 100644
--- a/tests/tests/widget/res/values/themes.xml
+++ b/tests/tests/widget/res/values/themes.xml
@@ -24,4 +24,8 @@
         <item name="themeColor">@color/remoteviews_theme_color</item>
         <item name="themeString">@string/remoteviews_theme_string</item>
     </style>
-</resources>
\ No newline at end of file
+
+    <style name="HorizontalScrollViewCtsActivityTheme" parent="@android:style/Theme.DeviceDefault">
+        <item name="android:windowSwipeToDismiss">false</item>
+    </style>
+</resources>
diff --git a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
index 96d8279..489aa54 100644
--- a/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
+++ b/tests/tests/widget/src/android/widget/cts/HorizontalScrollViewCtsActivity.java
@@ -24,6 +24,7 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+        setTheme(R.style.HorizontalScrollViewCtsActivityTheme);
         setContentView(R.layout.horizontal_scrollview);
     }
 }
diff --git a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
index 9908432..db698fd 100644
--- a/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
+++ b/tests/video/src/android/video/cts/VideoEncoderDecoderTest.java
@@ -146,6 +146,7 @@
     private int mWidth;
     private int mHeight;
     private String mEncoderName;
+    private int mMaxBFrames;
 
     private class TestConfig {
         public boolean mTestPixels = true;
@@ -201,26 +202,29 @@
     }
 
     /** run performance test. */
-    private void perf(String mimeType, int w, int h, String encoder) throws Exception {
-        doTest(mimeType, w, h, true /* isPerf */, encoder);
+    private void perf(String mimeType, int w, int h, String encoder, int maxBFrames)
+            throws Exception {
+        doTest(mimeType, w, h, true /* isPerf */, encoder, maxBFrames);
     }
 
     /** run quality test. */
-    private void qual(String mimeType, int w, int h, String encoder) throws Exception {
-        doTest(mimeType, w, h, false /* isPerf */, encoder);
+    private void qual(String mimeType, int w, int h, String encoder, int maxBFrames)
+            throws Exception {
+        doTest(mimeType, w, h, false /* isPerf */, encoder, maxBFrames);
     }
 
     /** run quality test but do not report error. */
-    private void qual(String mimeType, int w, int h, String encoder, double margin)
+    private void qual(String mimeType, int w, int h, String encoder, int maxBFrames, double margin)
             throws Exception {
         mRmsErrorMargin = margin;
-        doTest(mimeType, w, h, false /* isPerf */, encoder);
+        doTest(mimeType, w, h, false /* isPerf */, encoder, maxBFrames);
     }
 
     static void prepareParamsList(List<Object[]> testParams, String mediaType, int[] widths,
             int[] heights) {
         final Type[] types = {Type.Qual, Type.Perf};
         String[] encoderNames = MediaUtils.getEncoderNamesForMime(mediaType);
+        int[] maxBFrames = {0, 2};
         for (Type type : types) {
             for (int i = 0; i < widths.length; i++) {
                 MediaFormat format =
@@ -230,8 +234,16 @@
                         continue;
                     }
                     if (MediaUtils.supports(encoder, format)) {
-                        testParams.add(
-                                new Object[]{type, mediaType, widths[i], heights[i], encoder});
+                        for (int maxBFrame : maxBFrames) {
+                            if (!mediaType.equals(MediaFormat.MIMETYPE_VIDEO_AVC)
+                                    && !mediaType.equals(MediaFormat.MIMETYPE_VIDEO_HEVC)
+                                    && maxBFrame != 0) {
+                                continue;
+                            }
+                            testParams.add(
+                                    new Object[]{type, mediaType, widths[i], heights[i], encoder,
+                                            maxBFrame});
+                        }
                         break;
                     }
                 }
@@ -239,7 +251,7 @@
         }
     }
 
-    @Parameterized.Parameters(name = "{1}_{4}_{0}_{2}x{3}")
+    @Parameterized.Parameters(name = "{1}_{4}_{0}_{2}x{3}_{5}")
     public static Collection<Object[]> input() throws IOException {
         final List<Object[]> testParams = new ArrayList<>();
         final String[] mediaTypes = {AVC, HEVC, MPEG2, MPEG4, VP8, VP9, H263};
@@ -278,12 +290,13 @@
     }
 
     public VideoEncoderDecoderTest(Type type, String mediaType, int width, int height,
-            String encoderName) {
+            String encoderName, int maxBFrames) {
         this.mType = type;
         this.mMediaType = mediaType;
         this.mWidth = width;
         this.mHeight = height;
         this.mEncoderName = encoderName;
+        this.mMaxBFrames = maxBFrames;
     }
 
     @Test
@@ -291,12 +304,12 @@
         if (mType == Type.Qual) {
             if (mMediaType == H263 && (mWidth == 704
                     || mWidth == 1408)) {
-                qual(mMediaType, mWidth, mHeight, mEncoderName, 25);
+                qual(mMediaType, mWidth, mHeight, mEncoderName, mMaxBFrames, 25);
             } else {
-                qual(mMediaType, mWidth, mHeight, mEncoderName);
+                qual(mMediaType, mWidth, mHeight, mEncoderName, mMaxBFrames);
             }
         } else {
-            perf(mMediaType, mWidth, mHeight, mEncoderName);
+            perf(mMediaType, mWidth, mHeight, mEncoderName, mMaxBFrames);
         }
     }
 
@@ -351,8 +364,8 @@
         }
     }
 
-    private void doTest(String mimeType, int w, int h, boolean isPerf, String encoderName)
-            throws Exception {
+    private void doTest(String mimeType, int w, int h, boolean isPerf, String encoderName,
+            int maxBFrames) throws Exception {
         if (TestArgs.shouldSkipMediaType(mimeType)) {
             return;
         }
@@ -433,6 +446,7 @@
             format.setInteger(MediaFormat.KEY_FRAME_RATE, infoEnc.mFps);
             mFrameRate = infoEnc.mFps;
             format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, KEY_I_FRAME_INTERVAL);
+            format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, maxBFrames);
 
             RunResult encodingResult =
                 runEncoder(encoderName, format, mTestConfig.mTotalFrames, i);
@@ -504,7 +518,7 @@
             // allow improvements in mainline-updated google-supplied software codecs.
             boolean fasterIsOk =  mUpdatedSwCodec & encoderName.startsWith("c2.android.");
             String error = MediaPerfUtils.verifyAchievableFrameRates(
-                    encoderName, mimeType, w, h, fasterIsOk, measuredFps);
+                    encoderName, mimeType, w, h, fasterIsOk, maxBFrames > 0, measuredFps);
             // Performance numbers only make sense on real devices, so skip on non-real devices
             //
             // Also ignore verification on non-preferred ABIs due to the possibility of
diff --git a/tests/videocodec/AndroidManifest.xml b/tests/videocodec/AndroidManifest.xml
index 6edbe66..14e2f31 100644
--- a/tests/videocodec/AndroidManifest.xml
+++ b/tests/videocodec/AndroidManifest.xml
@@ -23,6 +23,7 @@
 
     <application
         android:requestLegacyExternalStorage="true"
+        android:largeHeap="true"
         android:usesCleartextTraffic="true">
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/videocodec/src/android/videocodec/cts/VideoEncoderMinMaxTest.java b/tests/videocodec/src/android/videocodec/cts/VideoEncoderMinMaxTest.java
new file mode 100644
index 0000000..f59a450
--- /dev/null
+++ b/tests/videocodec/src/android/videocodec/cts/VideoEncoderMinMaxTest.java
@@ -0,0 +1,299 @@
+/*
+ * 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.videocodec.cts;
+
+import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_CBR;
+import static android.media.MediaCodecInfo.EncoderCapabilities.BITRATE_MODE_VBR;
+import static android.mediav2.common.cts.CodecTestBase.ComponentClass.HARDWARE;
+import static android.mediav2.common.cts.CodecTestBase.MEDIA_CODEC_LIST_REGULAR;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.media.MediaCodecInfo;
+import android.media.MediaFormat;
+import android.mediav2.common.cts.CompareStreams;
+import android.mediav2.common.cts.EncoderConfigParams;
+import android.mediav2.common.cts.RawResource;
+
+import com.android.compatibility.common.util.ApiTest;
+
+import org.junit.AfterClass;
+import org.junit.Assume;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * 1. MinMaxResolutionsTest should query the ranges of supported width and height using
+ * MediaCodecInfo.VideoCapabilities, test the min resolution and the max resolution of the encoder.
+ * <p></p>
+ * Test Params:
+ * <p>Input resolution = min/max</p>
+ * <p>Number of frames = 30</p>
+ * <p>FrameRate = 30</p>
+ * <p>Target bitrate = 10 Mbps</p>
+ * <p>Bitrate mode = VBR</p>
+ * <p>MaxBFrames = 0/1</p>
+ * <p>Codec type = AVC/HEVC</p>
+ * <p>IFrameInterval = 0/1 second</p>
+ * <p></p>
+ *
+ * 2. MinMaxBitrateTest should query the range of the supported bitrates, and test min/max of them
+ * <p></p>
+ * Test Params:
+ * <p>Input resolution = 720p30fps</p>
+ * <p>Number of frames = 300</p>
+ * <p>FrameRate = 30</p>
+ * <p>Target bitrate = min/max</p>
+ * <p>Bitrate mode = CBR/VBR</p>
+ * <p>MaxBFrames = 0/1</p>
+ * <p>Codec type = AVC/HEVC</p>
+ * <p>IFrameInterval = 0/1 second</p>
+ * <p></p>
+ *
+ * 3. MinMaxFrameRatesTest should query the range of the supported frame rates, and test min/max
+ * of them.
+ * Test Params:
+ * <p>Input resolution = 720p</p>
+ * <p>Number of frames = 300</p>
+ * <p>FrameRate = min/max</p>
+ * <p>Target bitrate = 5Mbps</p>
+ * <p>Bitrate mode = CBR/VBR</p>
+ * <p>MaxBFrames = 0/1</p>
+ * <p>Codec type = AVC/HEVC</p>
+ * <p>IFrameInterval = 0/1 second</p>
+ * <p></p>
+ */
+@RunWith(Parameterized.class)
+public class VideoEncoderMinMaxTest extends VideoEncoderValidationTestBase {
+    private static final float MIN_ACCEPTABLE_QUALITY = 20.0f;  // psnr in dB
+    private static final int FRAME_LIMIT = 300;
+    private static final int FRAME_RATE = 30;
+    private static final int BIT_RATE = 10000000;
+    private static final List<Object[]> exhaustiveArgsList = new ArrayList<>();
+    private static final HashMap<String, RawResource> RES_YUV_MAP = new HashMap<>();
+
+    @BeforeClass
+    public static void decodeResourcesToYuv() {
+        ArrayList<CompressedResource> resources = new ArrayList<>();
+        for (Object[] arg : exhaustiveArgsList) {
+            resources.add((CompressedResource) arg[2]);
+        }
+        decodeStreamsToYuv(resources, RES_YUV_MAP);
+    }
+
+    @AfterClass
+    public static void cleanUpResources() {
+        for (RawResource res : RES_YUV_MAP.values()) {
+            new File(res.mFileName).delete();
+        }
+    }
+
+    private static EncoderConfigParams getVideoEncoderCfgParams(String mediaType, int width,
+            int height, int maxBFrames, int intraInterval) {
+        return new EncoderConfigParams.Builder(mediaType)
+                .setWidth(width)
+                .setHeight(height)
+                .setBitRate(BIT_RATE)
+                .setMaxBFrames(maxBFrames)
+                .setKeyFrameInterval(intraInterval)
+                .setFrameRate(FRAME_RATE)
+                .build();
+    }
+
+    private static void addParams(int width, int height, CompressedResource res) {
+        final String[] mediaTypes = new String[]{MediaFormat.MIMETYPE_VIDEO_AVC,
+                MediaFormat.MIMETYPE_VIDEO_HEVC};
+        final int[] maxBFramesPerSubGop = new int[]{0, 1};
+        final int[] intraIntervals = new int[]{0, 1};
+        for (String mediaType : mediaTypes) {
+            for (int maxBFrames : maxBFramesPerSubGop) {
+                for (int intraInterval : intraIntervals) {
+                    // mediaType, cfg, resource file
+                    exhaustiveArgsList.add(new Object[]{mediaType,
+                            getVideoEncoderCfgParams(mediaType, width, height, maxBFrames,
+                                    intraInterval), res});
+                }
+            }
+        }
+    }
+
+    private static List<Object> applyMinMaxRanges(MediaCodecInfo.CodecCapabilities caps,
+            Object cfgObject) throws CloneNotSupportedException {
+        int minWidth = caps.getVideoCapabilities().getSupportedWidths().getLower();
+        int maxWidth = caps.getVideoCapabilities().getSupportedWidths().getUpper();
+        int minHeight = caps.getVideoCapabilities().getSupportedHeights().getLower();
+        int maxHeight = caps.getVideoCapabilities().getSupportedHeights().getUpper();
+
+        int minBitRate = caps.getVideoCapabilities().getBitrateRange().getLower();
+        int maxBitRate = caps.getVideoCapabilities().getBitrateRange().getUpper();
+
+        int minFrameRate = caps.getVideoCapabilities().getSupportedFrameRates().getLower();
+        int maxFrameRate = caps.getVideoCapabilities().getSupportedFrameRates().getUpper();
+
+        List<Object> cfgObjects = new ArrayList<>();
+        EncoderConfigParams cfgParam = (EncoderConfigParams) cfgObject;
+
+        final int[] bitRateModes = new int[]{BITRATE_MODE_CBR, BITRATE_MODE_VBR};
+        for (int bitRateMode : bitRateModes) {
+            cfgObjects.add((Object) cfgParam.getBuilder()
+                    .setWidth(minWidth)
+                    .setHeight(minHeight)
+                    .setBitRate(minBitRate)
+                    .setBitRateMode(bitRateMode)
+                    .build());
+
+            cfgObjects.add((Object) cfgParam.getBuilder()
+                    .setWidth(maxWidth)
+                    .setHeight(maxHeight)
+                    .setBitRate(maxBitRate)
+                    .setBitRateMode(bitRateMode)
+                    .build());
+
+            cfgObjects.add((Object) cfgParam.getBuilder()
+                    .setFrameRate(minFrameRate)
+                    .setBitRate(5000000)
+                    .setBitRateMode(bitRateMode)
+                    .build());
+
+            cfgObjects.add((Object) cfgParam.getBuilder()
+                    .setFrameRate(maxFrameRate)
+                    .setBitRate(5000000)
+                    .setBitRateMode(bitRateMode)
+                    .build());
+        }
+
+        cfgObjects.add((Object) cfgParam.getBuilder()
+                .setWidth(minWidth)
+                .setHeight(maxHeight)
+                .setBitRateMode(BITRATE_MODE_VBR)
+                .build());
+
+        cfgObjects.add((Object) cfgParam.getBuilder()
+                .setWidth(maxWidth)
+                .setHeight(minHeight)
+                .setBitRateMode(BITRATE_MODE_VBR)
+                .build());
+
+        return cfgObjects;
+    }
+
+    private static List<Object> getMinMaxRangeCfgObjects(Object codecName, Object mediaType,
+            Object cfgObject) throws CloneNotSupportedException {
+        for (MediaCodecInfo codecInfo : MEDIA_CODEC_LIST_REGULAR.getCodecInfos()) {
+            for (String type : codecInfo.getSupportedTypes()) {
+                if (codecName.equals(codecInfo.getName()) && mediaType.equals(type)) {
+                    MediaCodecInfo.CodecCapabilities caps =
+                            codecInfo.getCapabilitiesForType(type);
+                    return applyMinMaxRanges(caps, cfgObject);
+                }
+            }
+        }
+        return null;
+    }
+
+    private static Collection<Object[]> updateParamList(Collection<Object[]> paramList)
+            throws CloneNotSupportedException {
+        Collection<Object[]> newParamList = new ArrayList<>();
+        for (Object[] arg : paramList) {
+            List<Object> cfgObjects = getMinMaxRangeCfgObjects(arg[0], arg[1], arg[2]);
+            for (Object obj : cfgObjects) {
+                Object[] argUpdate = new Object[arg.length + 1];
+                System.arraycopy(arg, 0, argUpdate, 0, arg.length);
+                argUpdate[2] = obj;
+                EncoderConfigParams cfgVar = (EncoderConfigParams) obj;
+                String label = String.format("%dkbps_%dx%d_%dfps_maxb-%d_%s_i-dist-%d",
+                        cfgVar.mBitRate / 1000, cfgVar.mWidth, cfgVar.mHeight, cfgVar.mFrameRate,
+                        cfgVar.mMaxBFrames, bitRateModeToString(cfgVar.mBitRateMode),
+                        (int) cfgVar.mKeyFrameInterval);
+                argUpdate[arg.length - 1] = label;
+                argUpdate[arg.length] = paramToString(argUpdate);
+                newParamList.add(argUpdate);
+            }
+        }
+        return newParamList;
+    }
+
+    @Parameterized.Parameters(name = "{index}({0}_{1}_{4})")
+    public static Collection<Object[]> input() throws CloneNotSupportedException {
+        addParams(1280, 720, BIRTHDAY_FULLHD_LANDSCAPE);
+        return updateParamList(prepareParamList(exhaustiveArgsList, true, false, true, false,
+                HARDWARE));
+    }
+
+    public VideoEncoderMinMaxTest(String encoder, String mediaType, EncoderConfigParams cfgParams,
+            CompressedResource res, @SuppressWarnings("unused") String testLabel,
+            String allTestParams) {
+        super(encoder, mediaType, cfgParams, res, allTestParams);
+    }
+
+    @Before
+    public void setUp() {
+        mIsLoopBack = true;
+    }
+
+    @ApiTest(apis = {"android.media.MediaFormat#KEY_WIDTH",
+            "android.media.MediaFormat#KEY_HEIGHT",
+            "android.media.MediaFormat#KEY_BITRATE",
+            "android.media.MediaFormat#KEY_FRAME_RATE"})
+    @Test
+    public void testMinMaxSupport() throws IOException, InterruptedException {
+        MediaFormat format = mEncCfgParams[0].getFormat();
+        ArrayList<MediaFormat> formats = new ArrayList<>();
+        formats.add(format);
+        Assume.assumeTrue("Encoder: " + mCodecName + " doesn't support format: " + format,
+                areFormatsSupported(mCodecName, mMime, formats));
+        RawResource res = RES_YUV_MAP.getOrDefault(mCRes.uniqueLabel(), null);
+        assertNotNull("no raw resource found for testing config : " + mEncCfgParams[0]
+                + mTestConfig + mTestEnv, res);
+        encodeToMemory(mCodecName, mEncCfgParams[0], res, FRAME_LIMIT, true, true);
+        CompareStreams cs = null;
+        StringBuilder msg = new StringBuilder();
+        boolean isOk = true;
+        try {
+            cs = new CompareStreams(res, mMime, mMuxedOutputFile, true, mIsLoopBack);
+            final double[] minPSNR = cs.getMinimumPSNR();
+            for (int i = 0; i < minPSNR.length; i++) {
+                if (minPSNR[i] < MIN_ACCEPTABLE_QUALITY) {
+                    msg.append(String.format("For %d plane, minPSNR is less than tolerance"
+                                    + " threshold, Got %f, Threshold %f", i, minPSNR[i],
+                            MIN_ACCEPTABLE_QUALITY));
+                    isOk = false;
+                    break;
+                }
+            }
+        } finally {
+            if (cs != null) cs.cleanUp();
+        }
+        new File(mMuxedOutputFile).delete();
+        assertEquals("encoder did not encode the requested number of frames \n"
+                + mTestConfig + mTestEnv, FRAME_LIMIT, mOutputCount);
+        assertTrue("Encountered frames with PSNR less than configured threshold "
+                + MIN_ACCEPTABLE_QUALITY + "dB \n" + msg + mTestConfig + mTestEnv, isOk);
+    }
+}
diff --git a/tests/videocodec/src/android/videocodec/cts/VideoEncoderValidationTestBase.java b/tests/videocodec/src/android/videocodec/cts/VideoEncoderValidationTestBase.java
index 044a311..676127c 100644
--- a/tests/videocodec/src/android/videocodec/cts/VideoEncoderValidationTestBase.java
+++ b/tests/videocodec/src/android/videocodec/cts/VideoEncoderValidationTestBase.java
@@ -27,9 +27,9 @@
 import android.media.MediaCodec;
 import android.media.MediaFormat;
 import android.mediav2.common.cts.BitStreamUtils;
+import android.mediav2.common.cts.CodecEncoderTestBase;
 import android.mediav2.common.cts.DecodeStreamToYuv;
 import android.mediav2.common.cts.EncoderConfigParams;
-import android.mediav2.common.cts.EncoderTestBase;
 import android.mediav2.common.cts.RawResource;
 import android.util.Log;
 
@@ -47,7 +47,7 @@
 /**
  * Wrapper class for handling and testing video encoder components.
  */
-public class VideoEncoderValidationTestBase extends EncoderTestBase {
+public class VideoEncoderValidationTestBase extends CodecEncoderTestBase {
     private static final String LOG_TAG = VideoEncoderValidationTestBase.class.getSimpleName();
     private static final String MEDIA_DIR = WorkDir.getMediaDirString();
 
diff --git a/tests/wallpapereffectsgeneration/OWNERS b/tests/wallpapereffectsgeneration/OWNERS
index 39cdd55..ab3d604 100644
--- a/tests/wallpapereffectsgeneration/OWNERS
+++ b/tests/wallpapereffectsgeneration/OWNERS
@@ -1,3 +1,4 @@
+# Bug component: 168740
 susharon@google.com
 shanh@google.com
 huiwu@google.com
diff --git a/tools/cts-tradefed/Android.bp b/tools/cts-tradefed/Android.bp
index 0811941..e50b6b4 100644
--- a/tools/cts-tradefed/Android.bp
+++ b/tools/cts-tradefed/Android.bp
@@ -34,7 +34,7 @@
     wrapper: "etc/cts-tradefed",
     short_name: "CTS",
     full_name: "Compatibility Test Suite",
-    version: "13_r3",
+    version: "13_r4",
     static_libs: ["cts-tradefed-harness"],
     required: ["compatibility-host-util"],
 }
diff --git a/tools/cts-tradefed/res/config/cts-known-failures.xml b/tools/cts-tradefed/res/config/cts-known-failures.xml
index 34feac2..a37929d 100644
--- a/tools/cts-tradefed/res/config/cts-known-failures.xml
+++ b/tools/cts-tradefed/res/config/cts-known-failures.xml
@@ -308,4 +308,10 @@
 
     <!-- b/260037367 -->
     <option name="compatibility:exclude-filter" value="odsign_e2e_tests com.android.tests.odsign.CompOsSigningHostTest" />
-</configuration>
+
+    <!-- b/264824229 -->
+    <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_data" />
+    <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_match" />
+    <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_mismatch" />
+    <option name="compatibility:exclude-filter" value="CtsTelephonyTestCases android.telephony.cts.VisualVoicemailServiceTest#testFilter_port_anydata" />
+</configuration>
\ No newline at end of file
diff --git a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
index 306737f..1ccf352 100644
--- a/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
+++ b/tools/cts-tradefed/tests/src/com/android/compatibility/common/tradefed/presubmit/ValidateTestsAbi.java
@@ -103,11 +103,20 @@
         BINARY_EXCEPTIONS.add("sepolicy-analyze");
         BINARY_EXCEPTIONS.add("avbtool");
         BINARY_EXCEPTIONS.add("img2simg");
+        BINARY_EXCEPTIONS.add("initrd_bootconfig");
         BINARY_EXCEPTIONS.add("lpmake");
         BINARY_EXCEPTIONS.add("lpunpack");
         BINARY_EXCEPTIONS.add("mk_payload");
         BINARY_EXCEPTIONS.add("sign_virt_apex");
         BINARY_EXCEPTIONS.add("simg2img");
+
+        /**
+         * These binaries are testing components with no 32-bit variant, which
+         * means their dependent libraries by default will not have 32-bit
+         * variants on the device, and which gain no additional testing coverage
+         * by forcing those variants to be available.
+         */
+        BINARY_EXCEPTIONS.add("CtsInitTestCases");
     }
 
     private static final String BINARY_EXCEPTIONS_REGEX [] = {