Merge "CameraITS: Show CameraITS app in Folded state." into android13-tests-dev
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/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index e8994f5..6d11ea5 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"/>
 
@@ -2085,7 +2085,7 @@
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
             </intent-filter>
             <meta-data android:name="test_category" android:value="@string/test_category_hardware" />
-            <meta-data android:name="test_required_features" android:value="android.hardware.nfc" />
+            <meta-data android:name="test_applicable_features" android:value="android.hardware.nfc:android.hardware.nfc.hce" />
             <meta-data android:name="display_mode"
                        android:value="multi_display_mode" />
             <meta-data android:name="NonApiTest" android:value="Helper class. List test activities" />
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 9b4641f..a0dd36c 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -5465,6 +5465,8 @@
     <string name="audio_general_pass">PASS</string>
     <string name="audio_general_fail">FAIL</string>
     <string name="audio_general_not_tested">Not Tested</string>
+    <string name="audio_general_not_required">Please Test If Supported</string>
+    <string name="audio_general_required">Required</string>
 
     <string name="audio_general_Input">Input</string>
     <string name="audio_general_Output">Output</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
index 413734b..2e5046a 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioLoopbackLatencyActivity.java
@@ -86,6 +86,8 @@
     String mPassString;
     String mFailString;
     String mNotTestedString;
+    String mNotRequiredString;
+    String mRequiredString;
 
     // These flags determine the maximum allowed latency
     private boolean mClaimsProAudio;
@@ -281,6 +283,7 @@
         // Speaker/Mic Path
         mTestSpecs[TESTROUTE_DEVICE] =
                 new TestSpec(TESTROUTE_DEVICE, CONFIDENCE_THRESHOLD_AMBIENT);
+        mTestSpecs[TESTROUTE_DEVICE].mRouteAvailable = true;    // Always
 
         // Analog Jack Path
         mTestSpecs[TESTROUTE_ANALOG_JACK] =
@@ -296,7 +299,9 @@
         mNoString = resources.getString(R.string.audio_general_no);
         mPassString = resources.getString(R.string.audio_general_pass);
         mFailString = resources.getString(R.string.audio_general_fail);
-        mNotTestedString = resources.getString(R.string.audio_general_not_tested) + " ";
+        mNotTestedString = resources.getString(R.string.audio_general_not_tested);
+        mNotRequiredString = resources.getString(R.string.audio_general_not_required);
+        mRequiredString = resources.getString(R.string.audio_general_required);
 
         // Pro Audio
         ((TextView) findViewById(R.id.audio_loopback_pro_audio)).setText(
@@ -342,6 +347,8 @@
         connectLoopbackUI();
 
         enableStartButtons(true);
+
+        handleTestCompletion(false);
     }
 
     //
@@ -632,14 +639,14 @@
 
             mTestPhase++;
             if (mTestPhase >= NUM_TEST_PHASES) {
-                handleTestCompletion();
+                handleTestCompletion(true);
             } else {
                 startTestPhase();
             }
         }
     }
 
-    private void handleTestCompletion() {
+    private void handleTestCompletion(boolean showResult) {
         TestSpec testSpec = mTestSpecs[mTestRoute];
         testSpec.handleTestCompletion();
 
@@ -657,13 +664,13 @@
         LoopbackLatencyRequirements requirements = new LoopbackLatencyRequirements();
         boolean pass = isReportLogOkToPass()
                 && requirements.evaluate(mClaimsProAudio,
-                Build.VERSION.MEDIA_PERFORMANCE_CLASS,
-                mTestSpecs[TESTROUTE_DEVICE].isMeasurementValid()
-                        ? mTestSpecs[TESTROUTE_DEVICE].mMeanLatencyMS : 0.0,
-                mTestSpecs[TESTROUTE_ANALOG_JACK].isMeasurementValid()
-                        ? mTestSpecs[TESTROUTE_ANALOG_JACK].mMeanLatencyMS :  0.0,
-                mTestSpecs[TESTROUTE_USB].isMeasurementValid()
-                        ? mTestSpecs[TESTROUTE_USB].mMeanLatencyMS : 0.0);
+                        Build.VERSION.MEDIA_PERFORMANCE_CLASS,
+                        mTestSpecs[TESTROUTE_DEVICE].isMeasurementValid()
+                                ? mTestSpecs[TESTROUTE_DEVICE].mMeanLatencyMS : 0.0,
+                        mTestSpecs[TESTROUTE_ANALOG_JACK].isMeasurementValid()
+                                ? mTestSpecs[TESTROUTE_ANALOG_JACK].mMeanLatencyMS :  0.0,
+                        mTestSpecs[TESTROUTE_USB].isMeasurementValid()
+                                ? mTestSpecs[TESTROUTE_USB].mMeanLatencyMS : 0.0);
 
         getPassButton().setEnabled(pass);
 
@@ -672,6 +679,9 @@
             sb.append(getResources().getString(R.string.audio_general_reportlogtest) + "\n");
         }
         sb.append(requirements.getResultsString());
+        if (showResult) {
+            sb.append("\n" + (pass ? mPassString : mFailString));
+        }
         mTestStatusText.setText(sb.toString());
 
         showWait(false);
@@ -694,16 +704,16 @@
                 case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_OPEN_ERROR:
                     Log.v(TAG,"got message native rec can't start!!");
                     mTestStatusText.setText("Test Error opening streams.");
-                    handleTestCompletion();
+                    handleTestCompletion(true);
                     break;
                 case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_ERROR:
                     Log.v(TAG,"got message native rec can't start!!");
                     mTestStatusText.setText("Test Error while recording.");
-                    handleTestCompletion();
+                    handleTestCompletion(true);
                     break;
                 case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_REC_COMPLETE_ERRORS:
                     mTestStatusText.setText("Test FAILED due to errors.");
-                    handleTestCompletion();
+                    handleTestCompletion(true);
                     break;
                 case NativeAnalyzerThread.NATIVE_AUDIO_THREAD_MESSAGE_ANALYZING:
                     mTestStatusText.setText(String.format("[phase: %d] - Analyzing ...",
@@ -753,6 +763,10 @@
                                        double deviceLatency,
                                        double analogLatency,
                                        double usbLatency) {
+
+            // Required to test the Mic/Speaker path
+            boolean internalPathRun = deviceLatency != LATENCY_NOT_MEASURED;
+
             // All devices must be under the basic limit.
             boolean basicPass = checkLatency(deviceLatency, LATENCY_BASIC)
                     && checkLatency(analogLatency, LATENCY_BASIC)
@@ -783,7 +797,11 @@
             }
 
             boolean pass =
-                    basicPass && mpcAtLeastOnePass && proAudioAtLeastOnePass && proAudioLimitsPass;
+                    internalPathRun &&
+                    basicPass &&
+                    mpcAtLeastOnePass &&
+                    proAudioAtLeastOnePass &&
+                    proAudioLimitsPass;
 
             // Build the results explanation
             StringBuilder sb = new StringBuilder();
@@ -796,19 +814,17 @@
             }
             sb.append(" ");
 
-            sb.append("Speaker/Mic: " + (deviceLatency != LATENCY_NOT_MEASURED
+            sb.append("\nSpeaker/Mic: " + (deviceLatency != LATENCY_NOT_MEASURED
                     ? String.format("%.2fms ", deviceLatency)
-                    : mNotTestedString));
-            sb.append("Headset: " + (analogLatency != LATENCY_NOT_MEASURED
+                    : (mNotTestedString + " - " + mRequiredString)));
+            sb.append("\nHeadset: " + (analogLatency != LATENCY_NOT_MEASURED
                     ? String.format("%.2fms ", analogLatency)
-                    : mNotTestedString));
-            sb.append("USB: " + (usbLatency != LATENCY_NOT_MEASURED
+                    : (mNotTestedString + " - " + mNotRequiredString)));
+            sb.append("\nUSB: " + (usbLatency != LATENCY_NOT_MEASURED
                     ? String.format("%.2fms ", usbLatency)
-                    : mNotTestedString));
+                    : (mNotTestedString + " - " + mNotRequiredString)));
 
             sb.append(supplementalText);
-
-            sb.append(pass ? mPassString : mFailString);
             mResultsString = sb.toString();
 
             return pass;
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/ItsTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/camera/its/ItsTestActivity.java
index 692538a..9f43e85 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
@@ -392,7 +392,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/nfc/NfcTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcTestActivity.java
index 4cc0da8..a0eb2ea 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/nfc/NfcTestActivity.java
@@ -54,19 +54,23 @@
 
         ArrayTestListAdapter adapter = new ArrayTestListAdapter(this);
 
-        adapter.add(TestListItem.newCategory(this, R.string.nfc_tag_verification));
-        adapter.add(TestListItem.newTest(this, R.string.nfc_ndef,
-                NDEF_ID, getTagIntent(Ndef.class), null));
-        if (getPackageManager().hasSystemFeature(FEATURE_NFC_MIFARE)) {
-            adapter.add(TestListItem.newTest(this, R.string.nfc_mifare_ultralight,
-                    MIFARE_ULTRALIGHT_ID, getTagIntent(MifareUltralight.class), null));
+        if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
+            adapter.add(TestListItem.newCategory(this, R.string.nfc_tag_verification));
+            adapter.add(TestListItem.newTest(this, R.string.nfc_ndef,
+                    NDEF_ID, getTagIntent(Ndef.class), null));
+            if (getPackageManager().hasSystemFeature(FEATURE_NFC_MIFARE)) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_mifare_ultralight,
+                        MIFARE_ULTRALIGHT_ID, getTagIntent(MifareUltralight.class), null));
+            }
         }
 
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION)) {
             adapter.add(TestListItem.newCategory(this, R.string.nfc_hce));
-            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_reader_tests,
-                    HceReaderTestActivity.class.getName(),
-                    new Intent(this, HceReaderTestActivity.class), null));
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_hce_reader_tests,
+                        HceReaderTestActivity.class.getName(),
+                        new Intent(this, HceReaderTestActivity.class), null));
+            }
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_emulator_tests,
                     HceEmulatorTestActivity.class.getName(),
                     new Intent(this, HceEmulatorTestActivity.class), null));
@@ -74,9 +78,11 @@
 
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_HOST_CARD_EMULATION_NFCF)) {
             adapter.add(TestListItem.newCategory(this, R.string.nfc_hce_f));
-            adapter.add(TestListItem.newTest(this, R.string.nfc_hce_f_reader_tests,
-                    HceFReaderTestActivity.class.getName(),
-                    new Intent(this, HceFReaderTestActivity.class), null));
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_hce_f_reader_tests,
+                        HceFReaderTestActivity.class.getName(),
+                        new Intent(this, HceFReaderTestActivity.class), null));
+            }
             adapter.add(TestListItem.newTest(this, R.string.nfc_hce_f_emulator_tests,
                     HceFEmulatorTestActivity.class.getName(),
                     new Intent(this, HceFEmulatorTestActivity.class), null));
@@ -84,9 +90,11 @@
 
         if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC_OFF_HOST_CARD_EMULATION_UICC)) {
             adapter.add(TestListItem.newCategory(this, R.string.nfc_offhost_uicc));
-            adapter.add(TestListItem.newTest(this, R.string.nfc_offhost_uicc_reader_tests,
-                    OffhostUiccReaderTestActivity.class.getName(),
-                    new Intent(this, OffhostUiccReaderTestActivity.class), null));
+            if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
+                adapter.add(TestListItem.newTest(this, R.string.nfc_offhost_uicc_reader_tests,
+                        OffhostUiccReaderTestActivity.class.getName(),
+                        new Intent(this, OffhostUiccReaderTestActivity.class), null));
+            }
             adapter.add(TestListItem.newTest(this, R.string.nfc_offhost_uicc_emulator_tests,
                     OffhostUiccEmulatorTestActivity.class.getName(),
                     new Intent(this, OffhostUiccEmulatorTestActivity.class), null));
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/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
index 4f68e8b..6b3bbe0 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/tv/TvInputDiscoveryTestActivity.java
@@ -47,7 +47,6 @@
     private View mTuneToChannelItem;
     private View mVerifyTuneItem;
     private View mVerifyOverlayViewItem;
-    private View mVerifyGlobalSearchItem;
     private View mVerifyOverlayViewSizeChanged;
     private View mGoToEpgItem;
     private View mVerifyEpgItem;
@@ -57,7 +56,6 @@
     private View mSupportThirdPartyInputNoItem;
     private boolean mTuneVerified;
     private boolean mOverlayViewVerified;
-    private boolean mGlobalSearchVerified;
     private boolean mOverlayViewSizeChangedVerified;
 
     @Override
@@ -130,7 +128,7 @@
                     goToNextState(postTarget, failCallback);
                 }
             });
-            verifyGlobalSearch(postTarget, failCallback);
+            // TODO: handle GLOBAL_SEARCH permission and verify global search
             startActivity(TV_APP_INTENT);
         } else if (containsButton(mGoToEpgItem, v)) {
             startActivity(EPG_INTENT);
@@ -168,8 +166,6 @@
                 R.string.tv_input_discover_test_verify_overlay_view);
         mVerifyOverlayViewSizeChanged = createAndAttachAutoItem(
                 R.string.tv_input_discover_test_verify_size_changed);
-        mVerifyGlobalSearchItem = createAndAttachAutoItem(
-                R.string.tv_input_discover_test_verify_global_search);
         mGoToEpgItem = createAndAttachUserItem(R.string.tv_input_discover_test_go_to_epg,
                 R.string.tv_launch_epg, this);
         mVerifyEpgItem = createAndAttachUserItem(R.string.tv_input_discover_test_verify_epg,
@@ -187,38 +183,9 @@
     }
 
     private void goToNextState(View postTarget, Runnable failCallback) {
-        if (mTuneVerified && mOverlayViewVerified
-                && mGlobalSearchVerified && mOverlayViewSizeChangedVerified) {
+        if (mTuneVerified && mOverlayViewVerified && mOverlayViewSizeChangedVerified) {
             postTarget.removeCallbacks(failCallback);
             setButtonEnabled(mGoToEpgItem, true);
         }
     }
-
-    private void verifyGlobalSearch(final View postTarget, final Runnable failCallback) {
-        new AsyncTask<Void, Void, Boolean>() {
-            @Override
-            protected Boolean doInBackground(Void... params) {
-                Context context = TvInputDiscoveryTestActivity.this;
-                for (SearchableInfo info : SearchUtil.getSearchableInfos(context)) {
-                    if (SearchUtil.verifySearchResult(context, info,
-                            MockTvInputSetupActivity.CHANNEL_NAME,
-                            MockTvInputSetupActivity.PROGRAM_TITLE)
-                            && SearchUtil.verifySearchResult(context, info,
-                                    MockTvInputSetupActivity.PROGRAM_TITLE,
-                                    MockTvInputSetupActivity.PROGRAM_TITLE)) {
-                        return true;
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            protected void onPostExecute(Boolean result) {
-                super.onPostExecute(result);
-                setPassState(mVerifyGlobalSearchItem, result);
-                mGlobalSearchVerified = result;
-                goToNextState(postTarget, failCallback);
-            }
-        }.execute();
-    }
 }
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 862fcbe..19d2c75 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/common/HdmiCecGeneralProtocolTest.java
@@ -27,11 +27,15 @@
 
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 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 {
@@ -51,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);
@@ -85,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 {
@@ -105,6 +120,16 @@
      * ignore the last byte of the parameter and treat it as {@code <UCP>[KEYCODE_DPAD_UP]}
      */
     @Test
+    @Ignore("b/259002142, b/264510905")
+    /**
+     * TODO: b/259002142, b/264510905
+     *
+     * 1. implement the behavior that the current test is testing
+     * (i.e. ignore additional parameters in <User Control Pressed> messages)
+     *
+     * 2. implement the tests as they are proposed by the HDMI forum and validate that they are
+     * passing with the current implementation of the behavior
+     */
     public void cect_hf_ignoreAdditionalParams() throws Exception {
         setCec20();
         RemoteControlPassthrough.checkUserControlPressAndReleaseWithAdditionalParams(
diff --git a/hostsidetests/media/Android.bp b/hostsidetests/media/Android.bp
index 7f174a2..02d666c 100644
--- a/hostsidetests/media/Android.bp
+++ b/hostsidetests/media/Android.bp
@@ -41,6 +41,11 @@
         "cts-host-utils",
         "cts-statsd-atom-host-test-utils",
     ],
+    data: [
+        ":CtsMediaMetricsHostTestApp",
+        ":CtsMediaSessionHostTestApp",
+        ":CtsMediaSessionTestHelper",
+    ],
 }
 
 filegroup {
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/src/android/media/metrics/cts/MediaMetricsAtomTests.java b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
index fe2ac25..77cc851 100644
--- a/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
+++ b/hostsidetests/media/src/android/media/metrics/cts/MediaMetricsAtomTests.java
@@ -24,23 +24,38 @@
 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.device.ITestDevice;
+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.DeviceTestCase;
 import com.android.tradefed.testtype.IBuildReceiver;
 
 import com.google.common.truth.Correspondence;
 
 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;
 
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
 public class MediaMetricsAtomTests extends DeviceTestCase implements IBuildReceiver {
+
+    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";
@@ -75,9 +90,9 @@
     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());
@@ -93,9 +108,9 @@
     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());
@@ -112,9 +127,9 @@
     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());
@@ -131,9 +146,9 @@
     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());
@@ -154,9 +169,9 @@
     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());
@@ -177,9 +192,9 @@
     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());
@@ -206,9 +221,9 @@
     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());
@@ -233,9 +248,9 @@
     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());
@@ -262,9 +277,9 @@
     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());
@@ -292,9 +307,9 @@
     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());
@@ -311,8 +326,9 @@
     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());
@@ -329,9 +345,9 @@
     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());
@@ -364,8 +380,9 @@
     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());
@@ -400,8 +417,9 @@
     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());
@@ -411,8 +429,9 @@
     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());
@@ -422,8 +441,9 @@
     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());
@@ -433,9 +453,9 @@
     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());
@@ -445,8 +465,9 @@
     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());
@@ -456,11 +477,14 @@
     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,
@@ -474,13 +498,14 @@
     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);
@@ -511,12 +536,14 @@
     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);
@@ -533,13 +560,14 @@
     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 +623,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);
@@ -650,17 +679,86 @@
                 "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/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/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 ddbb4aa..7cc1576 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/JobThrottlingTest.java
@@ -18,23 +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.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;
@@ -44,9 +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.wifi.WifiManager;
 import android.os.PowerManager;
 import android.os.SystemClock;
 import android.os.Temperature;
@@ -64,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.
  */
@@ -106,22 +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;
-    private boolean mInitialAirplaneModeState;
     private String mInitialDisplayTimeout;
     private String mInitialRestrictedBucketEnabled;
-    private String mInitialLocationMode;
     private String mInitialBatteryStatsConstants;
     private boolean mAutomotiveDevice;
     private boolean mLeanbackOnly;
@@ -154,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);
@@ -171,11 +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();
-        mInitialAirplaneModeState = isAirplaneModeOn();
         mInitialRestrictedBucketEnabled = Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.ENABLE_RESTRICTED_BUCKET);
         mInitialBatteryStatsConstants = Settings.Global.getString(mContext.getContentResolver(),
@@ -183,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);
@@ -603,7 +573,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);
@@ -634,9 +604,9 @@
         assumeTrue("app standby not enabled", mAppStandbyEnabled);
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
-
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeFalse("not testable, since ethernet is connected", hasEthernetConnection());
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
 
@@ -644,7 +614,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);
@@ -673,9 +643,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));
@@ -978,8 +947,8 @@
         assumeFalse("not testable in automotive device", mAutomotiveDevice);
         assumeFalse("not testable in leanback device", mLeanbackOnly);
 
-        assumeTrue(mHasWifi);
-        ensureSavedWifiNetwork(mWifiManager);
+        assumeTrue(mNetworkingHelper.hasWifiFeature());
+        mNetworkingHelper.ensureSavedWifiNetwork();
 
         setRestrictedBucketEnabled(true);
         setTestPackageStandbyBucket(Bucket.RESTRICTED);
@@ -989,9 +958,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);
@@ -1004,13 +972,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);
@@ -1195,23 +1162,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);
@@ -1367,110 +1323,8 @@
                 + " -u " + UserHandle.myUserId() + " " + TEST_APP_PACKAGE + " " + mTestJobId);
     }
 
-    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);
+    private boolean hasEthernetConnection() {
+        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/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
index 79d4b2b..197fbd5 100644
--- a/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
+++ b/tests/PhotoPicker/src/android/photopicker/cts/PhotoPickerBaseTest.java
@@ -20,13 +20,12 @@
 import android.app.Instrumentation;
 import android.content.Context;
 import android.content.Intent;
-import android.provider.DeviceConfig;
+import android.content.pm.PackageManager;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.uiautomator.UiDevice;
 
-import com.android.modules.utils.build.SdkLevel;
-
+import org.junit.Assume;
 import org.junit.Before;
 
 /**
@@ -42,6 +41,8 @@
 
     @Before
     public void setUp() throws Exception {
+        Assume.assumeTrue(isHardwareSupported());
+
         final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
         mDevice = UiDevice.getInstance(inst);
 
@@ -63,4 +64,15 @@
         mActivity.clearResult();
         mDevice.waitForIdle();
     }
+
+    private static boolean isHardwareSupported() {
+        final Instrumentation inst = InstrumentationRegistry.getInstrumentation();
+        // These UI tests are not optimised for Watches, TVs, Auto;
+        // IoT devices do not have a UI to run these UI tests
+        PackageManager pm = inst.getContext().getPackageManager();
+        return !pm.hasSystemFeature(pm.FEATURE_EMBEDDED)
+                && !pm.hasSystemFeature(pm.FEATURE_WATCH)
+                && !pm.hasSystemFeature(pm.FEATURE_LEANBACK)
+                && !pm.hasSystemFeature(pm.FEATURE_AUTOMOTIVE);
+    }
 }
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/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
index 49dfb93..3461e6a 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityWindowReportingTest.java
@@ -16,6 +16,7 @@
 
 package android.accessibilityservice.cts;
 
+import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWaitForAll;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangeTypesAndWindowTitle;
 import static android.accessibilityservice.cts.utils.AccessibilityEventFilterUtils.filterWindowsChangedWithChangeTypes;
 import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.findWindowByTitle;
@@ -431,15 +432,21 @@
             intent.setAction(NotTouchableWindowTestActivity.ADD_WINDOW);
 
             try {
-                // Waits for the not-touchable activity is covered by the untrusted window.
-                sUiAutomation.executeAndWaitForEvent(() -> sInstrumentation.runOnMainSync(
-                        () -> sInstrumentation.getContext().sendBroadcast(intent)),
-                        (event) -> {
-                            final AccessibilityWindowInfo notTouchableWindow =
-                                    findWindowByTitle(sUiAutomation,
-                                            NotTouchableWindowTestActivity.TITLE);
-                            return notTouchableWindow == null;
-                        }, TIMEOUT_ASYNC_PROCESSING);
+                // Waits for two events, whose order is nondeterministic:
+                //  (1) the test activity is covered by the untrusted non-touchable window.
+                //  (2) the untrusted non-touchable window is added.
+                sendIntentAndWaitForEvent(intent,
+                        filterWaitForAll(
+                                event -> {
+                                    final AccessibilityWindowInfo coveredWindow =
+                                            findWindowByTitle(sUiAutomation,
+                                                    NotTouchableWindowTestActivity.TITLE);
+                                    return coveredWindow == null;
+                                },
+                                filterWindowsChangeTypesAndWindowTitle(sUiAutomation,
+                                        WINDOWS_CHANGE_ADDED,
+                                        NotTouchableWindowTestActivity.NON_TOUCHABLE_WINDOW_TITLE)
+                        ));
             } finally {
                 intent.setAction(NotTouchableWindowTestActivity.REMOVE_WINDOW);
                 sendIntentAndWaitForEvent(intent,
@@ -468,7 +475,7 @@
                     sendIntentAndWaitForEvent(intent,
                             filterWindowsChangeTypesAndWindowTitle(sUiAutomation,
                                     WINDOWS_CHANGE_ADDED,
-                                    NotTouchableWindowTestActivity.NON_TOUCHABLE_WINDOW_TITLE.toString())
+                                    NotTouchableWindowTestActivity.NON_TOUCHABLE_WINDOW_TITLE)
                     );
                 }, Manifest.permission.INTERNAL_SYSTEM_WINDOW);
 
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NotTouchableWindowTestActivity.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NotTouchableWindowTestActivity.java
index 9aca75f..e2bd5c2 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NotTouchableWindowTestActivity.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/activities/NotTouchableWindowTestActivity.java
@@ -71,9 +71,9 @@
 
     private BroadcastReceiver mBroadcastReceiver = new CommandReceiver();
 
-    public static final CharSequence TITLE =
+    public static final String TITLE =
             "NotTouchableWindowTestActivity";
-    public static final CharSequence NON_TOUCHABLE_WINDOW_TITLE =
+    public static final String NON_TOUCHABLE_WINDOW_TITLE =
             "android.accessibilityservice.cts.activities.NON_TOUCHABLE_WINDOW_TITLE";
 
     public static final String ADD_WINDOW =
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
index 57d1103..01e484e 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/AccessibilityEventFilterUtils.java
@@ -27,6 +27,8 @@
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeMatcher;
 
+import java.util.Arrays;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.function.BiPredicate;
 
@@ -79,6 +81,25 @@
                 new WindowIdMatcher(windowId))::matches;
     }
 
+    /**
+     * Creates an {@link AccessibilityEventFilter} that returns {@code true} once all the given
+     * filters return {@code true} for any event.
+     * Each given filters are invoked on every AccessibilityEvent until it returns {@code true}.
+     * After all filters return {@code true} once, the created filter returns {@code true} forever.
+     */
+    public static AccessibilityEventFilter filterWaitForAll(AccessibilityEventFilter... filters) {
+        return new AccessibilityEventFilter() {
+            private final List<AccessibilityEventFilter> mUnresolved =
+                    new LinkedList<>(Arrays.asList(filters));
+
+            @Override
+            public boolean accept(AccessibilityEvent event) {
+                mUnresolved.removeIf(filter -> filter.accept(event));
+                return mUnresolved.isEmpty();
+            }
+        };
+    }
+
     public static class AccessibilityEventTypeMatcher extends TypeSafeMatcher<AccessibilityEvent> {
         private int mType;
 
diff --git a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
index 9409b25..ed7c72a 100644
--- a/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerProcessStateTest.java
@@ -79,10 +79,14 @@
 import com.android.compatibility.common.util.AmMonitor;
 import com.android.compatibility.common.util.SystemUtil;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
@@ -190,6 +194,22 @@
         }
     }
 
+    @After
+    public void tearDown() throws Exception {
+        // Stop all the packages
+        final List<String> allPackageNames = new ArrayList<>();
+        allPackageNames.addAll(Arrays.asList(PACKAGE_NAMES));
+        allPackageNames.add(SIMPLE_PACKAGE_NAME);
+        allPackageNames.add(CANT_SAVE_STATE_1_PACKAGE_NAME);
+        allPackageNames.add(CANT_SAVE_STATE_2_PACKAGE_NAME);
+        final ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        for (final String pkgName : allPackageNames) {
+            SystemUtil.runWithShellPermissionIdentity(() -> {
+                am.forceStopPackage(pkgName);
+            });
+        }
+    }
+
     /**
      * Drain the ordered broadcast queue, it'll be useful when the test runs in secondary user
      * which is just created prior to the testing, the ordered broadcast queue could be clogged.
diff --git a/tests/app/src/android/app/cts/NotificationTemplateTest.kt b/tests/app/src/android/app/cts/NotificationTemplateTest.kt
index ff8bf56..f7edaf7 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,8 +35,8 @@
 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
+import org.junit.Assume
 
 class NotificationTemplateTest : NotificationTemplateTestBase() {
 
@@ -144,11 +143,7 @@
     }
 
     fun testWideIcon_inBigPicture_cappedTo16By9() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_cappedTo16By9" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 100)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -166,11 +161,7 @@
     }
 
     fun testWideIcon_inBigPicture_canShowExact4By3() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_canShowExact4By3" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
         val picture = createBitmap(40, 30)
         val icon = createBitmap(400, 300)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -188,11 +179,7 @@
     }
 
     fun testWideIcon_inBigPicture_neverNarrowerThanSquare() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_neverNarrowerThanSquare" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 300)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -254,11 +241,7 @@
     }
 
     fun testBigPictureStyle_populatesExtrasCompatibly() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testBigPictureStyle_populatesExtrasCompatibly" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
         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 +255,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 +269,15 @@
         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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         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 +287,16 @@
         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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
         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 +311,13 @@
             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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -367,8 +331,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 +339,8 @@
     }
 
     fun testPromoteBigPicture_withLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(80, 65)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -392,37 +352,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)
-
         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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val inputWidth = 400
         val inputHeight = 300
@@ -436,36 +385,28 @@
                         .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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         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 +418,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 +803,15 @@
         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() {
+        Assume.assumeFalse("Current platform does not support notification styles.",
+                mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE) ||
+                        mContext.packageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK))
     }
 
     companion object {
diff --git a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
index 18d4904..2c88064 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CameraManagerTest.java
@@ -669,18 +669,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 +786,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 +848,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,6 +948,8 @@
 
             verifySingleAvailabilityCbsReceived(onCameraClosedEventQueue,
                     onCameraOpenedEventQueue, cameras[0], "onCameraClosed", "onCameraOpened");
+
+            mCameraManager.unregisterAvailabilityCallback(ac);
         }
     } // testCameraManagerListenerCallbacks
 
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
index 1c35d48..f85d895 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DevicePolicyManagementRoleHolderTest.java
@@ -148,25 +148,29 @@
         UserHandle profile = null;
         String roleHolderPackageName = null;
         try (TestAppInstance roleHolderApp = sRoleHolderApp.install()) {
-            roleHolderPackageName = roleHolderApp.packageName();
-            TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
+            try {
+                roleHolderPackageName = roleHolderApp.packageName();
+                TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
 
-            profile = sDevicePolicyManager.createAndProvisionManagedProfile(
-                    MANAGED_PROFILE_PROVISIONING_PARAMS);
+                profile = sDevicePolicyManager.createAndProvisionManagedProfile(
+                        MANAGED_PROFILE_PROVISIONING_PARAMS);
 
-            UserReference userReference = UserReference.of(profile);
-            Poll.forValue(() -> TestApis.packages().installedForUser(userReference))
-                    .toMeet(packages -> packages.contains(Package.of(roleHolderApp.packageName())))
-                    .errorOnFail("Role holder package not installed on the managed profile.")
-                    .await();
+                UserReference userReference = UserReference.of(profile);
+                Poll.forValue(() -> TestApis.packages().installedForUser(userReference))
+                        .toMeet(packages -> packages.contains(
+                                Package.of(roleHolderApp.packageName())))
+                        .errorOnFail("Role holder package not installed on the managed profile.")
+                        .await();
+            } finally {
+                if (roleHolderPackageName != null) {
+                    TestApis.devicePolicy()
+                            .unsetDevicePolicyManagementRoleHolder(roleHolderPackageName);
+                }
+            }
         } finally {
             if (profile != null) {
                 TestApis.users().find(profile).remove();
             }
-            if (roleHolderPackageName != null) {
-                TestApis.devicePolicy()
-                        .unsetDevicePolicyManagementRoleHolder(roleHolderPackageName);
-            }
         }
     }
 
@@ -182,29 +186,33 @@
         UserHandle managedUser = null;
         String roleHolderPackageName = null;
         try (TestAppInstance roleHolderApp = sRoleHolderApp.install()) {
-            roleHolderPackageName = roleHolderApp.packageName();
-            TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
+            try {
+                roleHolderPackageName = roleHolderApp.packageName();
+                TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
 
-            managedUser = sDeviceState.dpc().devicePolicyManager().createAndManageUser(
-                    RemoteDpc.DPC_COMPONENT_NAME,
-                    MANAGED_USER_NAME,
-                    RemoteDpc.DPC_COMPONENT_NAME,
-                    /* adminExtras= */ null,
-                    /* flags= */ 0);
+                managedUser = sDeviceState.dpc().devicePolicyManager().createAndManageUser(
+                        RemoteDpc.DPC_COMPONENT_NAME,
+                        MANAGED_USER_NAME,
+                        RemoteDpc.DPC_COMPONENT_NAME,
+                        /* adminExtras= */ null,
+                        /* flags= */ 0);
 
-            UserReference userReference = UserReference.of(managedUser);
-            Poll.forValue(() -> TestApis.packages().installedForUser(userReference))
-                    .toMeet(packages -> packages.contains(Package.of(roleHolderApp.packageName())))
-                    .errorOnFail("Role holder package not installed on the managed user.")
-                    .await();
+                UserReference userReference = UserReference.of(managedUser);
+                Poll.forValue(() -> TestApis.packages().installedForUser(userReference))
+                        .toMeet(packages -> packages.contains(
+                                Package.of(roleHolderApp.packageName())))
+                        .errorOnFail("Role holder package not installed on the managed user.")
+                        .await();
+            } finally {
+                if (roleHolderPackageName != null) {
+                    TestApis.devicePolicy()
+                            .unsetDevicePolicyManagementRoleHolder(roleHolderPackageName);
+                }
+            }
         } finally {
             if (managedUser != null) {
                 TestApis.users().find(managedUser).remove();
             }
-            if (roleHolderPackageName != null) {
-                TestApis.devicePolicy()
-                        .unsetDevicePolicyManagementRoleHolder(roleHolderPackageName);
-            }
         }
     }
 
@@ -218,20 +226,22 @@
     public void profileRemoved_roleHolderReceivesBroadcast() throws Exception {
         String roleHolderPackageName = null;
         try (TestAppInstance roleHolderApp = sRoleHolderApp.install()) {
-            roleHolderPackageName = roleHolderApp.packageName();
-            TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
-            UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
-                    MANAGED_PROFILE_PROVISIONING_PARAMS);
+            try {
+                roleHolderPackageName = roleHolderApp.packageName();
+                TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
+                UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
+                        MANAGED_PROFILE_PROVISIONING_PARAMS);
 
-            TestApis.users().find(profile).remove();
+                TestApis.users().find(profile).remove();
 
-            EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
-                            .whereIntent().action().isEqualTo(ACTION_MANAGED_PROFILE_REMOVED))
-                    .eventOccurred();
-        } finally {
-            if (roleHolderPackageName != null) {
-                TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
-                        roleHolderPackageName);
+                EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
+                                .whereIntent().action().isEqualTo(ACTION_MANAGED_PROFILE_REMOVED))
+                        .eventOccurred();
+            } finally {
+                if (roleHolderPackageName != null) {
+                    TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
+                            roleHolderPackageName);
+                }
             }
         }
     }
@@ -246,20 +256,23 @@
     public void profilePaused_roleHolderReceivesBroadcast() throws Exception {
         String roleHolderPackageName = null;
         try (TestAppInstance roleHolderApp = sRoleHolderApp.install()) {
-            roleHolderPackageName = roleHolderApp.packageName();
-            TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
-            UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
-                    MANAGED_PROFILE_PROVISIONING_PARAMS);
+            try {
+                roleHolderPackageName = roleHolderApp.packageName();
+                TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
+                UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
+                        MANAGED_PROFILE_PROVISIONING_PARAMS);
 
-            TestApis.users().find(profile).setQuietMode(true);
+                TestApis.users().find(profile).setQuietMode(true);
 
-            EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
-                            .whereIntent().action().isEqualTo(ACTION_MANAGED_PROFILE_UNAVAILABLE))
-                    .eventOccurred();
-        } finally {
-            if (roleHolderPackageName != null) {
-                TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
-                        roleHolderPackageName);
+                EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
+                                .whereIntent().action().isEqualTo(
+                                        ACTION_MANAGED_PROFILE_UNAVAILABLE))
+                        .eventOccurred();
+            } finally {
+                if (roleHolderPackageName != null) {
+                    TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
+                            roleHolderPackageName);
+                }
             }
         }
     }
@@ -274,21 +287,23 @@
     public void profileStarted_roleHolderReceivesBroadcast() throws Exception {
         String roleHolderPackageName = null;
         try (TestAppInstance roleHolderApp = sRoleHolderApp.install()) {
-            roleHolderPackageName = roleHolderApp.packageName();
-            TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
-            UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
-                    MANAGED_PROFILE_PROVISIONING_PARAMS);
-            TestApis.users().find(profile).setQuietMode(true);
+            try {
+                roleHolderPackageName = roleHolderApp.packageName();
+                TestApis.devicePolicy().setDevicePolicyManagementRoleHolder(roleHolderPackageName);
+                UserHandle profile = sDevicePolicyManager.createAndProvisionManagedProfile(
+                        MANAGED_PROFILE_PROVISIONING_PARAMS);
+                TestApis.users().find(profile).setQuietMode(true);
 
-            TestApis.users().find(profile).setQuietMode(false);
+                TestApis.users().find(profile).setQuietMode(false);
 
-            EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
-                            .whereIntent().action().isEqualTo(ACTION_MANAGED_PROFILE_AVAILABLE))
-                    .eventOccurred();
-        } finally {
-            if (roleHolderPackageName != null) {
-                TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
-                        roleHolderPackageName);
+                EventLogsSubject.assertThat(roleHolderApp.events().broadcastReceived()
+                                .whereIntent().action().isEqualTo(ACTION_MANAGED_PROFILE_AVAILABLE))
+                        .eventOccurred();
+            } finally {
+                if (roleHolderPackageName != null) {
+                    TestApis.devicePolicy().unsetDevicePolicyManagementRoleHolder(
+                            roleHolderPackageName);
+                }
             }
         }
     }
diff --git a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
index 5598d3f..66d1e02 100644
--- a/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/RandomRWTest.java
@@ -21,6 +21,7 @@
 
 import android.os.Environment;
 import android.mediapc.cts.common.Utils;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 
 import androidx.test.runner.AndroidJUnit4;
 
@@ -30,7 +31,9 @@
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
 @RunWith(AndroidJUnit4.class)
@@ -38,19 +41,9 @@
     private static final String DIR_RANDOM_WR = "RANDOM_WR";
     private static final String DIR_RANDOM_RD = "RANDOM_RD";
     private static final String REPORT_LOG_NAME = "CtsFileSystemTestCases";
-    private static final double MIN_READ_MBPS;
-    private static final double MIN_WRITE_MBPS;
 
-    static {
-        if (Utils.isRPerfClass()) {
-            MIN_READ_MBPS = 25;
-            MIN_WRITE_MBPS = 10;
-        } else {
-            // Performance class Build.VERSION_CODES.S and beyond
-            MIN_READ_MBPS = 40;
-            MIN_WRITE_MBPS = 10;
-        }
-    }
+    @Rule
+    public final TestName mTestName = new TestName();
 
     @After
     public void tearDown() throws Exception {
@@ -58,7 +51,7 @@
         FileUtil.removeFileOrDir(getContext(), DIR_RANDOM_RD);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-4"})
     @Test
     public void testRandomRead() throws Exception {
         final int READ_BUFFER_SIZE = 4 * 1024;
@@ -72,14 +65,18 @@
         double mbps = FileUtil.doRandomReadTest(getContext(), DIR_RANDOM_RD, report, fileSize,
                 READ_BUFFER_SIZE);
         report.submit(getInstrumentation());
-        if (Utils.isPerfClass()) {
-            assertTrue("measured " + mbps + " is less than target (" + MIN_READ_MBPS + " MBPS)",
-                       mbps >= MIN_READ_MBPS);
-        }
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_4 = pce.addR8_2__H_1_4();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_4 = pce.addR8_2__H_2_4();
+        r8_2__H_1_4.setFilesystemIoRate(mbps);
+        r8_2__H_2_4.setFilesystemIoRate(mbps);
+
+        pce.submitAndCheck();
     }
 
     // It is taking too long in some device, and thus cannot run multiple times
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-2"})
     @Test
     public void testRandomUpdate() throws Exception {
         final int WRITE_BUFFER_SIZE = 4 * 1024;
@@ -98,10 +95,13 @@
                 WRITE_BUFFER_SIZE);
         }
         report.submit(getInstrumentation());
-        if (Utils.isPerfClass()) {
-            // for performance class devices we must be able to write 256MB
-            assertTrue("measured " + mbps + " is less than target (" + MIN_WRITE_MBPS + " MBPS)",
-                       mbps >= MIN_WRITE_MBPS);
-        }
+
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_2 = pce.addR8_2__H_1_2();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_2 = pce.addR8_2__H_2_2();
+        r8_2__H_1_2.setFilesystemIoRate(mbps);
+        r8_2__H_2_2.setFilesystemIoRate(mbps);
+
+        pce.submitAndCheck();
     }
 }
diff --git a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
index e535bc9..1beb91a 100644
--- a/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
+++ b/tests/filesystem/src/android/filesystem/cts/SequentialRWTest.java
@@ -18,6 +18,7 @@
 
 import android.util.Log;
 import android.mediapc.cts.common.Utils;
+import android.mediapc.cts.common.PerformanceClassEvaluator;
 
 import static androidx.test.InstrumentationRegistry.getContext;
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -35,7 +36,9 @@
 import static org.junit.Assert.assertTrue;
 
 import org.junit.After;
+import org.junit.Rule;
 import org.junit.Test;
+import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
 import java.io.File;
@@ -51,19 +54,9 @@
     private static final String DIR_SEQ_RD = "SEQ_RD";
     private static final String REPORT_LOG_NAME = "CtsFileSystemTestCases";
     private static final int BUFFER_SIZE = 10 * 1024 * 1024;
-    private static final double MIN_READ_MBPS;
-    private static final double MIN_WRITE_MBPS;
 
-    static {
-        if (Utils.isRPerfClass()) {
-            MIN_READ_MBPS = 200;
-            MIN_WRITE_MBPS = 100;
-        } else {
-            // Performance class Build.VERSION_CODES.S and beyond
-            MIN_READ_MBPS = 250;
-            MIN_WRITE_MBPS = 125;
-        }
-    }
+    @Rule
+    public final TestName mTestName = new TestName();
 
     @After
     public void tearDown() throws Exception {
@@ -72,7 +65,7 @@
         FileUtil.removeFileOrDir(getContext(), DIR_SEQ_RD);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-1"})
     @Test
     public void testSingleSequentialWrite() throws Exception {
         final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
@@ -105,10 +98,13 @@
         Log.v(TAG, "sequential write " + stat.mAverage + " MBPS");
         report.submit(getInstrumentation());
 
-        if (Utils.isPerfClass()) {
-            assertTrue("measured " + stat.mAverage + " is less than target (" + MIN_WRITE_MBPS +
-                       " MBPS)", stat.mAverage >= MIN_WRITE_MBPS);
-        }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_1 = pce.addR8_2__H_1_1();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_1 = pce.addR8_2__H_2_1();
+        r8_2__H_1_1.setFilesystemIoRate(stat.mAverage);
+        r8_2__H_2_1.setFilesystemIoRate(stat.mAverage);
+
+        pce.submitAndCheck();
     }
 
     @Test
@@ -124,7 +120,7 @@
                 NUMBER_REPETITION, REPORT_LOG_NAME, streamName);
     }
 
-    @CddTest(requirement="8.2")
+    @CddTest(requirements = {"8.2/H-1-3"})
     @Test
     public void testSingleSequentialRead() throws Exception {
         final long fileSize = FileUtil.getFileSizeExceedingMemory(getContext(), BUFFER_SIZE);
@@ -167,9 +163,12 @@
         Log.v(TAG, "sequential read " + stat.mAverage + " MBPS");
         report.submit(getInstrumentation());
 
-        if (Utils.isPerfClass()) {
-            assertTrue("measured " + stat.mAverage + " is less than target (" + MIN_READ_MBPS +
-                       " MBPS)", stat.mAverage >= MIN_READ_MBPS);
-        }
+        PerformanceClassEvaluator pce = new PerformanceClassEvaluator(this.mTestName);
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_1_3 = pce.addR8_2__H_1_3();
+        PerformanceClassEvaluator.FileSystemRequirement r8_2__H_2_3 = pce.addR8_2__H_2_3();
+        r8_2__H_1_3.setFilesystemIoRate(stat.mAverage);
+        r8_2__H_2_3.setFilesystemIoRate(stat.mAverage);
+
+        pce.submitAndCheck();
     }
 }
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/jetpack/Android.bp b/tests/framework/base/windowmanager/jetpack/Android.bp
index 5771a28..1ab377f 100644
--- a/tests/framework/base/windowmanager/jetpack/Android.bp
+++ b/tests/framework/base/windowmanager/jetpack/Android.bp
@@ -32,6 +32,21 @@
 }
 
 android_library_import {
+    name: "cts_window-extensions-core_nodeps",
+    aars: ["window-extensions-core-release.aar"],
+    sdk_version: "current",
+}
+
+java_library {
+    name: "cts_window-extensions-core",
+    sdk_version: "current",
+    static_libs: [
+        "cts_window-extensions-core_nodeps",
+    ],
+    installable: false,
+}
+
+android_library_import {
     name: "cts_window-sidecar_nodeps",
     aars: ["window-sidecar-release.aar"],
     sdk_version: "current",
@@ -49,11 +64,12 @@
 java_library {
     name: "cts_window_jetpack_utils",
     srcs: [
-        "src/android/server/wm/jetpack/utils/**/*.java"
+        "src/android/server/wm/jetpack/utils/**/*.java",
     ],
     static_libs: [
         "compatibility-device-util-axt",
         "cts_window-extensions",
+        "cts_window-extensions-core",
         "cts_window-sidecar",
     ],
     sdk_version: "test_current",
@@ -71,6 +87,7 @@
         "platform-test-annotations",
         "cts_window-sidecar",
         "cts_window-extensions",
+        "cts_window-extensions-core",
     ],
     libs: [
         "android.test.base",
diff --git a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
index b332543..66e856d 100644
--- a/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
+++ b/tests/framework/base/windowmanager/jetpack/SignedApp/src/android/server/wm/jetpack/signed/SignedEmbeddingActivity.java
@@ -18,6 +18,7 @@
 
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.EMBEDDED_ACTIVITY_ID;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createSplitPairRuleBuilderWithJava8Predicate;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createWildcardSplitPairRule;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityCrossUidInSplit;
 import static android.server.wm.jetpack.utils.ExtensionUtil.assumeExtensionSupportedDevice;
@@ -85,7 +86,7 @@
         TestValueCountConsumer<List<SplitInfo>> splitInfoConsumer = new TestValueCountConsumer<>();
         embeddingComponent.setSplitInfoCallback(splitInfoConsumer);
 
-        SplitPairRule splitPairRule = new SplitPairRule.Builder(
+        SplitPairRule splitPairRule = createSplitPairRuleBuilderWithJava8Predicate(
                 activityActivityPair -> true /* activityActivityPredicate */,
                 activityIntentPair -> true /* activityIntentPredicate */,
                 parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
index 46d3fa8..18fe90e 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ActivityEmbeddingBoundsTests.java
@@ -19,6 +19,7 @@
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.DEFAULT_SPLIT_RATIO;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.UNEVEN_CONTAINERS_DEFAULT_SPLIT_RATIO;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.assertValidSplit;
+import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.createSplitPairRuleBuilderWithJava8Predicate;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.startActivityAndVerifySplit;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitAndAssertNotVisible;
 import static android.server.wm.jetpack.utils.ActivityEmbeddingUtil.waitForFillsTask;
@@ -71,7 +72,7 @@
         // Set split pair rule such that if the parent width is any smaller than it is now, then
         // the parent cannot support a split.
         final int originalTaskWidth = getTaskWidth();
-        final SplitPairRule splitPairRule = new SplitPairRule.Builder(
+        final SplitPairRule splitPairRule = createSplitPairRuleBuilderWithJava8Predicate(
                 activityActivityPair -> true /* activityPairPredicate */,
                 activityIntentPair -> true /* activityIntentPredicate */,
                 parentWindowMetrics -> parentWindowMetrics.getBounds().width() >= originalTaskWidth)
@@ -173,7 +174,7 @@
         final float activityBCSplitRatio = 0.85f;
 
         // Create a split rule for activity A and activity B where the split ratio is 0.37.
-        final SplitPairRule splitPairRuleAB = new SplitPairRule.Builder(
+        final SplitPairRule splitPairRuleAB = createSplitPairRuleBuilderWithJava8Predicate(
                 activityActivityPair -> false /* activityPairPredicate */,
                 activityIntentPair -> matchesActivityIntentPair(activityIntentPair, activityAId,
                         activityBId) /* activityIntentPredicate */,
@@ -181,7 +182,7 @@
                 .setSplitRatio(activityABSplitRatio).build();
 
         // Create a split rule for activity B and activity C where the split ratio is 0.65.
-        final SplitPairRule splitPairRuleBC = new SplitPairRule.Builder(
+        final SplitPairRule splitPairRuleBC = createSplitPairRuleBuilderWithJava8Predicate(
                 activityActivityPair -> false /* activityPairPredicate */,
                 activityIntentPair -> matchesActivityIntentPair(activityIntentPair, activityBId,
                         activityCId) /* activityIntentPredicate */,
@@ -209,7 +210,8 @@
     }
 
     private SplitPairRule createUnevenWidthSplitPairRule(int layoutDir) {
-        return new SplitPairRule.Builder(activityActivityPair -> true /* activityPairPredicate */,
+        return createSplitPairRuleBuilderWithJava8Predicate(
+                activityActivityPair -> true /* activityPairPredicate */,
                 activityIntentPair -> true /* activityIntentPredicate */,
                 parentWindowMetrics -> true /* parentWindowMetricsPredicate */)
                 .setSplitRatio(UNEVEN_CONTAINERS_DEFAULT_SPLIT_RATIO)
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
index 7162a442..c2752e6 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/ExtensionWindowLayoutComponentTest.java
@@ -39,10 +39,9 @@
 import static org.junit.Assume.assumeNotNull;
 
 import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
 import android.server.wm.jetpack.utils.TestActivity;
 import android.server.wm.jetpack.utils.TestConfigChangeHandlingActivity;
-import android.server.wm.jetpack.utils.TestValueCountConsumer;
+import android.server.wm.jetpack.utils.TestValueCountJavaConsumer;
 import android.server.wm.jetpack.utils.WindowManagerJetpackTestBase;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -104,8 +103,8 @@
         // Create the callback, onWindowLayoutChanged should only be called twice in this
         // test, not the third time when the orientation will change because the listener will be
         // removed.
-        TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
-                new TestValueCountConsumer<>();
+        TestValueCountJavaConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
+                new TestValueCountJavaConsumer<>();
         windowLayoutInfoConsumer.setCount(2);
 
         // Add window layout listener for mWindowToken - onWindowLayoutChanged should be called
@@ -129,8 +128,8 @@
 
     @Test
     public void testWindowLayoutComponent_WindowLayoutInfoListener() {
-        TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
-                new TestValueCountConsumer<>();
+        TestValueCountJavaConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
+                new TestValueCountJavaConsumer<>();
         // Test that adding and removing callback succeeds
         mWindowLayoutComponent.addWindowLayoutInfoListener(mActivity, windowLayoutInfoConsumer);
         mWindowLayoutComponent.removeWindowLayoutInfoListener(windowLayoutInfoConsumer);
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
index 477cc8d..aeb1cbf 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ActivityEmbeddingUtil.java
@@ -43,6 +43,7 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.window.extensions.core.util.function.Predicate;
 import androidx.window.extensions.embedding.ActivityEmbeddingComponent;
 import androidx.window.extensions.embedding.SplitInfo;
 import androidx.window.extensions.embedding.SplitPairRule;
@@ -54,7 +55,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
-import java.util.function.Predicate;
 
 /**
  * Utility class for activity embedding tests.
@@ -69,18 +69,17 @@
 
     @NonNull
     public static SplitPairRule createWildcardSplitPairRule(boolean shouldClearTop) {
-        // Any activity be split with any activity
-        final Predicate<Pair<Activity, Activity>> activityPairPredicate =
-                activityActivityPair -> true;
-        // Any activity can launch any split intent
-        final Predicate<Pair<Activity, Intent>> activityIntentPredicate =
-                activityIntentPair -> true;
-        // Allow any parent bounds to show the split containers side by side
-        Predicate<WindowMetrics> parentWindowMetricsPredicate = windowMetrics -> true;
         // Build the split pair rule
-        return new SplitPairRule.Builder(activityPairPredicate,
-                activityIntentPredicate, parentWindowMetricsPredicate).setSplitRatio(
-                DEFAULT_SPLIT_RATIO).setShouldClearTop(shouldClearTop).build();
+        return createSplitPairRuleBuilderWithJava8Predicate(
+                // Any activity be split with any activity
+                activityActivityPair -> true,
+                // Any activity can launch any split intent
+                activityIntentPair -> true,
+                // Allow any parent bounds to show the split containers side by side
+                windowMetrics -> true)
+                .setSplitRatio(DEFAULT_SPLIT_RATIO)
+                .setShouldClearTop(shouldClearTop)
+                .build();
     }
 
     @NonNull
@@ -93,18 +92,16 @@
     @NonNull
     public static SplitPairRule.Builder createWildcardSplitPairRuleBuilderWithPrimaryActivityClass(
             Class<? extends Activity> activityClass, boolean shouldClearTop) {
-        // The specified activity be split any activity
-        final Predicate<Pair<Activity, Activity>> activityPairPredicate =
-                activityActivityPair -> activityActivityPair.first.getClass().equals(activityClass);
-        // The specified activity can launch any split intent
-        final Predicate<Pair<Activity, Intent>> activityIntentPredicate =
-                activityIntentPair -> activityIntentPair.first.getClass().equals(activityClass);
-        // Allow any parent bounds to show the split containers side by side
-        Predicate<WindowMetrics> parentWindowMetricsPredicate = windowMetrics -> true;
         // Build the split pair rule
-        return new SplitPairRule.Builder(activityPairPredicate,
-                activityIntentPredicate, parentWindowMetricsPredicate).setSplitRatio(
-                DEFAULT_SPLIT_RATIO).setShouldClearTop(shouldClearTop);
+        return createSplitPairRuleBuilderWithJava8Predicate(
+                // The specified activity be split any activity
+                activityActivityPair -> activityActivityPair.first.getClass().equals(activityClass),
+                // The specified activity can launch any split intent
+                activityIntentPair -> activityIntentPair.first.getClass().equals(activityClass),
+                // Allow any parent bounds to show the split containers side by side
+                windowMetrics -> true)
+                .setSplitRatio(DEFAULT_SPLIT_RATIO)
+                .setShouldClearTop(shouldClearTop);
     }
 
     @NonNull
@@ -112,6 +109,24 @@
         return createWildcardSplitPairRule(false /* shouldClearTop */);
     }
 
+    /**
+     * A wrapper to create {@link SplitPairRule} builder with Java 8 Predicate to prevent ambiguous
+     * issue when using lambda expressions.
+     * <p>
+     * It should only be used if
+     * {@link #createSplitPairRuleBuilder(Predicate, Predicate, Predicate)} cannot be called prior
+     * to {@link ExtensionUtil#EXTENSION_VERSION_2}.
+     */
+    @NonNull
+    public static SplitPairRule.Builder createSplitPairRuleBuilderWithJava8Predicate(
+            @NonNull java.util.function.Predicate<Pair<Activity, Activity>> activitiesPairPredicate,
+            @NonNull java.util.function.Predicate<Pair<Activity, Intent>>
+                    activityIntentPairPredicate,
+            @NonNull java.util.function.Predicate<WindowMetrics> windowMetricsPredicate) {
+        return new SplitPairRule.Builder(activitiesPairPredicate, activityIntentPairPredicate,
+                windowMetricsPredicate);
+    }
+
     public static TestActivity startActivityAndVerifyNotSplit(
             @NonNull Activity activityLaunchingFrom) {
         final String secondActivityId = "secondActivityId";
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
index a3e682b..f7b352f 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/ExtensionUtil.java
@@ -114,8 +114,8 @@
         if (windowLayoutComponent == null) {
             return null;
         }
-        TestValueCountConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
-                new TestValueCountConsumer<>();
+        TestValueCountJavaConsumer<WindowLayoutInfo> windowLayoutInfoConsumer =
+                new TestValueCountJavaConsumer<>();
         windowLayoutComponent.addWindowLayoutInfoListener(activity, windowLayoutInfoConsumer);
         return windowLayoutInfoConsumer.waitAndGet();
     }
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
index 4ebeac4..10fe6fc 100644
--- a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountConsumer.java
@@ -17,14 +17,18 @@
 package android.server.wm.jetpack.utils;
 
 import androidx.annotation.Nullable;
+import androidx.window.extensions.core.util.function.Consumer;
 
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
 
 /**
  * Consumer that provides a simple way to wait for a specific count of values to be received within
  * a timeout and then return the last value.
+ *
+ * It requires the vendor API version at least {@link ExtensionUtil#EXTENSION_VERSION_2} because
+ * it uses extensions core version of {@link Consumer} instead of
+ * {@link java.util.function.Consumer Java 8 version Consumer}.
  */
 public class TestValueCountConsumer<T> implements Consumer<T> {
 
diff --git a/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountJavaConsumer.java b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountJavaConsumer.java
new file mode 100644
index 0000000..19776cb
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/src/android/server/wm/jetpack/utils/TestValueCountJavaConsumer.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.server.wm.jetpack.utils;
+
+import androidx.annotation.Nullable;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+/**
+ * Consumer that provides a simple way to wait for a specific count of values to be received within
+ * a timeout and then return the last value.
+ * <p>
+ * Note that this class should only be used if {@link TestValueCountConsumer} can not be used prior
+ * to {@link ExtensionUtil#EXTENSION_VERSION_2}.
+ */
+public class TestValueCountJavaConsumer<T> implements Consumer<T> {
+
+    private static final long TIMEOUT_MS = 3000;
+    private static final int DEFAULT_COUNT = 1;
+    private int mCount = DEFAULT_COUNT;
+    private LinkedBlockingQueue<T> mLinkedBlockingQueue;
+    private T mLastReportedValue;
+
+    public TestValueCountJavaConsumer() {
+        mLinkedBlockingQueue = new LinkedBlockingQueue<>();
+    }
+
+    @Override
+    public void accept(T value) {
+        // Asynchronously offer value to queue
+        mLinkedBlockingQueue.offer(value);
+    }
+
+    public void setCount(int count) {
+        mCount = count;
+    }
+
+    @Nullable
+    public T waitAndGet() throws InterruptedException {
+        T value = null;
+        for (int i = 0; i < mCount; i++) {
+            value = mLinkedBlockingQueue.poll(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        }
+        mLastReportedValue = value;
+        return value;
+    }
+
+    // Doesn't change the count.
+    public void clearQueue() {
+        mLinkedBlockingQueue.clear();
+    }
+
+    @Nullable
+    public T getLastReportedValue() {
+        return mLastReportedValue;
+    }
+}
diff --git a/tests/framework/base/windowmanager/jetpack/window-extensions-core-release.aar b/tests/framework/base/windowmanager/jetpack/window-extensions-core-release.aar
new file mode 100644
index 0000000..96ff840
--- /dev/null
+++ b/tests/framework/base/windowmanager/jetpack/window-extensions-core-release.aar
Binary files differ
diff --git a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
index 6fc9a67..367e3b9 100644
--- a/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
+++ b/tests/framework/base/windowmanager/jetpack/window-extensions-release.aar
Binary files differ
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/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/mediapc/AndroidTest.xml b/tests/mediapc/AndroidTest.xml
index f4632df..cd882f8 100644
--- a/tests/mediapc/AndroidTest.xml
+++ b/tests/mediapc/AndroidTest.xml
@@ -31,7 +31,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-1.3" />
+        <option name="media-folder-name" value="CtsMediaPerformanceClassTestCases-1.4" />
         <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 739fb52..c1564ba 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-1.3.zip</value>
+      <value>https://storage.googleapis.com/android_media/cts/tests/mediapc/CtsMediaPerformanceClassTestCases-1.4.zip</value>
     </entry>
 </dynamicConfig>
 
diff --git a/tests/mediapc/README.md b/tests/mediapc/README.md
index eedb9bc..fdf445e 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-1.3.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-1.4.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 6cda76b..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;
 
@@ -202,6 +208,131 @@
         }
     }
 
+    // used for requirements [8.2/H-1-1], [8.2/H-1-2], [8.2/H-1-3], [8.2/H-1-4]
+    public static class FileSystemRequirement extends Requirement {
+
+        private static final String TAG = FileSystemRequirement.class.getSimpleName();
+
+        private FileSystemRequirement(String id, RequiredMeasurement<?>... reqs) {
+            super(id, reqs);
+        }
+        /**
+         * Set the Filesystem I/O Rate in MB/s.
+         */
+        public void setFilesystemIoRate(double filesystemIoRate) {
+            this.setMeasuredValue(RequirementConstants.FILESYSTEM_IO_RATE, filesystemIoRate);
+        }
+
+        /**
+         * [8.2/H-1-1] MUST ensure a sequential write performance of at least 100(R) / 125(S &
+         * above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_1() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 100.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 125.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_1, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-1] MUST ensure a sequential write performance of at least 125 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_1() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 125.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_1, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-2] MUST ensure a random write performance of at least 10 MB/s
+         */
+        public static FileSystemRequirement createR8_2__H_1_2() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 10.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_2, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-2] MUST ensure a random write performance of at least 10 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_2() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 10.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_2, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-3] MUST ensure a sequential read performance of at least 200(R) / 250(S &
+         * above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_3() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 200.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 250.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_3, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-3] MUST ensure a sequential read performance of at least 250 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_3() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 250.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_3, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-1-4] MUST ensure a random read performance of at least 25(R) / 40(S & above) MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_1_4() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.R, 25.0)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 40.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_1_4, filesystem_io_rate);
+        }
+
+        /**
+         * [8.2/H-2-4] MUST ensure a random read performance of at least 40 MB/s.
+         */
+        public static FileSystemRequirement createR8_2__H_2_4() {
+            RequiredMeasurement<Double> filesystem_io_rate = RequiredMeasurement
+                .<Double>builder().setId(RequirementConstants.FILESYSTEM_IO_RATE)
+                .setPredicate(RequirementConstants.DOUBLE_GTE)
+                .addRequiredValue(Build.VERSION_CODES.S, 40.0)
+                .build();
+
+            return new FileSystemRequirement(RequirementConstants.R8_2__H_2_4, filesystem_io_rate);
+        }
+    }
+
     public static class CodecInitLatencyRequirement extends Requirement {
 
         private static final String TAG = CodecInitLatencyRequirement.class.getSimpleName();
@@ -550,6 +681,42 @@
         }
 
         /**
+         * Helper method used to create ConcurrentCodecRequirements, builds and fills out the
+         * a requirement for tests ran with a resolution of 720p
+         */
+        private static ConcurrentCodecRequirement create720p(String requirementId,
+                RequiredMeasurement<?> measure) {
+            RequiredMeasurement<Integer> testResolution = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.TEST_RESOLUTION)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.R, 720)
+                .build();
+
+            ConcurrentCodecRequirement req = new ConcurrentCodecRequirement(requirementId, measure,
+                    testResolution);
+            req.setMeasuredValue(RequirementConstants.TEST_RESOLUTION, 720);
+            return req;
+        }
+
+        /**
+         * Helper method used to create ConcurrentCodecRequirements, builds and fills out the
+         * a requirement for tests ran with a resolution of 1080p
+         */
+        private static ConcurrentCodecRequirement create1080p(String requirementId,
+                RequiredMeasurement<?> measure) {
+            RequiredMeasurement<Integer> testResolution = RequiredMeasurement.<Integer>builder()
+                .setId(RequirementConstants.TEST_RESOLUTION)
+                .setPredicate(RequirementConstants.INTEGER_EQ)
+                .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 1080)
+                .build();
+
+            ConcurrentCodecRequirement req = new ConcurrentCodecRequirement(requirementId, measure,
+                    testResolution);
+            req.setMeasuredValue(RequirementConstants.TEST_RESOLUTION, 1080);
+            return req;
+        }
+
+        /**
          * [2.2.7.1/5.1/H-1-1] MUST advertise the maximum number of hardware video decoder
          * sessions that can be run concurrently in any codec combination via the
          * CodecCapabilities.getMaxSupportedInstances() and VideoCapabilities
@@ -568,7 +735,7 @@
                         resolution))
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
+            return create720p(RequirementConstants.R5_1__H_1_1, maxInstances);
         }
 
         /**
@@ -584,7 +751,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_1, maxInstances);
+            return create1080p(RequirementConstants.R5_1__H_1_1, maxInstances);
         }
 
         /**
@@ -603,8 +770,7 @@
                     getReqMinConcurrentFps(Build.VERSION_CODES.S, mimeType1, mimeType2, resolution))
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
-                reqConcurrentFps);
+            return create720p(RequirementConstants.R5_1__H_1_2, reqConcurrentFps);
         }
 
         /**
@@ -619,8 +785,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_2,
-                reqConcurrentFps);
+            return create1080p(RequirementConstants.R5_1__H_1_2, reqConcurrentFps);
         }
 
         /**
@@ -642,7 +807,7 @@
                         resolution))
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
+            return create720p(RequirementConstants.R5_1__H_1_3, maxInstances);
         }
 
         /**
@@ -658,7 +823,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_3, maxInstances);
+            return create1080p(RequirementConstants.R5_1__H_1_3, maxInstances);
         }
 
         /**
@@ -675,8 +840,7 @@
                 .addRequiredValue(Build.VERSION_CODES.S, 0.0)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
-                reqConcurrentFps);
+            return create720p(RequirementConstants.R5_1__H_1_4, reqConcurrentFps);
         }
 
         /**
@@ -692,8 +856,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 0.0)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_4,
-                reqConcurrentFps);
+            return create1080p(RequirementConstants.R5_1__H_1_4, reqConcurrentFps);
         }
 
         /**
@@ -715,7 +878,7 @@
                         resolution))
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
+            return create720p(RequirementConstants.R5_1__H_1_5, maxInstances);
         }
 
         /**
@@ -731,7 +894,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_5, maxInstances);
+            return create1080p(RequirementConstants.R5_1__H_1_5, maxInstances);
         }
 
         /**
@@ -753,8 +916,7 @@
                         / 2)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
-                reqConcurrentFps);
+            return create720p(RequirementConstants.R5_1__H_1_6, reqConcurrentFps);
         }
 
         /**
@@ -770,8 +932,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 6 * FPS_30_TOLERANCE / 2)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_6,
-                reqConcurrentFps);
+            return create1080p(RequirementConstants.R5_1__H_1_6, reqConcurrentFps);
         }
 
         /**
@@ -786,8 +947,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 2 * FPS_30_TOLERANCE)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_9,
-                reqConcurrentFps);
+            return create1080p(RequirementConstants.R5_1__H_1_9, reqConcurrentFps);
         }
 
         /**
@@ -803,8 +963,7 @@
                 .addRequiredValue(Build.VERSION_CODES.TIRAMISU, 4 * FPS_30_TOLERANCE)
                 .build();
 
-            return new ConcurrentCodecRequirement(RequirementConstants.R5_1__H_1_10,
-                reqConcurrentFps);
+            return create1080p(RequirementConstants.R5_1__H_1_10, reqConcurrentFps);
         }
     }
 
@@ -1341,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");
@@ -1374,6 +1573,38 @@
         return this.<MemoryRequirement>addRequirement(MemoryRequirement.createR7_6_1__H_2_1());
     }
 
+    public FileSystemRequirement addR8_2__H_1_1() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_1());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_1() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_1());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_2() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_2());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_2() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_2());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_3() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_3());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_3() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_3());
+    }
+
+    public FileSystemRequirement addR8_2__H_1_4() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_1_4());
+    }
+
+    public FileSystemRequirement addR8_2__H_2_4() {
+        return this.addRequirement(FileSystemRequirement.createR8_2__H_2_4());
+    }
+
     public FrameDropRequirement addR5_3__H_1_1_R() {
         return this.addRequirement(FrameDropRequirement.createR5_3__H_1_1_R());
     }
@@ -1540,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 f89cb28..777a8f2 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 ad0d0d56..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
@@ -77,6 +80,7 @@
     public static final String RTBD = "tbd"; // placeholder for requirements without a set id
 
     public static final String CONCURRENT_SESSIONS = "concurrent_sessions";
+    public static final String TEST_RESOLUTION = "resolution";
     public static final String CONCURRENT_FPS = "concurrent_fps";
     public static final String SUPPORTED_PERFORMANCE_POINTS = "supported_performance_points";
     public static final String FRAMES_DROPPED = "frame_drops_per_30sec";
@@ -92,6 +96,7 @@
     public static final String SECURE_REQ_SATISFIED = "secure_requirement_satisfied_boolean";
     public static final String NUM_CRYPTO_HW_SECURE_ALL_SUPPORT =
         "number_crypto_hw_secure_all_support";
+    public static final String FILESYSTEM_IO_RATE = "filesystem_io_rate_mbps";
 
     public static final String PRIMARY_CAMERA_AVAILABLE = "primary_camera_available";
     public static final String PRIMARY_CAMERA_RESOLUTION = "primary_camera_resolution";
@@ -126,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
@@ -137,9 +144,10 @@
     public static final BiPredicate<Integer, Integer> INTEGER_GTE = RequirementConstants.gte();
     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();
-    public static final BiPredicate<Double, Double> DOUBLE_GTE = RequirementConstants.gte();
 
     /**
      * Creates a >= predicate.
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 693691c..374a22c 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-1.3
+resLabel=CtsMediaPerformanceClassTestCases-1.4
 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 6cf7a9c..0497862 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-1.3/");
+            return (getTopDirString() + "test/CtsMediaPerformanceClassTestCases-1.4/");
         }
     }
 }
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/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
index 32d37fc..6807c39 100644
--- a/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
+++ b/tests/tests/bluetooth/bluetoothTestUtilLib/src/android/bluetooth/cts/BTAdapterUtils.java
@@ -280,7 +280,12 @@
         try {
             adoptPermissionAsShellUid(BLUETOOTH_CONNECT, BLUETOOTH_PRIVILEGED);
             bluetoothAdapter.disable();
-            return waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter);
+            if (waitForAdapterStateLocked(BluetoothAdapter.STATE_OFF, bluetoothAdapter)) {
+                //TODO b/234892968
+                Thread.sleep(2000);
+                return true;
+            }
+            return false;
         } catch (InterruptedException e) {
             Log.w(TAG, "disableAdapter(): interrupted", e);
         } finally {
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/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/src/android/graphics/fonts/FontFileTestUtil.java b/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
index 5ee0912..fcaab4bc0 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
+++ b/tests/tests/graphics/src/android/graphics/fonts/FontFileTestUtil.java
@@ -90,50 +90,4 @@
         }
         return null;
     }
-
-    public static boolean containsEmojiCompatMetadata(File file) throws IOException {
-        try (FileInputStream fis = new FileInputStream(file)) {
-            final FileChannel fc = fis.getChannel();
-            long size = fc.size();
-            ByteBuffer buffer = fc.map(FileChannel.MapMode.READ_ONLY, 0, size)
-                    .order(ByteOrder.BIG_ENDIAN);
-
-            int magicNumber = buffer.getInt(0);
-
-            int fontOffset = 0;
-            if (magicNumber == TTC_TAG) {
-                throw new IOException("Emoji font is not expected to be in a font collection.");
-            } else if (magicNumber != SFNT_VERSION_1 && magicNumber != SFNT_VERSION_OTTO) {
-                throw new IOException("Unknown magic number: #" + magicNumber);
-            }
-
-            int numTables = buffer.getShort(fontOffset + 4);  // offset to number of table
-            int metaTableOffset = 0;
-            for (int i = 0; i < numTables; ++i) {
-                int tableEntryOffset = fontOffset + 12 + i * 16;
-                int tableTag = buffer.getInt(tableEntryOffset);
-                if (tableTag == META_TAG) {
-                    metaTableOffset = buffer.getInt(tableEntryOffset + 8);
-                    break;
-                }
-            }
-
-            if (metaTableOffset == 0) {
-                throw new IOException("name table not found.");
-            }
-
-            int dataMapsCount = buffer.getInt(metaTableOffset + 12);
-
-            for (int i = 0; i < dataMapsCount; ++i) {
-                int tag = buffer.getInt(metaTableOffset + 16 + 12 * i);
-                int offset = buffer.getInt(metaTableOffset + 16 + 12 * i + 4);
-                int dataLength = buffer.getInt(metaTableOffset + 16 + 12 * i + 8);
-
-                if (tag == EMJI_TAG && dataLength != 0) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
 }
diff --git a/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java b/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
index f42da83..a4d0ab4 100644
--- a/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
+++ b/tests/tests/graphics/src/android/graphics/fonts/SystemEmojiTest.java
@@ -47,8 +47,6 @@
         // NotoColorEmoji.ttf should be always available as a fallback font even if another emoji
         // font files are installed in the system.
         assertThat(emojiFont).isNotNull();
-
-        assertThat(FontFileTestUtil.containsEmojiCompatMetadata(emojiFont)).isTrue();
     }
 
     public String getFontName(String chars) {
diff --git a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
index 90a4975..c0ddb91 100644
--- a/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
+++ b/tests/tests/hardware/src/android/hardware/input/cts/tests/VirtualMouseTest.java
@@ -128,10 +128,6 @@
         maybeConsumeHoverEnter();
 
         verifyEvents(Arrays.asList(
-                createMotionEvent(MotionEvent.ACTION_HOVER_ENTER, secondStopPositionX,
-                        secondStopPositionY, -relativeChangeX,
-                        -relativeChangeY, /* vScroll= */ 0f,
-                        /* hScroll= */ 0f, /* buttonState= */ 0, /* pressure= */ 0.0f),
                 createMotionEvent(MotionEvent.ACTION_HOVER_MOVE, secondStopPositionX,
                         secondStopPositionY, -relativeChangeX,
                         -relativeChangeY, /* vScroll= */ 0f,
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 0c33f93..644ecc6 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
@@ -750,7 +750,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/MediaTestBase.java b/tests/tests/media/common/src/android/media/cts/MediaTestBase.java
index 9f98508..55c94de 100644
--- a/tests/tests/media/common/src/android/media/cts/MediaTestBase.java
+++ b/tests/tests/media/common/src/android/media/cts/MediaTestBase.java
@@ -81,6 +81,7 @@
 
     @CallSuper
     protected void tearDown() {
+        mActivityScenario.close();
         mActivity = null;
     }
 
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..e0895ef 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,11 +19,11 @@
 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
 import com.google.common.truth.Truth.assertThat
+import org.junit.Assume
 
 class NotificationTemplateApi30Test : NotificationTemplateTestBase() {
 
@@ -58,11 +58,8 @@
     }
 
     fun testWideIcon_inBigPicture_isSquareForLegacyApps() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testWideIcon_inBigPicture_isSquareForLegacyApps" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(200, 100)
         val views = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -92,11 +89,8 @@
     }
 
     fun testPromoteBigPicture_withoutLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withoutLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
                 .setSmallIcon(R.drawable.ic_media_play)
@@ -121,11 +115,8 @@
     }
 
     fun testPromoteBigPicture_withLargeIcon() {
-        if (isPlatformAutomotive()) {
-            Log.i(TAG, "Skipping: testPromoteBigPicture_withLargeIcon" +
-                    " - BigPictureStyle is not supported in automotive.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val icon = createBitmap(80, 65)
         val builder = Notification.Builder(mContext, NOTIFICATION_CHANNEL_ID)
@@ -137,36 +128,24 @@
                         .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.")
-            return
-        }
+        skipIfPlatformDoesNotSupportNotificationStyles()
+
         val picture = createBitmap(40, 30)
         val inputWidth = 400
         val inputHeight = 300
@@ -180,24 +159,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 +288,19 @@
         }
     }
 
-    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() {
+        Assume.assumeFalse("Current platform does not support notification styles.",
+                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/os/src/android/os/cts/AutoRevokeTest.kt b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
index 9467e6b..db58721 100644
--- a/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
+++ b/tests/tests/os/src/android/os/cts/AutoRevokeTest.kt
@@ -26,6 +26,7 @@
 import android.content.pm.PackageManager.PERMISSION_DENIED
 import android.content.pm.PackageManager.PERMISSION_GRANTED
 import android.content.res.Resources
+import android.provider.DeviceConfig
 import android.net.Uri
 import android.os.Build
 import android.platform.test.annotations.AppModeFull
@@ -47,6 +48,7 @@
 import com.android.compatibility.common.util.SystemUtil.getEventually
 import com.android.compatibility.common.util.SystemUtil.runShellCommandOrThrow
 import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
+import com.android.compatibility.common.util.ThrowingSupplier
 import com.android.compatibility.common.util.UI_ROOT
 import com.android.compatibility.common.util.click
 import com.android.compatibility.common.util.depthFirstSearch
@@ -259,6 +261,7 @@
     @AppModeFull(reason = "Uses separate apps for testing")
     @Test
     fun testPreMinAutoRevokeVersionUnusedApp_doesntGetPermissionRevoked() {
+        assumeFalse(isHibernationEnabledForPreSApps())
         withUnusedThresholdMs(3L) {
             withDummyApp(preMinVersionApkPath, preMinVersionAppPackageName) {
                 withDummyApp {
@@ -287,6 +290,18 @@
         }
     }
 
+    private fun isHibernationEnabledForPreSApps(): Boolean {
+        return runWithShellPermissionIdentity(
+            ThrowingSupplier {
+                DeviceConfig.getBoolean(
+                    DeviceConfig.NAMESPACE_APP_HIBERNATION,
+                    "app_hibernation_targets_pre_s_apps",
+                    false
+                )
+            }
+        )
+    }
+
     @AppModeFull(reason = "Uses separate apps for testing")
     @Test
     fun testAutoRevoke_userAllowlisting() {
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index 1c9dc63..c495afa 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -6495,6 +6495,10 @@
          <p>Not for use by third-party applications.</p> -->
     <attribution android:tag="MusicRecognitionManagerService"
         android:label="@string/music_recognition_manager_service"/>
+    <!-- @hide Allows an application to receive keycode events.
+         <p>Wear specific. -->
+    <permission android:name="android.permission.RECEIVE_KEYCODE_EVENTS"
+                android:protectionLevel="signature|preinstalled" />
 
     <application android:process="system"
                  android:persistent="true"
diff --git a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
index 752a794..93d9f29 100644
--- a/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/PermissionPolicyTest.java
@@ -74,6 +74,9 @@
     private static final String SET_UNRESTRICTED_GESTURE_EXCLUSION
             = "android.permission.SET_UNRESTRICTED_GESTURE_EXCLUSION";
 
+    private static final String RECEIVE_KEYCODE_EVENTS_PERMISSION =
+            "android.permission.RECEIVE_KEYCODE_EVENTS";
+
     private static final String LOG_TAG = "PermissionProtectionTest";
 
     private static final String PLATFORM_PACKAGE_NAME = "android";
@@ -167,11 +170,17 @@
         for (ExpectedPermissionInfo expectedPermission : expectedPermissions) {
             String expectedPermissionName = expectedPermission.name;
             if (shouldSkipPermission(expectedPermissionName)) {
-                // This permission doesn't need to exist yet, but will exist in
-                // a future SPL. It is acceptable to declare the permission
-                // even in an earlier SPL, so we remove it here so it doesn't
-                // trigger a failure after the loop.
-                declaredPermissionsMap.remove(expectedPermissionName);
+                // This permission doesn't need to exist, either because it
+                // will exist in a future SPL or because it is specific to a
+                // particular device type.
+
+                if (shouldAllowPermission(expectedPermissionName)) {
+                    // It is acceptable to declare the permission if it will
+                    // be in a future SPL, but not if it is for a different
+                    // device type. If the permission may be declared, remove
+                    // it here so it doesn't trigger a failure after the loop.
+                    declaredPermissionsMap.remove(expectedPermissionName);
+                }
                 continue;
             }
 
@@ -501,6 +510,18 @@
         return patchDate;
     }
 
+    private boolean shouldAllowPermission(String permissionName) {
+        boolean isWatch =
+                sContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
+
+        switch (permissionName) {
+            case RECEIVE_KEYCODE_EVENTS_PERMISSION:
+                return isWatch;
+            default:
+                return true;
+        }
+    }
+
     private boolean shouldSkipPermission(String permissionName) {
         switch (permissionName) {
             case HIDE_NON_SYSTEM_OVERLAY_WINDOWS_PERMISSION:
@@ -509,6 +530,8 @@
                 return parseDate(SECURITY_PATCH).before(MANAGE_COMPANION_DEVICES_PATCH_DATE);
             case SET_UNRESTRICTED_GESTURE_EXCLUSION:
                 return true;
+            case RECEIVE_KEYCODE_EVENTS_PERMISSION:
+                return true;
             default:
                 return false;
         }
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/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/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/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/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-on-gsi-on-r.xml b/tools/cts-tradefed/res/config/cts-on-gsi-on-r.xml
index be375f0..2800406c 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-on-r.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-on-r.xml
@@ -29,7 +29,13 @@
 
     <!-- Excluded test cases start-->
 
-    <!-- b/240971401 -->
+    <!-- CtsLocationPrivilegedTestCases: b/240971401 -->
     <option name="compatibility:exclude-filter" value="CtsLocationPrivilegedTestCases android.location.cts.privileged.GnssLocationValuesTest#testLowPowerModeGnssLocation" />
+    <!-- CtsMediaTranscodingTestCases: b/257522539 -->
+    <option name="compatibility:exclude-filter" value="CtsMediaTranscodingTestCases android.media.mediatranscoding.cts.MediaTranscodingManagerTest#testAvcTranscoding1080PVideo30FramesWithoutAudio" />
+    <!-- CtsSecurityTestCases: b/241000034 -->
+    <option name="compatibility:exclude-filter" value="CtsSecurityTestCases android.security.cts.VerifiedBootTest#testVerifiedBootSupport" />
+    <!-- CtsKeystoreTestCases: b/218751802 -->
+    <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.KeyAttestationTest#testAttestationKmVersionMatchesFeatureVersionStrongBox" />
 
 </configuration>
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-on-s.xml b/tools/cts-tradefed/res/config/cts-on-gsi-on-s.xml
index 2057484..0b48b68 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-on-s.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-on-s.xml
@@ -29,14 +29,13 @@
 
     <!-- Excluded test cases start-->
 
-    <!-- b/257492672 -->
+    <!-- CtsMediaV2TestCases: b/257492672, b/257492847, b/258826057, b/241293905, b/257493109 -->
     <option name="compatibility:exclude-filter" value="CtsMediaV2TestCases android.mediav2.cts.CodecDecoderTest#testReconfigure" />
-    <!-- b/257553257 -->
+    <!-- CtsOsTestCases: b/257553257 -->
     <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.VibratorTest#testVibrateWaveformWithFrequencyStartsAndFinishesVibration" />
     <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.VibratorTest#testVibratorFrequencyProfileSupportedFrequencyRange" />
     <option name="compatibility:exclude-filter" value="CtsOsTestCases android.os.cts.VibratorTest#testVibratorFrequencyProfileMeasurementInterval" />
-     <!-- b/257492847 -->
-    <option name="compatibility:exclude-filter" value="CtsMediaV2TestCases android.mediav2.cts.CodecDecoderTest#testSimpleDecodeQueueCSD" />
-    <option name="compatibility:exclude-filter" value="CtsMediaV2TestCases android.mediav2.cts.CodecDecoderTest#testSimpleDecode" />
+    <!-- CtsKeystoreTestCases: b/258826404 -->
+    <option name="compatibility:exclude-filter" value="CtsKeystoreTestCases android.keystore.cts.NoAttestKeyTest#testEcAttestKeyFail" />
 
 </configuration>