Merge "CTS test for TelephonyManager#isManualNetworkSelectionAllowed"
diff --git a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
index bdbc61a..976bee0 100644
--- a/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
+++ b/apps/CameraITS/tests/scene4/test_multi_camera_alignment.py
@@ -332,6 +332,12 @@
                              its.caps.per_frame_control(props) and
                              its.caps.logical_multi_camera(props))
 
+        # Convert chart_distance for lens facing back
+        if props['android.lens.facing']:
+            # API spec defines +z is pointing out from screen
+            print 'lens facing BACK'
+            chart_distance *= -1
+
         # Find physical camera IDs and those that support RGB raw
         ids = its.caps.logical_multi_camera_physical_ids(props)
         props_physical = {}
@@ -506,10 +512,6 @@
         # Convert circle centers to real world coordinates
         x_w = {}
         y_w = {}
-        if props['android.lens.facing']:
-            # API spec defines +z is pointing out from screen
-            print 'lens facing BACK'
-            chart_distance *= -1
         for i in [i_ref, i_2nd]:
             x_w[i], y_w[i] = convert_to_world_coordinates(
                     circle[i][0], circle[i][1], r[i], t[i], k[i],
diff --git a/apps/CtsVerifier/AndroidManifest.xml b/apps/CtsVerifier/AndroidManifest.xml
index db3ba0b..0703a59 100644
--- a/apps/CtsVerifier/AndroidManifest.xml
+++ b/apps/CtsVerifier/AndroidManifest.xml
@@ -3509,7 +3509,19 @@
         </activity>
 
         <activity android:name=".audio.USBAudioPeripheralButtonsActivity"
-                  android:label="@string/audio_uap_buttons_test">
+            android:label="@string/audio_uap_buttons_test">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.cts.intent.category.MANUAL_TEST" />
+            </intent-filter>
+            <meta-data android:name="test_category" android:value="@string/test_category_audio" />
+            <meta-data android:name="test_required_features" android:value="android.hardware.usb.host" />
+            <meta-data android:name="test_excluded_features"
+                android:value="android.hardware.type.television:android.software.leanback:android.hardware.type.watch:android.hardware.type.automotive" />
+        </activity>
+
+        <activity android:name=".audio.USBRestrictRecordAActivity"
+                  android:label="@string/audio_usb_restrict_record_test">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.cts.intent.category.MANUAL_TEST" />
diff --git a/apps/CtsVerifier/res/layout/usb_restrictrecord.xml b/apps/CtsVerifier/res/layout/usb_restrictrecord.xml
new file mode 100644
index 0000000..827bdbc
--- /dev/null
+++ b/apps/CtsVerifier/res/layout/usb_restrictrecord.xml
@@ -0,0 +1,26 @@
+<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
+android:layout_width="match_parent"
+android:layout_height="match_parent"
+android:id="@+id/scrollView"
+style="@style/RootLayoutPadding">
+
+<LinearLayout android:orientation="vertical"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+
+    <TextView
+        android:text="@string/usb_restrictrecord_instructions"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/usb_restrictrecord_instructions"/>
+
+    <Button
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="Test"
+        android:id="@+id/test_button"/>
+
+    <include layout="@layout/pass_fail_buttons"/>
+
+</LinearLayout>
+</ScrollView>
\ No newline at end of file
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index 5635493..3df427f 100755
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -4621,6 +4621,36 @@
     <string name="uapButtonTestInstructions">Connect the USB Audio headset with buttons
         and press each transport/media button in turn.</string>
 
+    <string name="audio_usb_restrict_record_test">USB Audio Restrict Record Access Test</string>
+    <string name="audio_usb_restrict_record_entry">
+        This test checks that the appropriate warning message is displayed when an app which has
+        not been granted RECORD permission could potentially record audio through the raw USB
+        API. To test, connect a USB peripheral with CAPTURE capability and press the "Test" button.
+        The access permission API should contain a warning message about potential dangerous
+        access. If so, the test passes.
+    </string>
+
+    <string name="audio_usb_restrict_permission_info">
+        The test can only be run with Microphone permission DENIED.\n\n
+        To run this test:\n
+        &#160;&#160;Exit CTS-Verifier\n
+        &#160;&#160;Go to Android Settings\n
+        &#160;&#160;Select Apps &amp; notifications\n
+        &#160;&#160;Select CTS Verifier\n
+        &#160;&#160;Select Permissions\n
+        &#160;&#160;Deny Microphone permission\n
+        &#160;&#160;Run this test\n
+        When complete:\n
+        &#160;&#160;Exit CTS-Verifier\n
+        &#160;&#160;Return to Permissions Settings for CTS Verifier\n
+        &#160;&#160;grant Microphone permission
+    </string>
+    <string name="usb_restrictrecord_instructions">
+        Permissions for CTS Verifier are correctly set to run this test.\n\n
+        Connect a USB peripheral with CAPTURE capability. Press the "Test" button and verify that
+        a warning is shown in the device access UI.
+    </string>
+
     <string name="uapButtonsBtnALbl">Button A - play/pause</string>
     <string name="uapButtonsBtnBLbl">Button B - volume up (+)</string>
     <string name="uapButtonsBtnCLbl">Button C - volume down (-)</string>
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
index 9378596..bf1f306 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/AbstractTestListActivity.java
@@ -17,7 +17,6 @@
 package com.android.cts.verifier;
 
 import com.android.cts.verifier.TestListAdapter.TestListItem;
-
 import android.app.ListActivity;
 import android.content.Intent;
 import android.content.res.Configuration;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
index 4dd7777..78751d2 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/TestListActivity.java
@@ -69,7 +69,9 @@
                     if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
                         requestPermissions(packageInfo.requestedPermissions,
                                 CTS_VERIFIER_PERMISSION_REQUEST);
-                        return;
+                        /* don't return here. Some tests (i.e. USB Restrict Access test)
+                         * which need to run even if permissions are incomplete.
+                         */
                     }
                 }
             }
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
index 24e273c..984e1ee 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/AudioAEC.java
@@ -248,7 +248,8 @@
                 startTest();
                 break;
             case R.id.audio_aec_mandatory_no:
-                enableUILayout(mLinearLayout,true);
+                enableUILayout(mLinearLayout,false);
+                getPassButton().setEnabled(true);
                 mButtonMandatoryNo.setEnabled(false);
                 mButtonMandatoryYes.setEnabled(false);
                 mMandatory = false;
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java
new file mode 100644
index 0000000..d51ea2c
--- /dev/null
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/audio/USBRestrictRecordAActivity.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.verifier.audio;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.UsbDevice;
+import android.hardware.usb.UsbManager;
+import android.Manifest;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.View;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import java.util.Collection;
+import java.util.HashMap;
+
+import com.android.cts.verifier.PassFailButtons;
+import com.android.cts.verifier.R;  // needed to access resource in CTSVerifier project namespace.
+
+/*
+ * This tests the USB Restrict Record functionality for the explicit USB device open case
+ *   (case "A").
+ * The other 2 cases are:
+ *   A SINGLE activity is invoked when a USB device is plugged in. (Case B)
+ *   ONE OF A MULTIPLE activities is iUSBRestrictedRecordAActivity. (Case C)
+ *
+ * We are using simple single-character distiguishes to avoid really long class names.
+ */
+public class USBRestrictRecordAActivity extends PassFailButtons.Activity {
+    private static final String TAG = "USBRestrictRecordAActivity";
+    private static final boolean DEBUG = false;
+
+    private LocalClickListener mButtonClickListener = new LocalClickListener();
+
+    private Context mContext;
+
+    // Test MUST be run WITHOUT record pemission
+    private boolean mHasRecordPermission;
+
+    // System USB stuff
+    private UsbManager mUsbManager;
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.usb_restrictrecord);
+
+        findViewById(R.id.test_button).setOnClickListener(mButtonClickListener);
+
+        mContext = this;
+
+        mUsbManager = (UsbManager)getSystemService(Context.USB_SERVICE);
+
+        setPassFailButtonClickListeners();
+        getPassButton().setEnabled(false);
+        setInfoResources(R.string.audio_usb_restrict_record_test,
+                R.string.audio_usb_restrict_record_entry, -1);
+
+        mHasRecordPermission = hasRecordPermission();
+
+        if (mHasRecordPermission) {
+            TextView tx = findViewById(R.id.usb_restrictrecord_instructions);
+            tx.setText(getResources().getString(R.string.audio_usb_restrict_permission_info));
+        }
+        findViewById(R.id.test_button).setEnabled(!mHasRecordPermission);
+    }
+
+    private boolean hasRecordPermission() {
+        try {
+            PackageManager pm = getPackageManager();
+            PackageInfo packageInfo = pm.getPackageInfo(
+                    getApplicationInfo().packageName, PackageManager.GET_PERMISSIONS);
+
+            if (packageInfo.requestedPermissions != null) {
+                for (String permission : packageInfo.requestedPermissions) {
+                    if (permission.equals(Manifest.permission.RECORD_AUDIO)) {
+                        return checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED;
+                    }
+                }
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.e(TAG, "Unable to load package's permissions", e);
+            Toast.makeText(this, R.string.runtime_permissions_error, Toast.LENGTH_SHORT).show();
+        }
+        return false;
+    }
+
+    public class LocalClickListener implements View.OnClickListener {
+        @Override
+        public void onClick(View view) {
+            int id = view.getId();
+            switch (id) {
+                case R.id.test_button:
+                    connectUSB(mContext);
+                    break;
+            }
+        }
+    }
+
+    private class ConnectDeviceBroadcastReceiver extends BroadcastReceiver {
+        private final String TAG = "ConnectDeviceBroadcastReceiver";
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            String action = intent.getAction();
+            if (ACTION_USB_PERMISSION.equals(action)) {
+                synchronized (this) {
+                    getPassButton().setEnabled(true);
+
+                    // These messages don't really matter
+                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+                        Toast.makeText(mContext, "Permission Granted.", Toast.LENGTH_SHORT).show();
+                    }
+                    else {
+                        Toast.makeText(mContext, "Permission Denied.", Toast.LENGTH_SHORT).show();
+                    }
+                }
+            }
+        }
+    }
+
+    private static final String ACTION_USB_PERMISSION = "com.android.usbdescriptors.USB_PERMISSION";
+
+    public void connectUSB(Context context) {
+        HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
+        Collection<UsbDevice> deviceCollection = deviceList.values();
+        Object[] devices = deviceCollection.toArray();
+        if (devices.length > 0) {
+            UsbDevice theDevice = (UsbDevice) devices[0];
+
+            PendingIntent permissionIntent =
+                    PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
+
+            IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+            ConnectDeviceBroadcastReceiver usbReceiver =
+                    new ConnectDeviceBroadcastReceiver();
+            context.registerReceiver(usbReceiver, filter);
+
+            mUsbManager.requestPermission(theDevice, permissionIntent);
+        }
+    }
+}
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
index c576253..7165728 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleCommon.java
@@ -22,11 +22,8 @@
 import java.util.Map;
 
 class CtsAngleCommon {
-    private static final int TEST_WAIT_TIME_MS = 1000;
-
     // General
     static final int NUM_ATTEMPTS = 5;
-    static final int APPLY_SLEEP_MSEC = 500;
     static final int REATTEMPT_SLEEP_MSEC = 5000;
 
     // Settings.Global
@@ -92,14 +89,18 @@
 
     static void setGlobalSetting(ITestDevice device, String globalSetting, String value) throws Exception {
         device.setSetting("global", globalSetting, value);
+        device.executeShellCommand("am refresh-settings-cache");
     }
 
     static void clearSettings(ITestDevice device) throws Exception {
+        // Cached Activity Manager settings
         setGlobalSetting(device, SETTINGS_GLOBAL_ALL_USE_ANGLE, "0");
         setGlobalSetting(device, SETTINGS_GLOBAL_ANGLE_IN_USE_DIALOG_BOX, "0");
         setGlobalSetting(device, SETTINGS_GLOBAL_DRIVER_PKGS, "\"\"");
         setGlobalSetting(device, SETTINGS_GLOBAL_DRIVER_VALUES, "\"\"");
         setGlobalSetting(device, SETTINGS_GLOBAL_WHITELIST, "\"\"");
+
+        // Properties
         setProperty(device, PROPERTY_TEMP_RULES_FILE, "\"\"");
     }
 
@@ -110,13 +111,9 @@
     }
 
     static void startActivity(ITestDevice device, String action) throws Exception {
-        // Pause for a moment for the settings to propagate, with the hope that adb and the ANGLE
-        // APK Global.Settings updates are the same for everyone.
-        Thread.sleep(TEST_WAIT_TIME_MS);
         // Run the ANGLE activity so it'll clear up any 'default' settings.
         device.executeShellCommand("am start --user " + device.getCurrentUser() +
                 " -S -W -a \"" + action + "\"");
-        Thread.sleep(TEST_WAIT_TIME_MS);
     }
 
     static void stopPackage(ITestDevice device, String pkgName) throws Exception {
@@ -129,22 +126,4 @@
     static void setProperty(ITestDevice device, String property, String value) throws Exception {
         device.executeShellCommand("setprop " + property + " " + value);
     }
-
-    /**
-     * Wait for a bit for things to settle down before running the device tests.
-     * @param pkgName
-     * @param testClassName
-     * @param testMethodName
-     * @return
-     * @throws Exception
-     */
-    static boolean waitThenRunDeviceTests(BaseHostJUnit4Test test,
-            String pkgName,
-            String testClassName,
-            String testMethodName) throws Exception {
-        // Pause for a moment for the settings to propagate, with the hope that adb and the ANGLE
-        // APK Global.Settings updates are the same for everyone.
-        Thread.sleep(TEST_WAIT_TIME_MS);
-        return test.runDeviceTests(pkgName, testClassName, testMethodName);
-    }
 }
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
index bbce276..b63dd99 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleDeveloperOptionHostTest.java
@@ -44,38 +44,12 @@
         setGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS, pkgName);
         setGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES, driverValue);
 
-        // SETTINGS_GLOBAL_DRIVER_PKGS
-        for (int i = 0; i < NUM_ATTEMPTS; i++)
-        {
-            setGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS, pkgName);
-            Thread.sleep(APPLY_SLEEP_MSEC);
-            String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
-            if (devOption.equals(pkgName))
-            {
-                break;
-            }
-            Thread.sleep(REATTEMPT_SLEEP_MSEC);
-        }
-
         String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_PKGS);
         Assert.assertEquals(
                 "Developer option '" + SETTINGS_GLOBAL_DRIVER_PKGS +
                         "' was not set correctly: '" + devOption + "'",
                 pkgName, devOption);
 
-        // SETTINGS_GLOBAL_DRIVER_VALUES
-        for (int i = 0; i < NUM_ATTEMPTS; i++)
-        {
-            setGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES, driverValue);
-            Thread.sleep(APPLY_SLEEP_MSEC);
-            devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
-            if (devOption.equals(driverValue))
-            {
-                break;
-            }
-            Thread.sleep(REATTEMPT_SLEEP_MSEC);
-        }
-
         devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_DRIVER_VALUES);
         Assert.assertEquals(
                 "Developer option '" + SETTINGS_GLOBAL_DRIVER_VALUES +
@@ -93,7 +67,7 @@
         CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
                 driver + ") with method '" + sDriverTestMethodMap.get(driver) + "'");
 
-        waitThenRunDeviceTests(this, pkgName, pkgName + "." + ANGLE_DRIVER_TEST_CLASS,
+        runDeviceTests(pkgName, pkgName + "." + ANGLE_DRIVER_TEST_CLASS,
                 sDriverTestMethodMap.get(driver));
     }
 
@@ -139,10 +113,10 @@
 
         setGlobalSetting(getDevice(), SETTINGS_GLOBAL_ALL_USE_ANGLE, "1");
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_ANGLE_METHOD);
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                 ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_ANGLE_METHOD);
     }
@@ -159,7 +133,7 @@
         setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG,
                 sDriverGlobalSettingMap.get(OpenGlDriverChoice.DEFAULT));
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_DEFAULT_METHOD);
     }
@@ -176,7 +150,7 @@
         setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG,
                 sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE));
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_ANGLE_METHOD);
     }
@@ -193,7 +167,7 @@
         setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG,
                 sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_NATIVE_METHOD);
     }
@@ -212,11 +186,11 @@
                         ANGLE_DRIVER_TEST_SEC_PKG,
                 sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE));
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_DEFAULT_METHOD);
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                 ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_DEFAULT_METHOD);
     }
@@ -232,7 +206,7 @@
 
         setAndValidateAngleDevOptionPkgDriver(ANGLE_DRIVER_TEST_PKG, "timtim");
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_DEFAULT_METHOD);
     }
@@ -274,11 +248,11 @@
                 sDriverGlobalSettingMap.get(OpenGlDriverChoice.ANGLE) + "," +
                         sDriverGlobalSettingMap.get(OpenGlDriverChoice.NATIVE));
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_ANGLE_METHOD);
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                 ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_NATIVE_METHOD);
     }
@@ -311,7 +285,7 @@
                 CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
                         firstDriver + ") with method '" + sDriverTestMethodMap.get(firstDriver) + "'");
 
-                waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+                runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                         ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                         sDriverTestMethodMap.get(firstDriver));
 
@@ -325,7 +299,7 @@
                 CLog.logAndDisplay(LogLevel.INFO, "Validating driver selection (" +
                         secondDriver + ") with method '" + sDriverTestMethodMap.get(secondDriver) + "'");
 
-                waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+                runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                         ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                         sDriverTestMethodMap.get(secondDriver));
 
@@ -337,7 +311,7 @@
                 CLog.logAndDisplay(LogLevel.INFO, "Validating: PKG name = '" +
                         devOptionPkg + "', driver value = '" + devOptionValue + "'");
 
-                waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+                runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                         ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                         ANGLE_DRIVER_TEST_ANGLE_METHOD);
             }
diff --git a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java b/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
index 50f55b0..1f7f06e 100644
--- a/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
+++ b/hostsidetests/angle/src/android/angle/cts/CtsAngleRulesFileTest.java
@@ -63,17 +63,7 @@
 
     private void setAndValidateAngleDevOptionWhitelist(String whiteList) throws Exception {
         // SETTINGS_GLOBAL_WHITELIST
-        for (int i = 0; i < NUM_ATTEMPTS; i++)
-        {
-            setGlobalSetting(getDevice(), SETTINGS_GLOBAL_WHITELIST, whiteList);
-            Thread.sleep(APPLY_SLEEP_MSEC);
-            String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_WHITELIST);
-            if (devOption.equals(whiteList))
-            {
-                break;
-            }
-            Thread.sleep(REATTEMPT_SLEEP_MSEC);
-        }
+        setGlobalSetting(getDevice(), SETTINGS_GLOBAL_WHITELIST, whiteList);
 
         String devOption = getGlobalSetting(getDevice(), SETTINGS_GLOBAL_WHITELIST);
         Assert.assertEquals(
@@ -112,7 +102,7 @@
 
         installPackage(ANGLE_DRIVER_TEST_APP);
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_NATIVE_METHOD);
     }
@@ -129,11 +119,11 @@
         installPackage(ANGLE_DRIVER_TEST_APP);
         installPackage(ANGLE_DRIVER_TEST_SEC_APP);
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_PKG,
                 ANGLE_DRIVER_TEST_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_ANGLE_METHOD);
 
-        waitThenRunDeviceTests(this, ANGLE_DRIVER_TEST_SEC_PKG,
+        runDeviceTests(ANGLE_DRIVER_TEST_SEC_PKG,
                 ANGLE_DRIVER_TEST_SEC_PKG + "." + ANGLE_DRIVER_TEST_CLASS,
                 ANGLE_DRIVER_TEST_NATIVE_METHOD);
     }
diff --git a/hostsidetests/appcompat/compatchanges/app/AndroidManifest.xml b/hostsidetests/appcompat/compatchanges/app/AndroidManifest.xml
index 08553c7..28b33d2 100644
--- a/hostsidetests/appcompat/compatchanges/app/AndroidManifest.xml
+++ b/hostsidetests/appcompat/compatchanges/app/AndroidManifest.xml
@@ -16,8 +16,10 @@
 
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.cts.appcompat">
-
-    <application>
+    <!-- targetSdkVersion for this test must be below 1234 -->
+    <uses-sdk android:targetSdkVersion="29"/>
+    <application
+        android:debuggable="true">
         <uses-library android:name="android.test.runner" />
     </application>
 
diff --git a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/CompatChangesTest.java b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/CompatChangesTest.java
index 1c9fe1b..7025a96 100644
--- a/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/CompatChangesTest.java
+++ b/hostsidetests/appcompat/compatchanges/app/src/com/android/cts/appcompat/CompatChangesTest.java
@@ -43,6 +43,7 @@
  */
 @RunWith(AndroidJUnit4.class)
 public final class CompatChangesTest {
+  private static final long CTS_SYSTEM_API_CHANGEID = 149391281;
   @Before
   public void setUp() {
     InstrumentationRegistry.getInstrumentation().getUiAutomation()
@@ -58,40 +59,40 @@
   /* Test run by CompatChangesSystemApiTest.testIsChangeEnabled */
   @Test
   public void isChangeEnabled_changeEnabled() {
-    assertThat(CompatChanges.isChangeEnabled(1L)).isTrue();
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID)).isTrue();
   }
 
   /* Test run by CompatChangesSystemApiTest.testIsChangeEnabledPackageName */
   @Test
   public void isChangeEnabledPackageName_changeEnabled() {
     Context context = InstrumentationRegistry.getTargetContext();
-    assertThat(CompatChanges.isChangeEnabled(1L, context.getPackageName(),
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID, context.getPackageName(),
             context.getUser())).isTrue();
   }
 
   /* Test run by CompatChangesSystemApiTest.testIsChangeEnabledUid */
   @Test
   public void isChangeEnabledUid_changeEnabled() {
-    assertThat(CompatChanges.isChangeEnabled(1L, Process.myUid())).isTrue();
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID, Process.myUid())).isTrue();
   }
 
   /* Test run by CompatChangesSystemApiTest.testIsChangeDisabled */
   @Test
   public void isChangeEnabled_changeDisabled() {
-    assertThat(CompatChanges.isChangeEnabled(1L)).isFalse();
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID)).isFalse();
   }
 
   /* Test run by CompatChangesSystemApiTest.testIsChangeDisabledPackageName */
   @Test
   public void isChangeEnabledPackageName_changeDisabled() {
     Context context = InstrumentationRegistry.getTargetContext();
-    assertThat(CompatChanges.isChangeEnabled(1L, context.getPackageName(),
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID, context.getPackageName(),
             context.getUser())).isFalse();
   }
 
   /* Test run by CompatChangesSystemApiTest.testIsChangeDisabledUid */
   @Test
   public void isChangeEnabledUid_changeDisabled() {
-    assertThat(CompatChanges.isChangeEnabled(1L, Process.myUid())).isFalse();
+    assertThat(CompatChanges.isChangeEnabled(CTS_SYSTEM_API_CHANGEID, Process.myUid())).isFalse();
   }
 }
diff --git a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
index 6f57aa8..699af1a 100644
--- a/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
+++ b/hostsidetests/appcompat/compatchanges/src/com/android/cts/appcompat/CompatChangesSystemApiTest.java
@@ -36,6 +36,8 @@
     protected static final String TEST_APK = "CtsHostsideCompatChangeTestsApp.apk";
     protected static final String TEST_PKG = "com.android.cts.appcompat";
 
+    private static final long CTS_SYSTEM_API_CHANGEID = 149391281;
+
     @Override
     protected void setUp() throws Exception {
         installPackage(TEST_APK, true);
@@ -43,39 +45,39 @@
 
     public void testIsChangeEnabled() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest", "isChangeEnabled_changeEnabled",
-                /*enabledChanges*/ImmutableSet.of(1L),
+                /*enabledChanges*/ImmutableSet.of(CTS_SYSTEM_API_CHANGEID),
                 /*disabledChanges*/ ImmutableSet.of());
     }
 
     public void testIsChangeEnabledPackageName() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
                 "isChangeEnabledPackageName_changeEnabled",
-                /*enabledChanges*/ImmutableSet.of(1L),
+                /*enabledChanges*/ImmutableSet.of(CTS_SYSTEM_API_CHANGEID),
                 /*disabledChanges*/ ImmutableSet.of());
     }
 
     public void testIsChangeEnabledUid() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest", "isChangeEnabledUid_changeEnabled",
-                /*enabledChanges*/ImmutableSet.of(1L),
+                /*enabledChanges*/ImmutableSet.of(CTS_SYSTEM_API_CHANGEID),
                 /*disabledChanges*/ ImmutableSet.of());
     }
 
     public void testIsChangeDisabled() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest", "isChangeEnabled_changeDisabled",
                 /*enabledChanges*/ImmutableSet.of(),
-                /*disabledChanges*/ ImmutableSet.of(1L));
+                /*disabledChanges*/ ImmutableSet.of(CTS_SYSTEM_API_CHANGEID));
     }
 
     public void testIsChangeDisabledPackageName() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest",
                 "isChangeEnabledPackageName_changeDisabled",
                 /*enabledChanges*/ImmutableSet.of(),
-                /*disabledChanges*/ ImmutableSet.of(1L));
+                /*disabledChanges*/ ImmutableSet.of(CTS_SYSTEM_API_CHANGEID));
     }
 
     public void testIsChangeDisabledUid() throws Exception {
         runDeviceCompatTest(TEST_PKG, ".CompatChangesTest", "isChangeEnabledUid_changeDisabled",
                 /*enabledChanges*/ImmutableSet.of(),
-                /*disabledChanges*/ ImmutableSet.of(1L));
+                /*disabledChanges*/ ImmutableSet.of(CTS_SYSTEM_API_CHANGEID));
     }
 }
diff --git a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
index 906cfed..38a76d9 100644
--- a/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
+++ b/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
@@ -31,6 +31,7 @@
 import org.junit.After;
 import org.junit.Assume;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -198,11 +199,12 @@
     }
 
     /**
-     * Verify that app with WRITE_EXTERNAL can leave gifts in external storage
-     * directories belonging to other apps, and those apps can read.
+     * Verify that app without REQUEST_INSTALL_PACKAGES can't access obb
+     * directories belonging to other apps.
      */
+    @Ignore("Re-enable as part of b/148918640")
     @Test
-    public void testExternalStorageGifts() throws Exception {
+    public void testCantAccessOtherObbDirs() throws Exception {
         try {
             wipePrimaryExternalStorage();
 
@@ -211,18 +213,17 @@
             getDevice().uninstallPackage(WRITE_PKG);
             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
 
-            // We purposefully delay the installation of the reading apps to
-            // verify that the daemon correctly invalidates any caches.
             assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
-            for (int user : mUsers) {
-                runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest", "testGifts", user);
-            }
-
             assertNull(getDevice().installPackage(getTestAppFile(NONE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
+
             for (int user : mUsers) {
-                runDeviceTests(READ_PKG, READ_PKG + ".ReadGiftTest", "testGifts", user);
-                runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testGifts", user);
+                runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteGiftTest",
+                        "testCantAccessOtherObbDirs", user);
+                runDeviceTests(READ_PKG, READ_PKG + ".ReadGiftTest", "testCantAccessOtherObbDirs",
+                        user);
+                runDeviceTests(NONE_PKG, NONE_PKG + ".GiftTest", "testCantAccessOtherObbDirs",
+                        user);
             }
         } finally {
             getDevice().uninstallPackage(NONE_PKG);
@@ -231,8 +232,12 @@
         }
     }
 
+    /**
+     * Verify that app with REQUEST_INSTALL_PACKAGES can leave gifts in obb
+     * directories belonging to other apps, and those apps can read.
+     */
     @Test
-    public void testExternalStorageObbGifts() throws Exception {
+    public void testCanAccessOtherObbDirs() throws Exception {
         try {
             wipePrimaryExternalStorage();
 
@@ -359,8 +364,7 @@
     }
 
     /**
-     * Test that apps with read permissions see the appropriate permissions
-     * when apps with r/w permission levels move around their files.
+     * Test that apps with read permissions see the appropriate permissions.
      */
     @Test
     public void testMultiViewMoveConsistency() throws Exception {
@@ -369,10 +373,8 @@
 
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(READ_PKG);
-            getDevice().uninstallPackage(WRITE_PKG);
             final String[] options = {AbiUtils.createAbiFlag(getAbi().getName())};
 
-            assertNull(getDevice().installPackage(getTestAppFile(WRITE_APK), false, options));
             assertNull(getDevice().installPackage(getTestAppFile(READ_APK), false, options));
 
             for (int user : mUsers) {
@@ -382,25 +384,14 @@
                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
             }
 
-            for (int user : mUsers) {
-                runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteMultiViewTest", "testMoveAway", user);
-            }
-            for (int user : mUsers) {
-                runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testROAccess", user);
-            }
-
             // for fuse file system
             Thread.sleep(10000);
             for (int user : mUsers) {
-                runDeviceTests(WRITE_PKG, WRITE_PKG + ".WriteMultiViewTest", "testMoveBack", user);
-            }
-            for (int user : mUsers) {
                 runDeviceTests(READ_PKG, READ_PKG + ".ReadMultiViewTest", "testRWAccess", user);
             }
         } finally {
             getDevice().uninstallPackage(NONE_PKG);
             getDevice().uninstallPackage(READ_PKG);
-            getDevice().uninstallPackage(WRITE_PKG);
         }
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
index 7ac42bd..88601e5 100644
--- a/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
+++ b/hostsidetests/appsecurity/test-apps/EncryptionApp/src/com/android/cts/encryptionapp/EncryptionAppTest.java
@@ -44,13 +44,13 @@
 import android.provider.Settings;
 import android.support.test.uiautomator.UiDevice;
 import android.test.InstrumentationTestCase;
-import android.text.format.DateUtils;
 import android.util.Log;
 import android.view.KeyEvent;
 
 import com.android.compatibility.common.util.TestUtils;
 
 import java.io.File;
+import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -259,7 +259,8 @@
         assertQuery(2, MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE);
 
         if (Environment.isExternalStorageEmulated()) {
-            assertEquals(Environment.MEDIA_UNMOUNTED, Environment.getExternalStorageState());
+            assertThat(Environment.getExternalStorageState())
+                    .isIn(Arrays.asList(Environment.MEDIA_UNMOUNTED, Environment.MEDIA_REMOVED));
 
             final File expected = null;
             assertEquals(expected, mCe.getExternalCacheDir());
@@ -417,8 +418,19 @@
 
     private boolean queryFileExists(Uri fileUri) {
         Cursor c = mDe.getContentResolver().query(fileUri, null, null, null, null);
+        if (c == null) {
+            Log.w(TAG, "Couldn't query for file " + fileUri + "; returning false");
+            return false;
+        }
+
         c.moveToFirst();
+
         int colIndex = c.getColumnIndex("exists");
+        if (colIndex < 0) {
+            Log.e(TAG, "Column 'exists' does not exist; returning false");
+            return false;
+        }
+
         return c.getInt(colIndex) == 1;
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
index 3fc9cae..507693e 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/CommonExternalStorageTest.java
@@ -177,22 +177,6 @@
         return targetFiles;
     }
 
-    /**
-     * Return a set of several package-specific external storage paths pointing
-     * at "gift" files designed to be exchanged with the target package.
-     */
-    public static List<File> getAllPackageSpecificGiftPaths(Context context,
-            String targetPackageName) {
-        final List<File> files = getPrimaryPackageSpecificPaths(context);
-        final List<File> targetFiles = new ArrayList<>();
-        for (File file : files) {
-            final File targetFile = new File(
-                    file.getAbsolutePath().replace(context.getPackageName(), targetPackageName));
-            targetFiles.add(new File(targetFile, targetPackageName + ".gift"));
-        }
-        return targetFiles;
-    }
-
     public static List<File> getPrimaryPackageSpecificPaths(Context context) {
         final List<File> paths = new ArrayList<File>();
         Collections.addAll(paths, context.getExternalCacheDir());
diff --git a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
index b8d5da4..3368c31 100644
--- a/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ExternalStorageApp/src/com/android/cts/externalstorageapp/GiftTest.java
@@ -18,11 +18,9 @@
 
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNotPresent;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificObbGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
 
@@ -33,24 +31,13 @@
 
 public class GiftTest extends AndroidTestCase {
     /**
-     * Verify we can read only our gifts.
+     * Verify we can't read other obb dirs.
      */
-    public void testGifts() throws Exception {
-        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
-        for (File none : noneList) {
-            assertFileReadWriteAccess(none);
-            assertEquals(100, readInt(none));
-        }
-
-        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
+    public void testCantAccessOtherObbDirs() throws Exception {
+        final List<File> readList = getAllPackageSpecificObbGiftPaths(getContext(), PACKAGE_READ);
         for (File read : readList) {
             assertFileNoAccess(read);
         }
-
-        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
-        for (File write : writeList) {
-            assertFileNoAccess(write);
-        }
     }
 
     /**
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
index 78bb738..c9ef723 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadGiftTest.java
@@ -17,12 +17,8 @@
 package com.android.cts.readexternalstorageapp;
 
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadOnlyAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
+import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificObbGiftPaths;
 
 import android.test.AndroidTestCase;
 
@@ -31,25 +27,12 @@
 
 public class ReadGiftTest extends AndroidTestCase {
     /**
-     * Verify we can read all gifts.
+     * Verify we can't read other obb dirs.
      */
-    public void testGifts() throws Exception {
-        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+    public void testCantAccessOtherObbDirs() throws Exception {
+        final List<File> noneList = getAllPackageSpecificObbGiftPaths(getContext(), PACKAGE_NONE);
         for (File none : noneList) {
-            assertFileReadOnlyAccess(none);
-            assertEquals(100, readInt(none));
-        }
-
-        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
-        for (File read : readList) {
-            assertFileReadWriteAccess(read);
-            assertEquals(101, readInt(read));
-        }
-
-        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
-        for (File write : writeList) {
-            assertFileReadOnlyAccess(write);
-            assertEquals(102, readInt(write));
+            assertFileNoAccess(none);
         }
     }
 }
diff --git a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadMultiViewTest.java b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadMultiViewTest.java
index 6061117..9ba53dd 100644
--- a/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadMultiViewTest.java
+++ b/hostsidetests/appsecurity/test-apps/ReadExternalStorageApp/src/com/android/cts/readexternalstorageapp/ReadMultiViewTest.java
@@ -55,20 +55,4 @@
         assertEquals(Os.getuid(), Os.stat(ourTestDir.getAbsolutePath()).st_uid);
         assertEquals(Os.getuid(), Os.stat(testFile.getAbsolutePath()).st_uid);
     }
-
-    /**
-     * Verify that we have RO access to test.probe in PACKAGE_WRITE's cache.
-     */
-    public void testROAccess() throws Exception {
-        final File ourCache = getContext().getExternalCacheDir();
-        final File otherCache = new File(ourCache.getAbsolutePath()
-                .replace(getContext().getPackageName(), PACKAGE_WRITE));
-        final File otherTestDir = new File(otherCache, "testDir");
-        final File testFile = new File(otherTestDir, "test.probe");
-
-        assertFileReadOnlyAccess(testFile);
-        assertNotEqual(Os.getuid(), Os.stat(testFile.getAbsolutePath()).st_uid);
-        assertNotEqual(Os.getuid(), Os.stat(otherCache.getAbsolutePath()).st_uid);
-        assertNotEqual(Os.getuid(), Os.stat(otherTestDir.getAbsolutePath()).st_uid);
-    }
 }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
index 9419e3b..13818b7 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteExternalStorageTest.java
@@ -154,8 +154,8 @@
 
             assertTrue(path.getAbsolutePath().contains(packageName));
 
-            // Walk until we leave device, writing the whole way
-            while (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState(path))) {
+            // Walk until we reach package specific directory.
+            while (path.getAbsolutePath().contains(packageName)) {
                 assertDirReadWriteAccess(path);
                 path = path.getParentFile();
             }
@@ -168,16 +168,20 @@
     public void testMountStatusWalkingUpTree() {
         final File top = Environment.getExternalStorageDirectory();
         File path = getContext().getExternalCacheDir();
+        final String packageName = getContext().getPackageName();
 
         int depth = 0;
         while (depth++ < 32) {
-            assertDirReadWriteAccess(path);
-            assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState(path));
-
+            // Check read&write access for only package specific directories. We might not have
+            // read/write access for directories like /storage/emulated/0/Android and
+            // /storage/emulated/0/Android/<data|media|obb>.
+            if (path.getAbsolutePath().contains(packageName)) {
+                assertDirReadWriteAccess(path);
+                assertEquals(Environment.MEDIA_MOUNTED, Environment.getExternalStorageState(path));
+            }
             if (path.getAbsolutePath().equals(top.getAbsolutePath())) {
                 break;
             }
-
             path = path.getParentFile();
         }
 
@@ -328,7 +332,9 @@
             final File after = new File(next, name);
 
             Log.v(TAG, "Moving " + before + " to " + after);
-            Os.rename(before.getAbsolutePath(), after.getAbsolutePath());
+            // Os.rename will fail with EXDEV here, use renameTo which does copy delete behind the
+            // scenes
+            before.renameTo(after);
 
             cur = next;
         }
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
index 9f3b197..bd88fca 100644
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
+++ b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteGiftTest.java
@@ -18,11 +18,9 @@
 
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_NONE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_WRITE;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertDirNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileNoAccess;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificObbGiftPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.getAllPackageSpecificPaths;
 import static com.android.cts.externalstorageapp.CommonExternalStorageTest.readInt;
@@ -36,37 +34,12 @@
 
 public class WriteGiftTest extends AndroidTestCase {
     /**
-     * Leave gifts for other packages in their primary external cache dirs.
+     * Verify we can't read other obb dirs.
      */
-    public void testGifts() throws Exception {
-        final List<File> noneList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_NONE);
+    public void testCantAccessOtherObbDirs() throws Exception {
+        final List<File> noneList = getAllPackageSpecificObbGiftPaths(getContext(), PACKAGE_NONE);
         for (File none : noneList) {
-            none.getParentFile().mkdirs();
-            none.createNewFile();
-            assertFileReadWriteAccess(none);
-
-            writeInt(none, 100);
-            assertEquals(100, readInt(none));
-        }
-
-        final List<File> readList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_READ);
-        for (File read : readList) {
-            read.getParentFile().mkdirs();
-            read.createNewFile();
-            assertFileReadWriteAccess(read);
-
-            writeInt(read, 101);
-            assertEquals(101, readInt(read));
-        }
-
-        final List<File> writeList = getAllPackageSpecificGiftPaths(getContext(), PACKAGE_WRITE);
-        for (File write : writeList) {
-            write.getParentFile().mkdirs();
-            write.createNewFile();
-            assertFileReadWriteAccess(write);
-
-            writeInt(write, 102);
-            assertEquals(102, readInt(write));
+            assertFileNoAccess(none);
         }
     }
 
diff --git a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteMultiViewTest.java b/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteMultiViewTest.java
deleted file mode 100644
index e48c319..0000000
--- a/hostsidetests/appsecurity/test-apps/WriteExternalStorageApp/src/com/android/cts/writeexternalstorageapp/WriteMultiViewTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.cts.writeexternalstorageapp;
-
-import static android.test.MoreAsserts.assertNotEqual;
-
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.PACKAGE_READ;
-import static com.android.cts.externalstorageapp.CommonExternalStorageTest.assertFileReadWriteAccess;
-
-import android.os.SystemClock;
-import android.system.Os;
-
-import android.test.AndroidTestCase;
-import android.text.format.DateUtils;
-
-import android.util.Log;
-
-import java.io.File;
-import java.util.List;
-
-public class WriteMultiViewTest extends AndroidTestCase {
-    /**
-     * Move PACKAGE_READ's cache to our cache
-     */
-    public void testMoveAway() throws Exception {
-        final File ourCache = getContext().getExternalCacheDir();
-        final File otherCache = new File(ourCache.getAbsolutePath()
-                .replace(getContext().getPackageName(), PACKAGE_READ));
-        final File ourTestDir = new File(ourCache, "testDir");
-        final File otherTestDir = new File(otherCache, "testDir");
-        final File beforeFile = new File(otherTestDir, "test.probe");
-        final File afterFile = new File(ourTestDir, "test.probe");
-
-        Os.rename(otherTestDir.getAbsolutePath(), ourTestDir.getAbsolutePath());
-
-        assertEquals(Os.getuid(), Os.stat(ourCache.getAbsolutePath()).st_uid);
-        assertEquals(Os.getuid(), Os.stat(ourTestDir.getAbsolutePath()).st_uid);
-        assertEquals(Os.getuid(), Os.stat(afterFile.getAbsolutePath()).st_uid);
-    }
-
-    /**
-     * Move our cache to PACKAGE_READ's cache
-     */
-    public void testMoveBack() throws Exception {
-        final File ourCache = getContext().getExternalCacheDir();
-        final File otherCache = new File(ourCache.getAbsolutePath()
-                .replace(getContext().getPackageName(), PACKAGE_READ));
-        final File ourTestDir = new File(ourCache, "testDir");
-        final File otherTestDir = new File(otherCache, "testDir");
-        final File beforeFile = new File(ourTestDir, "test.probe");
-        final File afterFile = new File(otherTestDir, "test.probe");
-
-        Os.rename(ourTestDir.getAbsolutePath(), otherTestDir.getAbsolutePath());
-
-        // Sit around long enough for VFS cache to expire
-        SystemClock.sleep(15 * DateUtils.SECOND_IN_MILLIS);
-
-        assertNotEqual(Os.getuid(), Os.stat(otherCache.getAbsolutePath()).st_uid);
-        assertNotEqual(Os.getuid(), Os.stat(otherTestDir.getAbsolutePath()).st_uid);
-        assertNotEqual(Os.getuid(), Os.stat(afterFile.getAbsolutePath()).st_uid);
-    }
-}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
index 02b480a..5564c3a 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/AndroidManifest.xml
@@ -42,6 +42,8 @@
                 <category android:name="android.intent.category.DEFAULT"/>
             </intent-filter>
         </activity>
+
+        <activity android:name=".CrossProfileSameTaskLauncherActivity" android:exported="true"/>
     </application>
 
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_same_task_launcher.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_same_task_launcher.xml
new file mode 100644
index 0000000..8d9cf94
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/res/layout/cross_profile_same_task_launcher.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="match_parent">
+
+    <TextView
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="CrossProfileSameTaskLauncherActivity"
+    />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
index edce5c3..485aec8 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsPermissionToInteractTest.java
@@ -135,4 +135,12 @@
         assertThat(intent).isNull();
     }
 
+    /**
+     * Calls {@link CrossProfileApps#createRequestInteractAcrossProfilesIntent()}. This can then be
+     * used by host-side tests.
+     */
+    @Test
+    public void testCreateRequestInteractAcrossProfilesIntent_noAsserts() {
+        mCrossProfileApps.createRequestInteractAcrossProfilesIntent();
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
index 9852e53..be5c4b1 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileAppsStartActivityTest.java
@@ -24,6 +24,7 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 
+import android.app.Activity;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -36,7 +37,6 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject2;
 import android.support.test.uiautomator.Until;
-import android.util.Log;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -104,7 +104,7 @@
         intent.setComponent(MainActivity.getComponentName(mContext));
         ShellIdentityUtils.dropShellPermissionIdentity();
 
-        mCrossProfileApps.startActivity(intent, mTargetUser);
+        mCrossProfileApps.startActivity(intent, mTargetUser, /* callingActivity= */ null);
     }
 
     @Test
@@ -113,8 +113,11 @@
         intent.setComponent(MainActivity.getComponentName(mContext));
         ShellIdentityUtils.dropShellPermissionIdentity();
 
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
-                crossProfileApps -> crossProfileApps.startActivity(intent, mTargetUser), INTERACT_ACROSS_PROFILES);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
+                crossProfileApps -> crossProfileApps.startActivity(
+                        intent, mTargetUser, /* callingActivity= */ null),
+                INTERACT_ACROSS_PROFILES);
 
         // Look for the text view to verify that MainActivity is started.
         UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW)),
@@ -130,8 +133,11 @@
         intent.setComponent(MainActivity.getComponentName(mContext));
         ShellIdentityUtils.dropShellPermissionIdentity();
 
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
-                crossProfileApps -> crossProfileApps.startActivity(intent, mTargetUser), INTERACT_ACROSS_USERS);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
+                crossProfileApps -> crossProfileApps.startActivity(
+                        intent, mTargetUser, /* callingActivity= */ null),
+                INTERACT_ACROSS_USERS);
 
         // Look for the text view to verify that MainActivity is started.
         UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW)),
@@ -147,8 +153,11 @@
         intent.setComponent(MainActivity.getComponentName(mContext));
         ShellIdentityUtils.dropShellPermissionIdentity();
 
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
-                crossProfileApps -> crossProfileApps.startActivity(intent, mTargetUser), INTERACT_ACROSS_USERS_FULL);
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
+                crossProfileApps -> crossProfileApps.startActivity(
+                        intent, mTargetUser, /* callingActivity= */ null),
+                INTERACT_ACROSS_USERS_FULL);
 
         // Look for the text view to verify that MainActivity is started.
         UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW)),
@@ -164,9 +173,10 @@
         Intent nonMainActivityImplicitIntent = new Intent();
         nonMainActivityImplicitIntent.setAction(Intent.ACTION_VIEW);
 
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
                 crossProfileApps -> crossProfileApps.startActivity(
-                        nonMainActivityImplicitIntent, mTargetUser));
+                        nonMainActivityImplicitIntent, mTargetUser, /* callingActivity= */ null));
     }
 
     @Test
@@ -175,9 +185,10 @@
         mainActivityIntent.setComponent(MainActivity.getComponentName(mContext));
 
         try {
-            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                    mCrossProfileApps,
                     crossProfileApps -> mCrossProfileApps.startActivity(
-                            mainActivityIntent, mTargetUser));
+                            mainActivityIntent, mTargetUser, /* callingActivity= */ null));
 
             // Look for the text view to verify that MainActivity is started.
             UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW)),
@@ -196,9 +207,10 @@
         nonMainActivityIntent.setComponent(NonMainActivity.getComponentName(mContext));
 
         try {
-            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
+            ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                    mCrossProfileApps,
                     crossProfileApps -> mCrossProfileApps.startActivity(
-                            nonMainActivityIntent, mTargetUser));
+                            nonMainActivityIntent, mTargetUser, /* callingActivity= */ null));
 
             // Look for the text view to verify that NonMainActivity is started.
             UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW2)),
@@ -211,6 +223,47 @@
         }
     }
 
+    /**
+     * Starts an activity in the same task in the target user. Asserts that the activity is
+     * correctly started in the correct user, but the host-side test should verify that the tasks
+     * are the same using the log messages printed by each activity.
+     */
+    @Test
+    public void testStartActivityIntent_sameTaskByDefault() throws Exception {
+        try {
+            final Intent crossProfileSameTaskCheckerIntent = new Intent();
+            crossProfileSameTaskCheckerIntent.setComponent(
+                    CrossProfileSameTaskLauncherActivity.getComponentName(mContext));
+            crossProfileSameTaskCheckerIntent.putExtra(
+                    CrossProfileSameTaskLauncherActivity.TARGET_USER_EXTRA, mTargetUser);
+            mContext.startActivity(crossProfileSameTaskCheckerIntent);
+
+            // Look for the text view to verify that NonMainActivity is started.
+            UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW2)),
+                    TIMEOUT_WAIT_UI);
+            assertNotNull("Failed to start non-main activity in target user", textView);
+            assertEquals("Non-Main Activity is started in wrong user",
+                    String.valueOf(mUserSerialNumber), textView.getText());
+        } catch (Exception e) {
+            fail("unable to start cross-profile activity in the same task: " + e);
+        }
+    }
+
+    /**
+     * Calls {@link CrossProfileApps#startActivity(Intent, UserHandle, Activity)}. This can then be used by
+     * host-side tests.
+     */
+    @Test
+    public void testStartActivityByIntent_noAsserts() throws Exception {
+        Intent nonMainActivityIntent = new Intent();
+        nonMainActivityIntent.setComponent(NonMainActivity.getComponentName(mContext));
+
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
+                crossProfileApps -> mCrossProfileApps.startActivity(
+                        nonMainActivityIntent, mTargetUser, /* callingActivity= */ null));
+    }
+
     @Test
     public void testCanStartMainActivityByComponent() {
         try {
@@ -252,8 +305,10 @@
         Intent nonExportedActivityIntent = new Intent();
         nonExportedActivityIntent.setComponent(NonExportedActivity.getComponentName(mContext));
 
-        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mCrossProfileApps,
-                crossProfileApps -> mCrossProfileApps.startActivity(nonExportedActivityIntent, mTargetUser));
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                mCrossProfileApps,
+                crossProfileApps -> mCrossProfileApps.startActivity(
+                        nonExportedActivityIntent, mTargetUser, /* callingActivity= */ null));
 
         // Look for the text view to verify that NonExportedActivity is started.
         UiObject2 textView = mDevice.wait(Until.findObject(By.res(ID_USER_TEXTVIEW2)),
@@ -275,9 +330,8 @@
         otherPackageIntent.setComponent(new ComponentName(
                 "com.android.cts.launcherapps.simpleapp",
                 "com.android.cts.launcherapps.simpleapp.SimpleActivity"));
-        mCrossProfileApps.startActivity(otherPackageIntent,
-                mTargetUser
-        );
+        mCrossProfileApps.startActivity(
+                otherPackageIntent, mTargetUser, /* callingActivity= */ null);
     }
 
     @Test(expected = SecurityException.class)
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileSameTaskLauncherActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileSameTaskLauncherActivity.java
new file mode 100644
index 0000000..9d1f209
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/CrossProfileSameTaskLauncherActivity.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.crossprofileappstest;
+
+import android.app.Activity;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.CrossProfileApps;
+import android.os.Bundle;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.annotation.Nullable;
+
+import com.android.compatibility.common.util.ShellIdentityUtils;
+
+/**
+ * An activity that launches the {@link NonMainActivity} in a different user within the same task.
+ *
+ * <p>Logs its task ID with the following format:
+ * "CrossProfileSameTaskLauncherActivity#taskId#[taskId]#", where [taskId] is the actual task ID,
+ * such as NonMainActivity#taskId#4#.
+ */
+public class CrossProfileSameTaskLauncherActivity extends Activity {
+    static final String TARGET_USER_EXTRA = "TARGET_USER";
+
+    private static final String LOG_TAG = "CrossProfileSameTaskChe"; // 23 chars max
+
+    @Override
+    public void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final Intent intent = getIntent();
+        if (!intent.hasExtra(TARGET_USER_EXTRA)) {
+            throw new IllegalStateException(
+                    "ActivityForwarder started without the extra: " + TARGET_USER_EXTRA);
+        }
+        setContentView(R.layout.cross_profile_same_task_launcher);
+        Log.w(LOG_TAG, "CrossProfileSameTaskLauncherActivity#taskId#" + getTaskId() + "#");
+        final UserHandle targetUser = intent.getParcelableExtra(TARGET_USER_EXTRA);
+        final Intent nonMainActivityIntent = new Intent();
+        nonMainActivityIntent.setComponent(NonMainActivity.getComponentName(this));
+        ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(
+                getSystemService(CrossProfileApps.class),
+                crossProfileApps
+                        -> crossProfileApps.startActivity(nonMainActivityIntent, targetUser, this));
+    }
+
+    static ComponentName getComponentName(Context context) {
+        return new ComponentName(context, CrossProfileSameTaskLauncherActivity.class);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/NonMainActivity.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/NonMainActivity.java
index 4131a98..c2ad97c 100644
--- a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/NonMainActivity.java
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileAppsTest/src/com/android/cts/crossprofileappstest/NonMainActivity.java
@@ -21,14 +21,23 @@
 import android.os.Bundle;
 import android.os.Process;
 import android.os.UserManager;
+import android.util.Log;
 import android.widget.TextView;
 
+/**
+ * An activity that is not the main activity of the application.
+ *
+ * <p>Logs its task ID with the following format: "NonMainActivity#taskId#[taskId]#", where [taskId]
+ * is the actual task ID, such as NonMainActivity#taskId#4#.
+ */
 public class NonMainActivity extends Activity {
+    private static final String LOG_TAG = "NonMainActivity";
 
     @Override
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
         setContentView(R.layout.non_main);
+        Log.w(LOG_TAG, "NonMainActivity#taskId#" + getTaskId() + "#");
     }
 
     @Override
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp
new file mode 100644
index 0000000..805897d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "CtsCrossProfileEnabledApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
+    min_sdk_version: "29",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/AndroidManifest.xml
new file mode 100644
index 0000000..f3fde4c
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.crossprofileenabledapp">
+
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+
+    <application
+        android:crossProfile="true">
+        <receiver android:name=".CrossProfileEnabledAppReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.crossprofileenabledapp"
+                     android:label="Launcher Apps CTS Tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/src/com/android/cts/crossprofileenabledapp/CrossProfileEnabledAppReceiver.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/src/com/android/cts/crossprofileenabledapp/CrossProfileEnabledAppReceiver.java
new file mode 100644
index 0000000..feef28c
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledApp/src/com/android/cts/crossprofileenabledapp/CrossProfileEnabledAppReceiver.java
@@ -0,0 +1,15 @@
+package com.android.cts.crossprofileenabledapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+public class CrossProfileEnabledAppReceiver extends BroadcastReceiver {
+    private static final String TAG = "CrossProfileEnabledAppReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Slog.w(TAG, String.format("onReceive(%s)", intent.getAction()));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp
new file mode 100644
index 0000000..44d5732
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "CtsCrossProfileEnabledNoPermsApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
+    min_sdk_version: "29",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml
new file mode 100644
index 0000000..d8bc983
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/AndroidManifest.xml
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.crossprofileenablednopermsapp">
+
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
+    <application
+        android:crossProfile="true">
+        <receiver android:name=".CrossProfileEnabledNoPermsAppReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.crossprofileenablednopermsapp"
+                     android:label="Launcher Apps CTS Tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/src/com/android/cts/crossprofileenablednopermsapp/CrossProfileEnabledNoPermsAppReceiver.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/src/com/android/cts/crossprofileenablednopermsapp/CrossProfileEnabledNoPermsAppReceiver.java
new file mode 100644
index 0000000..25bb569
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileEnabledNoPermsApp/src/com/android/cts/crossprofileenablednopermsapp/CrossProfileEnabledNoPermsAppReceiver.java
@@ -0,0 +1,15 @@
+package com.android.cts.crossprofileenablednopermsapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+public class CrossProfileEnabledNoPermsAppReceiver extends BroadcastReceiver {
+    private static final String TAG = "CrossProfileEnabledNoPermsAppReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Slog.w(TAG, String.format("onReceive(%s)", intent.getAction()));
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp
new file mode 100644
index 0000000..7a6592d
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "CtsCrossProfileNotEnabledApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
+    min_sdk_version: "29",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/AndroidManifest.xml
new file mode 100644
index 0000000..6af733e
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/AndroidManifest.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.crossprofilenotenabledapp">
+
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"/>
+
+    <application
+        android:crossProfile="false">
+        <receiver android:name=".CrossProfileNotEnabledAppReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.crossprofilenotenabledapp"
+                     android:label="Launcher Apps CTS Tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/src/com/android/cts/crossprofilenotenabledapp/CrossProfileNotEnabledAppReceiver.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/src/com/android/cts/crossprofilenotenabledapp/CrossProfileNotEnabledAppReceiver.java
new file mode 100644
index 0000000..7d06c3b
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileNotEnabledApp/src/com/android/cts/crossprofilenotenabledapp/CrossProfileNotEnabledAppReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.crossprofilenotenabledapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+public class CrossProfileNotEnabledAppReceiver extends BroadcastReceiver {
+    private static final String TAG = "CrossProfileNotEnabledAppReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Slog.w(TAG, String.format("onReceive(%s)", intent.getAction()));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp
new file mode 100644
index 0000000..f3c4611
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/Android.bp
@@ -0,0 +1,35 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "CtsCrossProfileUserEnabledApp",
+    defaults: ["cts_defaults"],
+    srcs: ["src/**/*.java"],
+    libs: ["junit"],
+    static_libs: [
+        "androidx.legacy_legacy-support-v4",
+        "ctstestrunner-axt",
+        "compatibility-device-util-axt",
+        "androidx.test.rules",
+        "truth-prebuilt",
+        "ub-uiautomator",
+    ],
+    min_sdk_version: "29",
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/AndroidManifest.xml b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/AndroidManifest.xml
new file mode 100644
index 0000000..c10c617
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.cts.crossprofileuserenabledapp">
+
+    <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/>
+
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/>
+
+    <application
+        android:crossProfile="true">
+        <receiver android:name=".CrossProfileUserEnabledAppReceiver">
+            <intent-filter>
+                <action android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+                <action android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
+            </intent-filter>
+        </receiver>
+    </application>
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="com.android.cts.crossprofileuserenabledapp"
+                     android:label="Launcher Apps CTS Tests"/>
+</manifest>
diff --git a/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/src/com/android/cts/crossprofileuserenabledapp/CrossProfileUserEnabledAppReceiver.java b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/src/com/android/cts/crossprofileuserenabledapp/CrossProfileUserEnabledAppReceiver.java
new file mode 100644
index 0000000..75fe44c
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/CrossProfileTestApps/CrossProfileUserEnabledApp/src/com/android/cts/crossprofileuserenabledapp/CrossProfileUserEnabledAppReceiver.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.crossprofileuserenabledapp;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Slog;
+
+public class CrossProfileUserEnabledAppReceiver extends BroadcastReceiver {
+    private static final String TAG = "CrossProfileUserEnabledAppReceiver";
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        Slog.w(TAG, String.format("onReceive(%s)", intent.getAction()));
+    }
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementParentTest.java
new file mode 100644
index 0000000..0aa1a79
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AccountManagementParentTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.android.cts.deviceandprofileowner.BaseDeviceAdminTest.ADMIN_RECEIVER_COMPONENT;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.Context;
+import android.test.InstrumentationTestCase;
+
+public class AccountManagementParentTest extends InstrumentationTestCase {
+    private static final String SOME_ACCOUNT_TYPE = "com.example.account.type";
+
+    private DevicePolicyManager mDevicePolicyManager;
+    private Context mContext;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mContext = getInstrumentation().getContext();
+
+        mDevicePolicyManager = mContext.getSystemService(DevicePolicyManager.class);
+        assertNotNull(mDevicePolicyManager);
+    }
+
+    public void testSetAccountManagementDisabledOnParent() {
+        DevicePolicyManager parentDevicePolicyManager = getParentInstance();
+
+        parentDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT,
+                SOME_ACCOUNT_TYPE, true);
+        assertThat(
+                parentDevicePolicyManager.getAccountTypesWithManagementDisabled()).asList()
+                .containsExactly(SOME_ACCOUNT_TYPE);
+        // Ensure that account management is not restricted on the managed profile itself.
+        assertThat(mDevicePolicyManager.getAccountTypesWithManagementDisabled()).isEmpty();
+    }
+
+    public void testAccountManagementDisabled() {
+        assertThat(
+                mDevicePolicyManager.getAccountTypesWithManagementDisabled()).asList()
+                .containsExactly(SOME_ACCOUNT_TYPE);
+    }
+
+    public void testEnableAccountManagement() {
+        DevicePolicyManager parentDevicePolicyManager = getParentInstance();
+
+        parentDevicePolicyManager.setAccountManagementDisabled(ADMIN_RECEIVER_COMPONENT,
+                SOME_ACCOUNT_TYPE, false);
+        assertThat(parentDevicePolicyManager.getAccountTypesWithManagementDisabled()).isEmpty();
+    }
+
+    private DevicePolicyManager getParentInstance() {
+        assertThat(mDevicePolicyManager.isAdminActive(ADMIN_RECEIVER_COMPONENT)).isTrue();
+        assertThat(mDevicePolicyManager.isProfileOwnerApp(
+                ADMIN_RECEIVER_COMPONENT.getPackageName())).isTrue();
+        assertThat(mDevicePolicyManager.isOrganizationOwnedDeviceWithManagedProfile()).isTrue();
+
+        DevicePolicyManager parentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+        assertThat(parentDevicePolicyManager).isNotNull();
+
+        return parentDevicePolicyManager;
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AdminConfiguredNetworksTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AdminConfiguredNetworksTest.java
index 243a4a0..3a3dd62 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AdminConfiguredNetworksTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/AdminConfiguredNetworksTest.java
@@ -20,18 +20,18 @@
 
 public class AdminConfiguredNetworksTest extends BaseDeviceAdminTest {
 
-    public void testSetLockdownAdminConfiguredNetworks() {
-        mDevicePolicyManager.setLockdownAdminConfiguredNetworks(ADMIN_RECEIVER_COMPONENT,
+    public void testSetConfiguredNetworksLockdownState() {
+        mDevicePolicyManager.setConfiguredNetworksLockdownState(ADMIN_RECEIVER_COMPONENT,
                 true);
 
-        assertThat(mDevicePolicyManager.isLockdownAdminConfiguredNetworks(
+        assertThat(mDevicePolicyManager.hasLockdownAdminConfiguredNetworks(
                 ADMIN_RECEIVER_COMPONENT)).isTrue();
 
-        mDevicePolicyManager.setLockdownAdminConfiguredNetworks(ADMIN_RECEIVER_COMPONENT,
+        mDevicePolicyManager.setConfiguredNetworksLockdownState(ADMIN_RECEIVER_COMPONENT,
                 false);
 
-        assertThat(mDevicePolicyManager.isLockdownAdminConfiguredNetworks(
+        assertThat(mDevicePolicyManager.hasLockdownAdminConfiguredNetworks(
                 ADMIN_RECEIVER_COMPONENT)).isFalse();
     }
 
-}
+}
\ No newline at end of file
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
index bc33910..653fd57 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DelegatedCertInstallerTest.java
@@ -349,7 +349,7 @@
 
     private void assertResult(String testName, Boolean expectSuccess) throws InterruptedException {
         assertTrue("Cert installer did not respond in time.",
-                mAvailableResultSemaphore.tryAcquire(10, TimeUnit.SECONDS));
+                mAvailableResultSemaphore.tryAcquire(60, TimeUnit.SECONDS));
         synchronized (this) {
             if (expectSuccess) {
                 assertTrue(testName + " failed unexpectedly.", mReceivedResult);
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingParentTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingParentTest.java
new file mode 100644
index 0000000..6eceb87
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingParentTest.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import android.app.admin.DevicePolicyManager;
+import android.os.UserManager;
+
+public class DevicePolicyLoggingParentTest extends BaseDeviceAdminTest {
+
+    private DevicePolicyManager mParentDevicePolicyManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mParentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+    }
+
+    public void testCameraDisabledLogged() {
+        mParentDevicePolicyManager.setCameraDisabled(ADMIN_RECEIVER_COMPONENT, true);
+        mParentDevicePolicyManager.setCameraDisabled(ADMIN_RECEIVER_COMPONENT, false);
+    }
+
+    public void testUserRestrictionLogged() {
+        mParentDevicePolicyManager.addUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONFIG_LOCATION);
+        mParentDevicePolicyManager.clearUserRestriction(ADMIN_RECEIVER_COMPONENT,
+                UserManager.DISALLOW_CONFIG_LOCATION);
+    }
+
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
index c7a0326..036f4a2 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/DevicePolicyLoggingTest.java
@@ -19,6 +19,7 @@
 import static android.Manifest.permission.READ_CONTACTS;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
+import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_TRUST_AGENTS;
 import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
 import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
@@ -74,6 +75,8 @@
         mDevicePolicyManager.setKeyguardDisabledFeatures(
                 ADMIN_RECEIVER_COMPONENT, KEYGUARD_DISABLE_TRUST_AGENTS);
         mDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                KEYGUARD_DISABLE_SECURE_CAMERA);
+        mDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
                 KEYGUARD_DISABLE_FEATURES_NONE);
     }
 
@@ -184,4 +187,14 @@
         mDevicePolicyManager.setMasterVolumeMuted(ADMIN_RECEIVER_COMPONENT, true);
         mDevicePolicyManager.setMasterVolumeMuted(ADMIN_RECEIVER_COMPONENT, initialValue);
     }
+
+    public void testSetPersonalAppsSuspendedLogged() {
+        mDevicePolicyManager.setPersonalAppsSuspended(ADMIN_RECEIVER_COMPONENT, true);
+        mDevicePolicyManager.setPersonalAppsSuspended(ADMIN_RECEIVER_COMPONENT, false);
+    }
+
+    public void testSetManagedProfileMaximumTimeOffLogged() {
+        mDevicePolicyManager.setManagedProfileMaximumTimeOff(ADMIN_RECEIVER_COMPONENT, 1234567);
+        mDevicePolicyManager.setManagedProfileMaximumTimeOff(ADMIN_RECEIVER_COMPONENT, 0);
+    }
 }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FactoryResetProtectionPolicyTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FactoryResetProtectionPolicyTest.java
index 19286c1..4a9e60e 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FactoryResetProtectionPolicyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/FactoryResetProtectionPolicyTest.java
@@ -32,7 +32,7 @@
 
         FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                 .setFactoryResetProtectionAccounts(accounts)
-                .setFactoryResetProtectionDisabled(true)
+                .setFactoryResetProtectionEnabled(false)
                 .build();
 
         mDevicePolicyManager.setFactoryResetProtectionPolicy(ADMIN_RECEIVER_COMPONENT, policy);
@@ -48,7 +48,7 @@
         // Set a non-default policy
         FactoryResetProtectionPolicy policy = new FactoryResetProtectionPolicy.Builder()
                 .setFactoryResetProtectionAccounts(new ArrayList<>())
-                .setFactoryResetProtectionDisabled(true)
+                .setFactoryResetProtectionEnabled(false)
                 .build();
         mDevicePolicyManager.setFactoryResetProtectionPolicy(ADMIN_RECEIVER_COMPONENT, policy);
 
@@ -68,8 +68,8 @@
 
     private void assertPoliciesAreEqual(FactoryResetProtectionPolicy expectedPolicy,
             FactoryResetProtectionPolicy actualPolicy) {
-        assertThat(actualPolicy.isFactoryResetProtectionDisabled()).isEqualTo(
-                expectedPolicy.isFactoryResetProtectionDisabled());
+        assertThat(actualPolicy.isFactoryResetProtectionEnabled()).isEqualTo(
+                expectedPolicy.isFactoryResetProtectionEnabled());
         assertAccountsAreEqual(expectedPolicy.getFactoryResetProtectionAccounts(),
                 actualPolicy.getFactoryResetProtectionAccounts());
     }
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyguardDisabledFeaturesTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyguardDisabledFeaturesTest.java
new file mode 100644
index 0000000..304b67a
--- /dev/null
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyguardDisabledFeaturesTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.cts.deviceandprofileowner;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.admin.DevicePolicyManager;
+
+public class KeyguardDisabledFeaturesTest extends BaseDeviceAdminTest {
+
+    public void testSetKeyguardDisabledFeatures() {
+        mDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        // Check if the admin has disabled the camera specifically for the keyguard
+        assertThat(mDevicePolicyManager.getKeyguardDisabledFeatures(
+                ADMIN_RECEIVER_COMPONENT)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        removeKeyguardDisableFeatures(mDevicePolicyManager);
+        mDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+
+        // Check if the admin has disabled notifications specifically for the keyguard
+        assertThat(mDevicePolicyManager.getKeyguardDisabledFeatures(
+                ADMIN_RECEIVER_COMPONENT)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+        removeKeyguardDisableFeatures(mDevicePolicyManager);
+    }
+
+    public void testSetKeyguardDisabledFeatures_onParentSilentIgnoreWhenCallerIsNotOrgOwnedPO() {
+        DevicePolicyManager parentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+
+        parentDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        assertThat(mDevicePolicyManager.getKeyguardDisabledFeatures(
+                ADMIN_RECEIVER_COMPONENT)).isEqualTo(0);
+    }
+
+    public void testSetKeyguardDisabledFeatures_onParent() {
+        DevicePolicyManager parentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+
+        parentDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        // Check if the admin has disabled the camera specifically for the keyguard
+        assertThat(parentDevicePolicyManager.getKeyguardDisabledFeatures(
+                ADMIN_RECEIVER_COMPONENT)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_CAMERA);
+
+        removeKeyguardDisableFeatures(parentDevicePolicyManager);
+        parentDevicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+
+        // Check if the admin has disabled notifications specifically for the keyguard
+        assertThat(parentDevicePolicyManager.getKeyguardDisabledFeatures(
+                ADMIN_RECEIVER_COMPONENT)).isEqualTo(
+                DevicePolicyManager.KEYGUARD_DISABLE_SECURE_NOTIFICATIONS);
+        removeKeyguardDisableFeatures(parentDevicePolicyManager);
+    }
+
+    private void removeKeyguardDisableFeatures(DevicePolicyManager devicePolicyManager) {
+        devicePolicyManager.setKeyguardDisabledFeatures(ADMIN_RECEIVER_COMPONENT,
+                DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE);
+    }
+}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ScreenCaptureDisabledTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ScreenCaptureDisabledTest.java
index e1a740a..f59803b 100644
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ScreenCaptureDisabledTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ScreenCaptureDisabledTest.java
@@ -46,6 +46,25 @@
         assertTrue(mDevicePolicyManager.getScreenCaptureDisabled(null /* any admin */));
     }
 
+    public void testSetScreenCaptureDisabledOnParent() throws Exception {
+        DevicePolicyManager parentDevicePolicyManager =
+                mDevicePolicyManager.getParentProfileInstance(ADMIN_RECEIVER_COMPONENT);
+        boolean initial = parentDevicePolicyManager.getScreenCaptureDisabled(
+                ADMIN_RECEIVER_COMPONENT);
+
+        parentDevicePolicyManager.setScreenCaptureDisabled(ADMIN_RECEIVER_COMPONENT, true);
+        assertTrue(parentDevicePolicyManager.getScreenCaptureDisabled(ADMIN_RECEIVER_COMPONENT));
+        assertTrue(parentDevicePolicyManager.getScreenCaptureDisabled(null /* any admin */));
+        testScreenCaptureImpossible();
+
+        parentDevicePolicyManager.setScreenCaptureDisabled(ADMIN_RECEIVER_COMPONENT, false);
+        assertFalse(parentDevicePolicyManager.getScreenCaptureDisabled(ADMIN_RECEIVER_COMPONENT));
+        assertFalse(parentDevicePolicyManager.getScreenCaptureDisabled(null /* any admin */));
+        testScreenCapturePossible();
+
+        parentDevicePolicyManager.setScreenCaptureDisabled(ADMIN_RECEIVER_COMPONENT, initial);
+    }
+
     public void testScreenCaptureImpossible() throws Exception {
         for (int i = 0; i < MAX_ATTEMPTS_COUNT; i++) {
             Log.d(TAG, "testScreenCaptureImpossible: " + i + " trials");
diff --git a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/proxy/PacProxyTest.java b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/proxy/PacProxyTest.java
index 6272f44..ce5aa03 100644
--- a/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/proxy/PacProxyTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceOwner/src/com/android/cts/deviceowner/proxy/PacProxyTest.java
@@ -56,6 +56,7 @@
    * are passed through correctly.
    */
   private static final String HOST_PAC = "function FindProxyForURL(url, host)" +
+      "{" +
       "  if (host == \"testhost\") {" +
       "    return \"PROXY localhost:8080\";" +
       "  }" +
@@ -226,7 +227,6 @@
     setPacURLAndWaitForDownload();
 
     waitForSetProxySysProp();
-
     String host = "testhost";
     URI uri = new URI("http://" + host + "/test/my/url");
     ProxySelector selector = ProxySelector.getDefault();
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
index cc87b4f..153bc92 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
+++ b/hostsidetests/devicepolicy/app/LauncherTests/AndroidManifest.xml
@@ -19,10 +19,13 @@
 
     <uses-sdk android:minSdkVersion="21" android:targetSdkVersion="25"/>
 
+    <uses-permission android:name="MODIFY_QUIET_MODE"/>
+
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
 
+
     <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
                      android:targetPackage="com.android.cts.launchertests"
                      android:label="Launcher Apps CTS Tests"/>
diff --git a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/QuietModeTest.java b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/QuietModeTest.java
index d836d6f..21e3991 100644
--- a/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/QuietModeTest.java
+++ b/hostsidetests/devicepolicy/app/LauncherTests/src/com/android/cts/launchertests/QuietModeTest.java
@@ -171,6 +171,26 @@
         return trySetQuietModeEnabled(enabled, true, flags, expectsCredentialsNotNeeded);
     }
 
+    @Test
+    public void testTryEnableQuietMode() throws Exception {
+        setTestAppAsDefaultLauncher();
+        startLauncherActivityInTestApp();
+
+        Intent intent = trySetQuietModeEnabled(true);
+        assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_UNAVAILABLE broadcast", intent);
+        assertTrue(mUserManager.isQuietModeEnabled(mTargetUser));
+    }
+
+    @Test
+    public void testTryDisableQuietMode() throws Exception {
+        setTestAppAsDefaultLauncher();
+        startLauncherActivityInTestApp();
+
+        Intent intent = trySetQuietModeEnabled(false);
+        assertNotNull("Failed to receive ACTION_MANAGED_PROFILE_AVAILABLE broadcast", intent);
+        assertFalse(mUserManager.isQuietModeEnabled(mTargetUser));
+    }
+
     private Intent trySetQuietModeEnabled(boolean enabled) throws Exception {
         return trySetQuietModeEnabled(enabled, false, 0, true);
     }
diff --git a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
index a5e8da1..7c3b3ee 100644
--- a/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
+++ b/hostsidetests/devicepolicy/app/LauncherTestsSupport/src/com/android/cts/launchertests/support/LauncherCallbackTestsService.java
@@ -1,5 +1,6 @@
 /*
- * Copyright (C) 2014 The Android Open Sour *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java
index 5bd1ae1..705f204 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/CrossProfileTest.java
@@ -85,6 +85,13 @@
         mUserManager = mContext.getSystemService(UserManager.class);
     }
 
+    @Override
+    protected void tearDown() throws Exception {
+        explicitlyResetInteractAcrossProfilesAppOps();
+        resetCrossProfilePackages();
+        super.tearDown();
+    }
+
     public void testSetCrossProfilePackages_notProfileOwner_throwsSecurityException() {
         try {
             mDevicePolicyManager.setCrossProfilePackages(
@@ -123,100 +130,96 @@
                 .isEqualTo(packages2);
     }
 
+    /**
+     * Sets each of the packages in {@link #ALL_CROSS_PROFILE_PACKAGES} as cross-profile. This can
+     * then be used for writing host-side tests. Note that the state is cleared after running any
+     * test in this class, so this method should not be used to attempt to perform a sequence of
+     * device-side calls.
+     */
+    public void testSetCrossProfilePackages_noAsserts() throws Exception {
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+    }
+
     public void testSetCrossProfilePackages_firstTime_doesNotResetAnyAppOps() throws Exception {
-        try {
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
     }
 
     public void testSetCrossProfilePackages_unchanged_doesNotResetAnyAppOps() throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
 
-            assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
     }
 
     public void testSetCrossProfilePackages_noPackagesUnset_doesNotResetAnyAppOps()
             throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
 
-            assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        assertThatPackagesHaveAppOpMode(ALL_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
     }
 
     public void testSetCrossProfilePackages_somePackagesUnset_doesNotResetAppOpsIfStillSet()
             throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
 
-            assertThatPackagesHaveAppOpMode(SUBLIST_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        assertThatPackagesHaveAppOpMode(SUBLIST_CROSS_PROFILE_PACKAGES, MODE_ALLOWED);
     }
 
     public void testSetCrossProfilePackages_resetsAppOpOfUnsetPackages() throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
 
-            assertThatPackagesHaveAppOpMode(DIFF_CROSS_PROFILE_PACKAGES, MODE_DEFAULT);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        assertThatPackagesHaveAppOpMode(DIFF_CROSS_PROFILE_PACKAGES, MODE_DEFAULT);
     }
 
     public void testSetCrossProfilePackages_resetsAppOpOfUnsetPackagesOnOtherProfile()
             throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
 
-            assertThatPackagesHaveAppOpMode(
-                    DIFF_CROSS_PROFILE_PACKAGES, MODE_DEFAULT, UserHandle.of(0));
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        assertThatPackagesHaveAppOpMode(
+                DIFF_CROSS_PROFILE_PACKAGES, MODE_DEFAULT, UserHandle.of(0));
+    }
+
+    /**
+     * Sets each of the packages in {@link #ALL_CROSS_PROFILE_PACKAGES} as cross-profile, then sets
+     * them again to {@link #SUBLIST_CROSS_PROFILE_PACKAGES}, with all app-ops explicitly set as
+     * allowed before-hand. This should result in resetting packages {@link
+     * #DIFF_CROSS_PROFILE_PACKAGES}. This can then be used for writing host-side tests.
+     */
+    public void testSetCrossProfilePackages_resetsAppOps_noAsserts() throws Exception {
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
     }
 
     /**
@@ -226,17 +229,12 @@
      */
     public void testSetCrossProfilePackages_sendsBroadcastWhenResettingAppOps_noAsserts()
             throws Exception {
-        try {
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
-            explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, ALL_CROSS_PROFILE_PACKAGES);
+        explicitlySetInteractAcrossProfilesAppOps(MODE_ALLOWED);
 
-            mDevicePolicyManager.setCrossProfilePackages(
-                    ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
-        } finally {
-            explicitlyResetInteractAcrossProfilesAppOps();
-            resetCrossProfilePackages();
-        }
+        mDevicePolicyManager.setCrossProfilePackages(
+                ADMIN_RECEIVER_COMPONENT, SUBLIST_CROSS_PROFILE_PACKAGES);
     }
 
     private void explicitlySetInteractAcrossProfilesAppOps(int mode) throws Exception {
diff --git a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
index c494db0..69bc1ac 100644
--- a/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
+++ b/hostsidetests/devicepolicy/app/ManagedProfile/src/com/android/cts/managedprofile/ParentProfileTest.java
@@ -92,6 +92,10 @@
             .add("getUserRestrictions")
             .add("setApplicationHidden")
             .add("isApplicationHidden")
+            .add("setScreenCaptureDisabled")
+            .add("getScreenCaptureDisabled")
+            .add("getAccountTypesWithManagementDisabled")
+            .add("setAccountManagementDisabled")
             .build();
 
     private static final String LOG_TAG = "ParentProfileTest";
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
index b47fbf2..d427645 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/CrossProfileAppsHostSideTest.java
@@ -1,20 +1,31 @@
 package com.android.cts.devicepolicy;
 
+import static android.stats.devicepolicy.EventId.CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES_VALUE;
+import static android.stats.devicepolicy.EventId.CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER_VALUE;
+import static android.stats.devicepolicy.EventId.START_ACTIVITY_BY_INTENT_VALUE;
+
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.isStatsdEnabled;
 
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
 import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.LargeTest;
-import android.stats.devicepolicy.EventId;
 
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
+import com.android.tradefed.result.InputStreamSource;
+import com.android.tradefed.util.StreamUtil;
 
 import org.junit.Test;
 
 import java.io.FileNotFoundException;
 import java.util.Collections;
 import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import javax.annotation.Nullable;
 
@@ -135,6 +146,53 @@
 
     @LargeTest
     @Test
+    public void testStartActivityIntent_isLogged() throws Exception {
+        if (!mHasManagedUserFeature) {
+            return;
+        }
+        assertMetricsLogged(
+                getDevice(),
+                () -> verifyCrossProfileAppsApi(
+                        mProfileId,
+                        mPrimaryUserId,
+                        START_ACTIVITY_TEST_CLASS,
+                        "testStartActivityByIntent_noAsserts"),
+                new DevicePolicyEventWrapper
+                        .Builder(START_ACTIVITY_BY_INTENT_VALUE)
+                        .setStrings(TEST_PACKAGE)
+                        .setBoolean(true) // from work profile
+                        .build());
+    }
+
+    @LargeTest
+    @Test
+    public void testStartActivityIntent_sameTaskByDefault() throws Exception {
+        if (!mHasManagedUserFeature) {
+            return;
+        }
+        getDevice().clearLogcat();
+        verifyCrossProfileAppsApi(
+                mProfileId,
+                mPrimaryUserId,
+                START_ACTIVITY_TEST_CLASS,
+                "testStartActivityIntent_sameTaskByDefault");
+        assertThat(findTaskId("CrossProfileSameTaskLauncherActivity"))
+                .isEqualTo(findTaskId("NonMainActivity"));
+    }
+
+    private int findTaskId(String className) throws Exception {
+        final Matcher matcher =
+                Pattern.compile(className + "#taskId#" + "(.*?)" + "#").matcher(readLogcat());
+        boolean isFound = matcher.find();
+        if (!isFound) {
+            fail("Task not found for " + className);
+            return -1;
+        }
+        return Integer.parseInt(matcher.group(1));
+    }
+
+    @LargeTest
+    @Test
     public void testPrimaryUserToSecondaryUser() throws Exception {
         if (!mCanTestMultiUser) {
             return;
@@ -177,7 +235,7 @@
                             "testStartMainActivity_noAsserts");
                 },
                 new DevicePolicyEventWrapper
-                        .Builder(EventId.CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER_VALUE)
+                        .Builder(CROSS_PROFILE_APPS_START_ACTIVITY_AS_USER_VALUE)
                         .setStrings(new String[] {"com.android.cts.crossprofileappstest"})
                         .build());
     }
@@ -198,7 +256,7 @@
                             "testGetTargetUserProfiles_noAsserts");
                 },
                 new DevicePolicyEventWrapper
-                        .Builder(EventId.CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES_VALUE)
+                        .Builder(CROSS_PROFILE_APPS_GET_TARGET_USER_PROFILES_VALUE)
                         .setStrings(new String[] {"com.android.cts.crossprofileappstest"})
                         .build());
     }
@@ -234,4 +292,14 @@
         return Collections.singletonMap(PARAM_TARGET_USER,
                 Integer.toString(getUserSerialNumber(targetUserId)));
     }
+
+    private String readLogcat() throws Exception {
+        getDevice().stopLogcat();
+        final String logcat;
+        try (InputStreamSource logcatStream = getDevice().getLogcat()) {
+            logcat = StreamUtil.getStringFromSource(logcatStream);
+        }
+        getDevice().startLogcat();
+        return logcat;
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index e31c514..3a41d0f 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -166,6 +166,7 @@
     private static final int KEYGUARD_DISABLE_FEATURES_NONE = 0;
     private static final int KEYGUARD_DISABLE_FINGERPRINT = 1 << 5;
     private static final int KEYGUARD_DISABLE_TRUST_AGENTS = 1 << 4;
+    private static final int KEYGUARD_DISABLE_SECURE_CAMERA = 1 << 1;
     private static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
     private static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume";
     private static final String DISALLOW_AUTOFILL = "no_autofill";
@@ -180,6 +181,8 @@
     private static final String PARAM_APP_TO_ENABLE = "app_to_enable";
     public static final String RESOLVE_ACTIVITY_CMD = "cmd package resolve-activity --brief %s | tail -n 1";
 
+    private static final String NOT_CALLED_FROM_PARENT = "notCalledFromParent";
+
     // ID of the user all tests are run as. For device owner this will be the primary user, for
     // profile owner it is the user id of the created profile.
     protected int mUserId;
@@ -767,12 +770,12 @@
             }, new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_HIDDEN_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setBoolean(false)
-                    .setStrings(PERMISSIONS_APP_PKG, "hidden")
+                    .setStrings(PERMISSIONS_APP_PKG, "hidden", NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_HIDDEN_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setBoolean(false)
-                    .setStrings(PERMISSIONS_APP_PKG, "not_hidden")
+                    .setStrings(PERMISSIONS_APP_PKG, "not_hidden", NOT_CALLED_FROM_PARENT)
                     .build());
         }
     }
@@ -1393,10 +1396,12 @@
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_CAMERA_DISABLED_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setBoolean(true)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_CAMERA_DISABLED_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build());
     }
 
@@ -1717,7 +1722,7 @@
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_QUALITY_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setInt(PASSWORD_QUALITY_COMPLEX)
-                    .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_PASSWORD_MINIMUM_LENGTH_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
@@ -1773,26 +1778,40 @@
         }, new DevicePolicyEventWrapper.Builder(EventId.SET_KEYGUARD_DISABLED_FEATURES_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setInt(KEYGUARD_DISABLE_FEATURES_NONE)
-                    .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_KEYGUARD_DISABLED_FEATURES_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setInt(KEYGUARD_DISABLE_FINGERPRINT)
-                    .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_KEYGUARD_DISABLED_FEATURES_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setInt(KEYGUARD_DISABLE_TRUST_AGENTS)
-                    .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
+                    .build(),
+            new DevicePolicyEventWrapper.Builder(EventId.SET_KEYGUARD_DISABLED_FEATURES_VALUE)
+                    .setAdminPackageName(DEVICE_ADMIN_PKG)
+                    .setInt(KEYGUARD_DISABLE_SECURE_CAMERA)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.SET_KEYGUARD_DISABLED_FEATURES_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
                     .setInt(KEYGUARD_DISABLE_FEATURES_NONE)
-                    .setBoolean(false)
+                    .setStrings(NOT_CALLED_FROM_PARENT)
                     .build());
     }
 
     @Test
+    public void testSetKeyguardDisabledFeatures() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        executeDeviceTestMethod(".KeyguardDisabledFeaturesTest",
+                "testSetKeyguardDisabledFeatures");
+    }
+
+    @Test
     public void testSetUserRestrictionLogged() throws Exception {
         if (!mHasFeature || !isStatsdEnabled(getDevice())) {
             return;
@@ -1802,27 +1821,27 @@
                     ".DevicePolicyLoggingTest", "testSetUserRestrictionLogged");
         }, new DevicePolicyEventWrapper.Builder(EventId.ADD_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_CONFIG_LOCATION)
+                    .setStrings(DISALLOW_CONFIG_LOCATION, NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.REMOVE_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_CONFIG_LOCATION)
+                    .setStrings(DISALLOW_CONFIG_LOCATION, NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.ADD_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_ADJUST_VOLUME)
+                    .setStrings(DISALLOW_ADJUST_VOLUME, NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.REMOVE_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_ADJUST_VOLUME)
+                    .setStrings(DISALLOW_ADJUST_VOLUME, NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.ADD_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_AUTOFILL)
+                    .setStrings(DISALLOW_AUTOFILL, NOT_CALLED_FROM_PARENT)
                     .build(),
             new DevicePolicyEventWrapper.Builder(EventId.REMOVE_USER_RESTRICTION_VALUE)
                     .setAdminPackageName(DEVICE_ADMIN_PKG)
-                    .setStrings(DISALLOW_AUTOFILL)
+                    .setStrings(DISALLOW_AUTOFILL, NOT_CALLED_FROM_PARENT)
                     .build()
         );
     }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
index 3700ef2..1a0d63a 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerPlusProfileOwnerTest.java
@@ -65,6 +65,7 @@
             new Builder(EventId.WIPE_DATA_WITH_REASON_VALUE)
                     .setAdminPackageName(COMP_DPC_PKG)
                     .setInt(0)
+                    .setStrings("notCalledFromParent")
                     .build();
     private static final String COMP_DPC_APK = "CtsCorpOwnedManagedProfile.apk";
     private static final String COMP_DPC_ADMIN =
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
index e220e16..6e7477b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileCrossProfileTest.java
@@ -16,6 +16,13 @@
 
 package com.android.cts.devicepolicy;
 
+import static android.stats.devicepolicy.EventId.ADD_CROSS_PROFILE_INTENT_FILTER_VALUE;
+import static android.stats.devicepolicy.EventId.ADD_CROSS_PROFILE_WIDGET_PROVIDER_VALUE;
+import static android.stats.devicepolicy.EventId.REMOVE_CROSS_PROFILE_WIDGET_PROVIDER_VALUE;
+import static android.stats.devicepolicy.EventId.SET_CROSS_PROFILE_CALENDAR_PACKAGES_VALUE;
+import static android.stats.devicepolicy.EventId.SET_CROSS_PROFILE_PACKAGES_VALUE;
+import static android.stats.devicepolicy.EventId.SET_INTERACT_ACROSS_PROFILES_APP_OP_VALUE;
+
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
 import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.isStatsdEnabled;
 
@@ -24,7 +31,6 @@
 
 import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.LargeTest;
-import android.stats.devicepolicy.EventId;
 
 import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
@@ -47,6 +53,9 @@
     private static final String ACTION_CAN_INTERACT_ACROSS_PROFILES_CHANGED =
             "android.content.pm.action.CAN_INTERACT_ACROSS_PROFILES_CHANGED";
 
+    /** From {@code android.app.AppOpsManager#MODE_DEFAULT}. */
+    private static final int MODE_DEFAULT = 3;
+
     @LargeTest
     @Test
     public void testCrossProfileIntentFilters() throws Exception {
@@ -66,7 +75,7 @@
                 runDeviceTestsAsUser(
                         MANAGED_PROFILE_PKG, MANAGED_PROFILE_PKG + ".ManagedProfileTest",
                         "testAddCrossProfileIntentFilter_all", mProfileUserId);
-            }, new DevicePolicyEventWrapper.Builder(EventId.ADD_CROSS_PROFILE_INTENT_FILTER_VALUE)
+            }, new DevicePolicyEventWrapper.Builder(ADD_CROSS_PROFILE_INTENT_FILTER_VALUE)
                     .setAdminPackageName(MANAGED_PROFILE_PKG)
                     .setInt(1)
                     .setStrings("com.android.cts.managedprofile.ACTION_TEST_ALL_ACTIVITY")
@@ -288,11 +297,11 @@
                 changeCrossProfileWidgetForUser(WIDGET_PROVIDER_PKG,
                         "remove-cross-profile-widget", mProfileUserId);
             }, new DevicePolicyEventWrapper
-                        .Builder(EventId.ADD_CROSS_PROFILE_WIDGET_PROVIDER_VALUE)
+                        .Builder(ADD_CROSS_PROFILE_WIDGET_PROVIDER_VALUE)
                         .setAdminPackageName(MANAGED_PROFILE_PKG)
                         .build(),
                 new DevicePolicyEventWrapper
-                        .Builder(EventId.REMOVE_CROSS_PROFILE_WIDGET_PROVIDER_VALUE)
+                        .Builder(REMOVE_CROSS_PROFILE_WIDGET_PROVIDER_VALUE)
                         .setAdminPackageName(MANAGED_PROFILE_PKG)
                         .build());
         } finally {
@@ -310,7 +319,7 @@
         assertMetricsLogged(getDevice(), () -> {
             runDeviceTestsAsUser(MANAGED_PROFILE_PKG, ".CrossProfileCalendarTest",
                     "testCrossProfileCalendarPackage", mProfileUserId);
-        }, new DevicePolicyEventWrapper.Builder(EventId.SET_CROSS_PROFILE_CALENDAR_PACKAGES_VALUE)
+        }, new DevicePolicyEventWrapper.Builder(SET_CROSS_PROFILE_CALENDAR_PACKAGES_VALUE)
                     .setAdminPackageName(MANAGED_PROFILE_PKG)
                     .setStrings(MANAGED_PROFILE_PKG)
                     .build());
@@ -393,6 +402,23 @@
                 mProfileUserId);
     }
 
+    @Test
+    public void testSetCrossProfilePackages_isLogged() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAllDummyApps();
+        assertMetricsLogged(
+                getDevice(),
+                () -> runWorkProfileDeviceTest(
+                        ".CrossProfileTest", "testSetCrossProfilePackages_noAsserts"),
+                new DevicePolicyEventWrapper.Builder(SET_CROSS_PROFILE_PACKAGES_VALUE)
+                        .setAdminPackageName(MANAGED_PROFILE_PKG)
+                        .setStrings(
+                                DUMMY_APP_1_PKG, DUMMY_APP_2_PKG, DUMMY_APP_3_PKG, DUMMY_APP_4_PKG)
+                        .build());
+    }
+
     @FlakyTest
     @Test
     public void testDisallowSharingIntoPersonalFromProfile() throws Exception {
@@ -521,6 +547,28 @@
         return readLogcat().contains(expectedSubstring);
     }
 
+    @Test
+    public void testSetCrossProfilePackages_resetsAppOps_isLogged() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installAllDummyApps();
+        assertMetricsLogged(
+                getDevice(),
+                () -> runWorkProfileDeviceTest(
+                        ".CrossProfileTest", "testSetCrossProfilePackages_resetsAppOps_noAsserts"),
+                new DevicePolicyEventWrapper.Builder(SET_INTERACT_ACROSS_PROFILES_APP_OP_VALUE)
+                        .setStrings(DUMMY_APP_3_PKG)
+                        .setInt(MODE_DEFAULT)
+                        .setBoolean(true) // cross-profile manifest attribute
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(SET_INTERACT_ACROSS_PROFILES_APP_OP_VALUE)
+                        .setStrings(DUMMY_APP_4_PKG)
+                        .setInt(MODE_DEFAULT)
+                        .setBoolean(true) // cross-profile manifest attribute
+                        .build());
+    }
+
     private void runCrossProfileCalendarTestsWhenWhitelistedAndEnabled() throws Exception {
         try {
             // Setup. Add the test package into cross-profile calendar whitelist, enable
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
index 2dbc829..3417145 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.LargeTest;
 import android.stats.devicepolicy.EventId;
 
@@ -551,7 +552,10 @@
         }
     }
 
+    // TODO(b/149580605): Fix this flaky test.
     @Test
+    @FlakyTest
+    @Ignore
     public void testSanityCheck() throws Exception {
         if (!mHasFeature) {
             return;
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileWipeTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileWipeTest.java
index 98eb538..06aadc1 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileWipeTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/ManagedProfileWipeTest.java
@@ -63,6 +63,7 @@
         }, new DevicePolicyEventWrapper.Builder(EventId.WIPE_DATA_WITH_REASON_VALUE)
                 .setAdminPackageName(MANAGED_PROFILE_PKG)
                 .setInt(0)
+                .setStrings("notCalledFromParent")
                 .build());
         // Check and clear the notification is presented after work profile got removed, so profile
         // user no longer exists, verification should be run in primary user.
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
index 0521f65..bb75420 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedManagedProfileOwnerTest.java
@@ -266,6 +266,17 @@
                 "testSucceedsWithProfileOwnerIdsGrant", mUserId);
     }
 
+    @Test
+    @Override
+    public void testSetKeyguardDisabledFeatures() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".KeyguardDisabledFeaturesTest",
+                "testSetKeyguardDisabledFeatures_onParentSilentIgnoreWhenCallerIsNotOrgOwnedPO",
+                mUserId);
+    }
+
     @FlakyTest
     @Override
     @Test
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
index a1bdc5d..512d29b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/OrgOwnedProfileOwnerTest.java
@@ -17,6 +17,8 @@
 package com.android.cts.devicepolicy;
 
 import static com.android.cts.devicepolicy.DeviceAndProfileOwnerTest.DEVICE_ADMIN_COMPONENT_FLATTENED;
+import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.assertMetricsLogged;
+import static com.android.cts.devicepolicy.metrics.DevicePolicyEventLogVerifier.isStatsdEnabled;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -25,7 +27,9 @@
 
 import android.platform.test.annotations.FlakyTest;
 import android.platform.test.annotations.LargeTest;
+import android.stats.devicepolicy.EventId;
 
+import com.android.cts.devicepolicy.metrics.DevicePolicyEventWrapper;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.log.LogUtil;
 
@@ -53,6 +57,8 @@
     protected int mUserId;
     private boolean mHasProfileToRemove = true;
     private boolean mHasSecondaryProfileToRemove = false;
+    private static final String DISALLOW_CONFIG_LOCATION = "no_config_location";
+    private static final String CALLED_FROM_PARENT = "calledFromParent";
 
     @Override
     public void setUp() throws Exception {
@@ -120,7 +126,8 @@
 
         try {
             installAppAsUser(DEVICE_ADMIN_APK, mParentUserId);
-            setDeviceOwner(DEVICE_ADMIN_COMPONENT_FLATTENED, mParentUserId, /*expectFailure*/false);
+            assertTrue(setDeviceOwner(DEVICE_ADMIN_COMPONENT_FLATTENED,
+                    mParentUserId, /*expectFailure*/false));
             mHasSecondaryProfileToRemove = true;
             runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".LockScreenInfoTest", "testLockInfoIsNull",
                     mParentUserId);
@@ -173,6 +180,24 @@
     }
 
     @Test
+    public void testUserRestrictionSetOnParentLogged() throws Exception {
+        if (!mHasFeature|| !isStatsdEnabled(getDevice())) {
+            return;
+        }
+        assertMetricsLogged(getDevice(), () -> {
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DevicePolicyLoggingParentTest",
+                    "testUserRestrictionLogged", mUserId);
+                }, new DevicePolicyEventWrapper.Builder(EventId.ADD_USER_RESTRICTION_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setStrings(DISALLOW_CONFIG_LOCATION, CALLED_FROM_PARENT)
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(EventId.REMOVE_USER_RESTRICTION_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setStrings(DISALLOW_CONFIG_LOCATION, CALLED_FROM_PARENT)
+                        .build());
+    }
+
+    @Test
     public void testUserRestrictionsSetOnParentAreNotPersisted() throws Exception {
         if (!mHasFeature) {
             return;
@@ -221,6 +246,26 @@
                 "testClearUserRestrictionDisallowAddUser", mUserId);
     }
 
+    @Test
+    public void testCameraDisabledOnParentLogged() throws Exception {
+        if (!mHasFeature || !isStatsdEnabled(getDevice())) {
+            return;
+        }
+        assertMetricsLogged(getDevice(), () -> {
+                    runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DevicePolicyLoggingParentTest",
+                            "testCameraDisabledLogged", mUserId);
+                }, new DevicePolicyEventWrapper.Builder(EventId.SET_CAMERA_DISABLED_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(true)
+                        .setStrings(CALLED_FROM_PARENT)
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(EventId.SET_CAMERA_DISABLED_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(false)
+                        .setStrings(CALLED_FROM_PARENT)
+                        .build());
+    }
+
     private void failToCreateUser() throws Exception {
         String command ="pm create-user " + "TestUser_" + System.currentTimeMillis();
         String commandOutput = getDevice().executeShellCommand(command);
@@ -353,6 +398,15 @@
         runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ApplicationHiddenParentTest", mUserId);
     }
 
+    @Test
+    public void testSetKeyguardDisabledFeatures() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".KeyguardDisabledFeaturesTest",
+                "testSetKeyguardDisabledFeatures_onParent", mUserId);
+    }
+
     private void removeOrgOwnedProfile() throws Exception {
         sendWipeProfileBroadcast(mUserId);
         waitUntilUserRemoved(mUserId);
@@ -385,6 +439,10 @@
 
     @Test
     public void testPersonalAppsSuspensionIme() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
         installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
         setupIme(mPrimaryUserId, DUMMY_IME_APK, DUMMY_IME_COMPONENT);
         setPersonalAppsSuspended(true);
@@ -393,6 +451,24 @@
         setPersonalAppsSuspended(false);
     }
 
+    @Test
+    public void testCanRestrictAccountManagementOnParentProfile() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".AccountManagementParentTest",
+                "testCanSetAccountManagementRestriction", mUserId);
+        installAppAsUser(DEVICE_ADMIN_APK, mPrimaryUserId);
+        try {
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".AccountManagementParentTest",
+                    "testAccountRestricted", mPrimaryUserId);
+        } finally {
+            runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".AccountManagementParentTest",
+                    "testCanRemoveAccountManagementRestriction", mUserId);
+        }
+    }
+
     private void setupIme(int userId, String imeApk, String imePackage) throws Exception {
         installAppAsUser(imeApk, userId);
         // Wait until IMS service is registered by the system.
@@ -418,6 +494,15 @@
                 canStart ? "testCanStartActivity" : "testCannotStartActivity", mParentUserId);
     }
 
+    @Test
+    public void testScreenCaptureDisabled() throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".ScreenCaptureDisabledTest",
+                "testSetScreenCaptureDisabledOnParent", mUserId);
+    }
+
     private void assertHasNoUser(int userId) throws DeviceNotAvailableException {
         int numWaits = 0;
         final int MAX_NUM_WAITS = 15;
@@ -440,7 +525,7 @@
                         userId, /* expectFailure */ false));
     }
 
-    public boolean hasService(String service) {
+    private boolean hasService(String service) {
         String command = "service check " + service;
         try {
             String commandOutput = getDevice().executeShellCommand(command);
@@ -450,4 +535,42 @@
             return false;
         }
     }
+
+    @Test
+    public void testSetPersonalAppsSuspendedLogged() throws Exception {
+        if (!mHasFeature|| !isStatsdEnabled(getDevice())) {
+            return;
+        }
+        assertMetricsLogged(getDevice(), () -> {
+                    runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DevicePolicyLoggingTest",
+                            "testSetPersonalAppsSuspendedLogged", mUserId);
+                }, new DevicePolicyEventWrapper.Builder(EventId.SET_PERSONAL_APPS_SUSPENDED_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(true)
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(EventId.SET_PERSONAL_APPS_SUSPENDED_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setBoolean(false)
+                        .build());
+    }
+
+    @Test
+    public void testSetManagedProfileMaximumTimeOffLogged() throws Exception {
+        if (!mHasFeature|| !isStatsdEnabled(getDevice())) {
+            return;
+        }
+        assertMetricsLogged(getDevice(), () -> {
+                    runDeviceTestsAsUser(DEVICE_ADMIN_PKG, ".DevicePolicyLoggingTest",
+                            "testSetManagedProfileMaximumTimeOffLogged", mUserId);
+                }, new DevicePolicyEventWrapper.Builder(
+                        EventId.SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setTimePeriod(1234567)
+                        .build(),
+                new DevicePolicyEventWrapper.Builder(
+                        EventId.SET_MANAGED_PROFILE_MAXIMUM_TIME_OFF_VALUE)
+                        .setAdminPackageName(DEVICE_ADMIN_PKG)
+                        .setTimePeriod(0)
+                        .build());
+    }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/PasswordComplexityTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/PasswordComplexityTest.java
index 43dde5b..bf90e78 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/PasswordComplexityTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/PasswordComplexityTest.java
@@ -56,6 +56,6 @@
                 () -> runDeviceTestsAsUser(PKG, CLS, mCurrentUserId),
                 new DevicePolicyEventWrapper
                         .Builder(EventId.GET_USER_PASSWORD_COMPLEXITY_LEVEL_VALUE)
-                        .setStrings(PKG).build());
+                        .setStrings("notCalledFromParent", PKG).build());
     }
 }
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
index d323258..d4fde47 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/QuietModeHostsideTest.java
@@ -1,9 +1,14 @@
 package com.android.cts.devicepolicy;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import android.platform.test.annotations.LargeTest;
 
+import com.android.tradefed.device.DeviceNotAvailableException;
+
 import org.junit.Test;
 
+import java.io.FileNotFoundException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -20,6 +25,17 @@
 
     private static final String TEST_LAUNCHER_PACKAGE = "com.android.cts.launchertests.support";
     private static final String TEST_LAUNCHER_APK = "CtsLauncherAppsTestsSupport.apk";
+    private static final String ENABLED_TEST_APK = "CtsCrossProfileEnabledApp.apk";
+    private static final String USER_ENABLED_TEST_APK = "CtsCrossProfileUserEnabledApp.apk";
+    private static final String ENABLED_NO_PERMS_TEST_APK = "CtsCrossProfileEnabledNoPermsApp.apk";
+    private static final String NOT_ENABLED_TEST_APK = "CtsCrossProfileNotEnabledApp.apk";
+    private static final String ENABLED_TEST_PACKAGE = "com.android.cts.crossprofileenabledapp";
+    private static final String USER_ENABLED_TEST_PACKAGE =
+            "com.android.cts.crossprofileuserenabledapp";
+    private static final String ENABLED_NO_PERMS_TEST_PACKAGE =
+            "com.android.cts.crossprofileenablednopermsapp";
+    private static final String NOT_ENABLED_TEST_PACKAGE =
+            "com.android.cts.crossprofilenotenabledapp";
 
     private int mProfileId;
     private String mOriginalLauncher;
@@ -30,12 +46,14 @@
 
         mHasFeature = mHasFeature & hasDeviceFeature("android.software.managed_users");
 
-        if(mHasFeature) {
+        if (mHasFeature) {
             mOriginalLauncher = getDefaultLauncher();
 
             installAppAsUser(TEST_APK, mPrimaryUserId);
             installAppAsUser(TEST_LAUNCHER_APK, mPrimaryUserId);
 
+            waitForBroadcastIdle();
+
             createAndStartManagedProfile();
             installAppAsUser(TEST_APK, mProfileId);
 
@@ -47,7 +65,7 @@
     @Override
     public void tearDown() throws Exception {
         if (mHasFeature) {
-            getDevice().uninstallPackage(TEST_PACKAGE);
+            uninstallRequiredApps();
             getDevice().uninstallPackage(TEST_LAUNCHER_PACKAGE);
         }
         super.tearDown();
@@ -57,7 +75,7 @@
     @Test
     public void testQuietMode_defaultForegroundLauncher() throws Exception {
         if (!mHasFeature) {
-          return;
+            return;
         }
         // Add a lockscreen to test the case that profile with unified challenge can still
         // be turned on without asking the user to enter the lockscreen password.
@@ -83,11 +101,11 @@
             return;
         }
         runDeviceTestsAsUser(
-            TEST_PACKAGE,
-            TEST_CLASS,
-            "testTryEnableQuietMode_notForegroundLauncher",
-            mPrimaryUserId,
-            createParams(mProfileId));
+                TEST_PACKAGE,
+                TEST_CLASS,
+                "testTryEnableQuietMode_notForegroundLauncher",
+                mPrimaryUserId,
+                createParams(mProfileId));
     }
 
     @LargeTest
@@ -97,11 +115,89 @@
             return;
         }
         runDeviceTestsAsUser(
-            TEST_PACKAGE,
-            TEST_CLASS,
-            "testTryEnableQuietMode_notDefaultLauncher",
-            mPrimaryUserId,
-            createParams(mProfileId));
+                TEST_PACKAGE,
+                TEST_CLASS,
+                "testTryEnableQuietMode_notDefaultLauncher",
+                mPrimaryUserId,
+                createParams(mProfileId));
+    }
+
+    @LargeTest
+    @Test
+    public void testBroadcastManagedProfileAvailable_withoutCrossProfileAppsOp() throws Exception {
+        checkBroadcastManagedProfileAvailable(/* withCrossProfileAppOps= */ false);
+    }
+
+
+    @LargeTest
+    @Test
+    public void testBroadcastManagedProfileAvailable_withCrossProfileAppsOp() throws Exception {
+        checkBroadcastManagedProfileAvailable(/* withCrossProfileAppOps= */ true);
+    }
+
+    private void checkBroadcastManagedProfileAvailable(boolean withCrossProfileAppOps)
+            throws Exception {
+        if (!mHasFeature) {
+            return;
+        }
+        installCrossProfileApps();
+        if (withCrossProfileAppOps) {
+            enableCrossProfileAppsOp();
+        }
+        clearLogcat();
+        runDeviceTestsAsUser(
+                TEST_PACKAGE,
+                TEST_CLASS,
+                "testTryEnableQuietMode",
+                mPrimaryUserId,
+                createParams(mProfileId));
+        waitForBroadcastIdle();
+        verifyBroadcastSent("android.intent.action.MANAGED_PROFILE_UNAVAILABLE",
+                /* needPermissions= */ !withCrossProfileAppOps);
+
+        clearLogcat();
+        runDeviceTestsAsUser(
+                TEST_PACKAGE,
+                TEST_CLASS,
+                "testTryDisableQuietMode",
+                mPrimaryUserId,
+                createParams(mProfileId));
+        waitForBroadcastIdle();
+        verifyBroadcastSent("android.intent.action.MANAGED_PROFILE_AVAILABLE",
+                /* needPermissions= */ !withCrossProfileAppOps);
+
+        clearLogcat();
+        removeUser(mProfileId);
+        waitForBroadcastIdle();
+        verifyBroadcastSent("android.intent.action.MANAGED_PROFILE_REMOVED",
+                /* needPermissions= */ false);
+    }
+
+    private void clearLogcat() throws DeviceNotAvailableException {
+        getDevice().executeAdbCommand("logcat", "-c");
+    }
+
+    private void verifyBroadcastSent(String actionName, boolean needPermissions)
+            throws DeviceNotAvailableException {
+        final String result = getDevice().executeAdbCommand("logcat", "-d");
+        assertThat(result).contains(
+                buildReceivedBroadcastRegex(actionName, "CrossProfileEnabledAppReceiver"));
+        assertThat(result).contains(
+                buildReceivedBroadcastRegex(actionName, "CrossProfileUserEnabledAppReceiver"));
+        String noPermsString = buildReceivedBroadcastRegex(actionName,
+                "CrossProfileEnabledNoPermsAppReceiver");
+        if (needPermissions) {
+            assertThat(result).doesNotContain(noPermsString);
+        } else {
+            assertThat(result).contains(noPermsString);
+        }
+        assertThat(result).doesNotContain(
+                buildReceivedBroadcastRegex(actionName,
+                        "CrossProfileNotEnabledAppReceiver"));
+    }
+
+    private String buildReceivedBroadcastRegex(String actionName, String className) {
+        return String.format("%s: onReceive(%s)", className, actionName);
     }
 
     @LargeTest
@@ -128,6 +224,46 @@
         startUser(mProfileId);
     }
 
+    private void uninstallRequiredApps()
+            throws DeviceNotAvailableException {
+        getDevice().uninstallPackage(TEST_PACKAGE);
+        getDevice().uninstallPackage(ENABLED_TEST_PACKAGE);
+        getDevice().uninstallPackage(USER_ENABLED_TEST_PACKAGE);
+        getDevice().uninstallPackage(ENABLED_NO_PERMS_TEST_PACKAGE);
+        getDevice().uninstallPackage(NOT_ENABLED_TEST_PACKAGE);
+    }
+
+    private void installCrossProfileApps()
+            throws FileNotFoundException, DeviceNotAvailableException {
+        installCrossProfileApp(ENABLED_TEST_APK);
+        installCrossProfileApp(USER_ENABLED_TEST_APK);
+        installCrossProfileApp(NOT_ENABLED_TEST_APK);
+        installCrossProfileApp(ENABLED_NO_PERMS_TEST_APK);
+    }
+
+    private void enableCrossProfileAppsOp() throws DeviceNotAvailableException {
+        enableCrossProfileAppsOp(ENABLED_TEST_PACKAGE, mPrimaryUserId);
+        enableCrossProfileAppsOp(USER_ENABLED_TEST_PACKAGE, mPrimaryUserId);
+        enableCrossProfileAppsOp(NOT_ENABLED_TEST_PACKAGE, mPrimaryUserId);
+        enableCrossProfileAppsOp(ENABLED_NO_PERMS_TEST_PACKAGE, mPrimaryUserId);
+    }
+
+    private void installCrossProfileApp(String apkName)
+            throws FileNotFoundException, DeviceNotAvailableException {
+        installAppAsUser(apkName, mPrimaryUserId);
+        installAppAsUser(apkName, mProfileId);
+    }
+
+    private void enableCrossProfileAppsOp(String packageName, int userId)
+            throws DeviceNotAvailableException {
+        getDevice().executeShellCommand(
+                String.format("appops set --user %s %s android:interact_across_profiles 0",
+                userId, packageName));
+        assertThat(getDevice().executeShellCommand(
+                String.format("appops get --user %s %s android:interact_across_profiles",
+                userId, packageName))).contains("INTERACT_ACROSS_PROFILES: allow");
+    }
+
     private Map<String, String> createParams(int targetUserId) throws Exception {
         Map<String, String> params = new HashMap<>();
         params.put(PARAM_TARGET_USER, Integer.toString(getUserSerialNumber(targetUserId)));
diff --git a/hostsidetests/dexmetadata/app/AndroidManifest.xml b/hostsidetests/dexmetadata/app/AndroidManifest.xml
index 136e403..0d0ed38 100644
--- a/hostsidetests/dexmetadata/app/AndroidManifest.xml
+++ b/hostsidetests/dexmetadata/app/AndroidManifest.xml
@@ -20,6 +20,10 @@
         <uses-library android:name="android.test.runner" />
     </application>
 
+    <queries>
+        <package android:name="com.android.cts.dexmetadata.splitapp" />
+    </queries>
+
     <instrumentation
         android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.cts.dexmetadata" />
diff --git a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
index f9000a8..fb14756 100644
--- a/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
+++ b/hostsidetests/gputools/src/android/gputools/cts/CtsRootlessGpuDebugHostTest.java
@@ -138,53 +138,19 @@
     }
 
     /**
-     * Apply a setting and ensure it sticks before continuing
+     * Apply a setting and refresh the platform's cache
      */
     private void applySetting(String setting, String value) throws Exception {
         getDevice().executeShellCommand("settings put global " + setting + " " + value);
-
-        long hostStartTime = System.currentTimeMillis();
-        while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
-
-            // Give the setting a chance to apply
-            Thread.sleep(1000);
-
-            // Read it back, make sure it has applied
-            String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
-            if ((returnedValue != null) && (returnedValue.trim().equals(value))) {
-                return;
-            }
-        }
-
-        // If this assert fires, try increasing the timeout
-        Assert.fail("Unable to set global setting (" + setting + ") to (" + value + ") before timout (" +
-                SETTING_APPLY_TIMEOUT_MS + "ms)");
+        getDevice().executeShellCommand("am refresh-settings-cache");
     }
 
     /**
-     * Delete a setting and ensure it goes away before continuing
+     * Delete a setting and refresh the platform's cache
      */
     private void deleteSetting(String setting) throws Exception {
-        getDevice().executeShellCommand("shell settings delete global " + setting);
-
-        long hostStartTime = System.currentTimeMillis();
-        while (((System.currentTimeMillis() - hostStartTime) < SETTING_APPLY_TIMEOUT_MS)) {
-
-            // Give the setting a chance to apply
-            Thread.sleep(1000);
-
-            // Read it back, make sure it is gone
-            String returnedValue = getDevice().executeShellCommand("settings get global " + setting);
-            if ((returnedValue == null) ||
-                (returnedValue.trim().isEmpty()) ||
-                (returnedValue.trim().equals("null"))) {
-                return;
-            }
-        }
-
-        // If this assert fires, try increasing the timeout
-        Assert.fail("Unable to delete global setting (" + setting + ") before timout (" +
-                SETTING_APPLY_TIMEOUT_MS + "ms)");
+        getDevice().executeShellCommand("settings delete global " + setting);
+        getDevice().executeShellCommand("am refresh-settings-cache");
     }
 
     /**
diff --git a/hostsidetests/hdmicec/OWNERS b/hostsidetests/hdmicec/OWNERS
index 254c58d..e7f5c32 100644
--- a/hostsidetests/hdmicec/OWNERS
+++ b/hostsidetests/hdmicec/OWNERS
@@ -1,3 +1,3 @@
-# Bug component: 141606867
+# Bug component: 114946
 nchalko@google.com
 amyjojo@google.com
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
index 3dac5d5..68c270a 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/CecDevice.java
@@ -21,12 +21,20 @@
 
 public enum CecDevice {
     TV(0x0),
-    RECORDING_1(0x1),
+    RECORDER_1(0x1),
+    RECORDER_2(0x2),
     TUNER_1(0x3),
     PLAYBACK_1(0x4),
     AUDIO_SYSTEM(0x5),
+    TUNER_2(0x6),
+    TUNER_3(0x7),
     PLAYBACK_2(0x8),
+    RECORDER_3(0x9),
+    TUNER_4(0xa),
     PLAYBACK_3(0xb),
+    RESERVED_1(0xc),
+    RESERVED_2(0xd),
+    SPECIFIC_USE(0xe),
     BROADCAST(0xf);
 
     private final int playerId;
@@ -53,8 +61,15 @@
                 return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TV);
             case AUDIO_SYSTEM:
                 return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_AUDIO_SYSTEM);
-            case RECORDING_1:
-                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RECORDING_DEVICE);
+            case RECORDER_1:
+            case RECORDER_2:
+            case RECORDER_3:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RECORDER);
+            case TUNER_1:
+            case TUNER_2:
+            case TUNER_3:
+            case TUNER_4:
+                return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_TUNER);
             default:
                 return Integer.toString(HdmiCecConstants.CEC_DEVICE_TYPE_RESERVED);
         }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
index 4bbf0ec..a4bacf4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecClientWrapper.java
@@ -171,6 +171,21 @@
      */
     public void sendUserControlPressAndRelease(CecDevice source, CecDevice destination,
             int keycode, boolean holdKey) throws Exception {
+        sendUserControlPress(source, destination, keycode, holdKey);
+        /* Sleep less than 200ms between press and release */
+        TimeUnit.MILLISECONDS.sleep(100);
+        mOutputConsole.write("tx " + source + destination + ":" +
+                              CecMessage.USER_CONTROL_RELEASED);
+        mOutputConsole.flush();
+    }
+
+    /**
+     * Sends a <UCP> message from source to destination through the output console of the
+     * cec-communication channel with the mentioned keycode. If holdKey is true, the method will
+     * send multiple <UCP> messages to simulate a long press. No <UCR> will be sent.
+     */
+    public void sendUserControlPress(CecDevice source, CecDevice destination,
+            int keycode, boolean holdKey) throws Exception {
         checkCecClient();
         String key = String.format("%02x", keycode);
         String command = "tx " + source + destination + ":" +
@@ -182,6 +197,7 @@
             int repeat = 16;
             for (int i = 0; i < repeat; i++) {
                 mOutputConsole.write(command);
+                mOutputConsole.newLine();
                 mOutputConsole.flush();
                 TimeUnit.MILLISECONDS.sleep(300);
             }
@@ -189,10 +205,6 @@
 
         mOutputConsole.write(command);
         mOutputConsole.newLine();
-        /* Sleep less than 200ms between press and release */
-        TimeUnit.MILLISECONDS.sleep(100);
-        mOutputConsole.write("tx " + source + destination + ":" +
-                              CecMessage.USER_CONTROL_RELEASED);
         mOutputConsole.flush();
     }
 
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
index 6383a4a..0565eae 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/HdmiCecConstants.java
@@ -41,7 +41,7 @@
     public static final int UNRECOGNIZED_OPCODE = 0x0;
 
     public static final int CEC_DEVICE_TYPE_TV = 0;
-    public static final int CEC_DEVICE_TYPE_RECORDING_DEVICE = 1;
+    public static final int CEC_DEVICE_TYPE_RECORDER = 1;
     public static final int CEC_DEVICE_TYPE_RESERVED = 2;
     public static final int CEC_DEVICE_TYPE_TUNER = 3;
     public static final int CEC_DEVICE_TYPE_PLAYBACK_DEVICE = 4;
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
index 182a3cb..a90b09f 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/audio/HdmiCecRemoteControlPassThroughTest.java
@@ -140,4 +140,38 @@
                 HdmiCecConstants.CEC_CONTROL_BACK, true);
         lookForLog("Long press KEYCODE_BACK");
     }
+
+    /**
+     * Test 11.2.13-3
+     * Tests that the device responds correctly to a <User Control Pressed> message for press and
+     * hold operations when no <User Control Released> is sent.
+     */
+    @Test
+    public void cect_11_2_13_3_UserControlPressAndHoldWithNoRelease() throws Exception {
+        ITestDevice device = getDevice();
+        // Clear activity
+        device.executeShellCommand(CLEAR_COMMAND);
+        // Clear logcat.
+        device.executeAdbCommand("logcat", "-c");
+        // Start the APK and wait for it to complete.
+        device.executeShellCommand(START_COMMAND);
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_UP, true);
+        lookForLog("Long press KEYCODE_DPAD_UP");
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_DOWN, true);
+        lookForLog("Long press KEYCODE_DPAD_DOWN");
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_LEFT, true);
+        lookForLog("Long press KEYCODE_DPAD_LEFT");
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_RIGHT, true);
+        lookForLog("Long press KEYCODE_DPAD_RIGHT");
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_SELECT, true);
+        lookForLog("Long press KEYCODE_DPAD_CENTER");
+        hdmiCecClient.sendUserControlPress(CecDevice.TV, CecDevice.AUDIO_SYSTEM,
+                HdmiCecConstants.CEC_CONTROL_BACK, true);
+        lookForLog("Long press KEYCODE_BACK");
+    }
 }
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
index e5ab1d9..c6df9f7 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemInformationTest.java
@@ -172,7 +172,7 @@
         final String originalLanguage = extractLanguage(locale);
         final String language = originalLanguage.equals("spa") ? "eng" : "spa";
         try {
-            hdmiCecClient.sendCecMessage(CecDevice.RECORDING_1, CecDevice.BROADCAST,
+            hdmiCecClient.sendCecMessage(CecDevice.RECORDER_1, CecDevice.BROADCAST,
                     CecMessage.SET_MENU_LANGUAGE, hdmiCecClient.convertStringToHexParams(language));
             assertEquals(originalLanguage, extractLanguage(getSystemLocale()));
         } finally {
diff --git a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java
index 3f51843..1aa8fe4 100644
--- a/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java
+++ b/hostsidetests/hdmicec/src/android/hdmicec/cts/playback/HdmiCecSystemStandbyTest.java
@@ -87,7 +87,7 @@
             checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.BROADCAST);
             /* Wake up the TV */
             hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
-            checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.BROADCAST);
+            checkDeviceAsleepAfterStandbySent(CecDevice.RECORDER_1, CecDevice.BROADCAST);
             /* Wake up the TV */
             hdmiCecClient.sendConsoleMessage("on " + CecDevice.TV);
             checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.BROADCAST);
@@ -109,7 +109,7 @@
         getDevice().executeShellCommand("reboot");
         getDevice().waitForBootComplete(HdmiCecConstants.REBOOT_TIMEOUT);
         checkDeviceAsleepAfterStandbySent(CecDevice.TV, CecDevice.PLAYBACK_1);
-        checkDeviceAsleepAfterStandbySent(CecDevice.RECORDING_1, CecDevice.PLAYBACK_1);
+        checkDeviceAsleepAfterStandbySent(CecDevice.RECORDER_1, CecDevice.PLAYBACK_1);
         checkDeviceAsleepAfterStandbySent(CecDevice.AUDIO_SYSTEM, CecDevice.PLAYBACK_1);
         checkDeviceAsleepAfterStandbySent(CecDevice.PLAYBACK_2, CecDevice.PLAYBACK_1);
         checkDeviceAsleepAfterStandbySent(CecDevice.BROADCAST, CecDevice.PLAYBACK_1);
diff --git a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
index 9701345..3c807fa 100644
--- a/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
+++ b/hostsidetests/incident/src/com/android/server/cts/JobSchedulerIncidentTest.java
@@ -91,13 +91,6 @@
     private static void testConstantsProto(ConstantsProto c) throws Exception {
         assertNotNull(c);
 
-        assertTrue(0 <= c.getMinIdleCount());
-        assertTrue(0 <= c.getMinChargingCount());
-        assertTrue(0 <= c.getMinBatteryNotLowCount());
-        assertTrue(0 <= c.getMinStorageNotLowCount());
-        assertTrue(0 <= c.getMinConnectivityCount());
-        assertTrue(0 <= c.getMinContentCount());
-        assertTrue(0 <= c.getMinReadyJobsCount());
         assertTrue(0 <= c.getHeavyUseFactor());
         assertTrue(0 <= c.getModerateUseFactor());
         assertTrue(0 <= c.getFgJobCount());
diff --git a/hostsidetests/net/app/AndroidManifest.xml b/hostsidetests/net/app/AndroidManifest.xml
index 3b00713..5ddad7c 100644
--- a/hostsidetests/net/app/AndroidManifest.xml
+++ b/hostsidetests/net/app/AndroidManifest.xml
@@ -25,6 +25,7 @@
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
 
diff --git a/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java b/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java
index e7374ac..b1bda95 100644
--- a/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java
+++ b/hostsidetests/os/src/android/os/cts/InattentiveSleepTests.java
@@ -27,7 +27,6 @@
 import com.android.compatibility.common.util.ProtoUtils;
 import com.android.server.power.PowerManagerServiceDumpProto;
 import com.android.server.power.PowerServiceSettingsAndConfigurationDumpProto;
-import com.android.server.wm.IdentifierProto;
 import com.android.server.wm.WindowManagerServiceDumpProto;
 import com.android.server.wm.WindowStateProto;
 import com.android.tradefed.device.ITestDevice;
@@ -193,17 +192,19 @@
 
     @Test
     public void testInattentiveSleep_warningTiming() throws Exception {
-        long eps = 300;
+        setInattentiveSleepTimeout(5000 + mWarningDurationConfig);
+
+        long eps = 1000;
         wakeUpToHome();
 
         long start = System.currentTimeMillis();
-        Thread.sleep(eps);
-        waitUntilWarningIsShowing();
+        waitUntilWarningIsNotShowing(1000);
+        waitUntilWarningIsShowing(5000);
         long warningShown = System.currentTimeMillis();
 
         long actualTimeToWarningShown = warningShown - start;
         assertTrue("Warning was shown at unexpected time, after " + actualTimeToWarningShown + "ms",
-                Math.abs(actualTimeToWarningShown - TIME_BEFORE_WARNING_MS) <= eps);
+                Math.abs(actualTimeToWarningShown - 5000) <= eps);
 
         long sleepTime = warningShown + mWarningDurationConfig - eps;
         while (System.currentTimeMillis() < sleepTime) {
@@ -253,6 +254,14 @@
     }
 
     private void waitUntilWarningIsShowing() throws Exception {
-        PollingCheck.waitFor(TIME_BEFORE_WARNING_MS + 1000, this::isWarningShown);
+        waitUntilWarningIsShowing(TIME_BEFORE_WARNING_MS + 1000);
+    }
+
+    private void waitUntilWarningIsShowing(long timeout) throws Exception {
+        PollingCheck.waitFor(timeout, this::isWarningShown);
+    }
+
+    private void waitUntilWarningIsNotShowing(long timeout) throws Exception {
+        PollingCheck.waitFor(timeout, () -> !isWarningShown());
     }
 }
diff --git a/hostsidetests/packagemanager/OWNERS b/hostsidetests/packagemanager/OWNERS
index 5ee2e6d..003fff4 100644
--- a/hostsidetests/packagemanager/OWNERS
+++ b/hostsidetests/packagemanager/OWNERS
@@ -1,2 +1,7 @@
 # Bug component: 36137
-pm-review@google.com
\ No newline at end of file
+patb@google.com
+toddke@google.com
+svetoslavganov@google.com
+narayan@google.com
+hackbod@google.com
+
diff --git a/hostsidetests/rollback/app/AndroidManifest.xml b/hostsidetests/rollback/app/AndroidManifest.xml
index 421ceff..9d4d5d2 100644
--- a/hostsidetests/rollback/app/AndroidManifest.xml
+++ b/hostsidetests/rollback/app/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.rollback.host.app" >
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
diff --git a/hostsidetests/rollback/app2/AndroidManifest.xml b/hostsidetests/rollback/app2/AndroidManifest.xml
index be6d483..3105857 100644
--- a/hostsidetests/rollback/app2/AndroidManifest.xml
+++ b/hostsidetests/rollback/app2/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.rollback.host.app2" >
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
diff --git a/hostsidetests/stagedinstall/app/AndroidManifest.xml b/hostsidetests/stagedinstall/app/AndroidManifest.xml
index 3708c02..067e1cc 100644
--- a/hostsidetests/stagedinstall/app/AndroidManifest.xml
+++ b/hostsidetests/stagedinstall/app/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.tests.stagedinstall" >
 
+    <uses-permission android:name="QUERY_ALL_PACKAGES" />
     <application>
         <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
diff --git a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
index 1dfdd00..5e9e2ba 100644
--- a/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
+++ b/hostsidetests/statsd/src/android/cts/statsd/atom/UidAtomTests.java
@@ -43,6 +43,7 @@
 import com.android.os.AtomsProto.ForegroundServiceStateChanged;
 import com.android.os.AtomsProto.GpsScanStateChanged;
 import com.android.os.AtomsProto.HiddenApiUsed;
+import com.android.os.AtomsProto.IonHeapSize;
 import com.android.os.AtomsProto.LooperStats;
 import com.android.os.AtomsProto.LmkKillOccurred;
 import com.android.os.AtomsProto.MediaCodecStateChanged;
@@ -1189,6 +1190,36 @@
             .that(foundSystemServer).isTrue();
     }
 
+    public void testIonHeapSize() throws Exception {
+        if (statsdDisabled() || !fileExists("/sys/kernel/ion/total_heaps_kb")) {
+            return;
+        }
+
+        // Get IonHeapSize as a simple gauge metric.
+        StatsdConfig.Builder config = getPulledConfig();
+        addGaugeAtomWithDimensions(config, Atom.ION_HEAP_SIZE_FIELD_NUMBER, null);
+        uploadConfig(config);
+        Thread.sleep(WAIT_TIME_SHORT);
+
+        // Start test app and trigger a pull while it is running.
+        try (AutoCloseable a = withActivity("StatsdCtsForegroundActivity", "action",
+                "action.show_notification")) {
+            setAppBreadcrumbPredicate();
+            Thread.sleep(WAIT_TIME_LONG);
+        }
+
+        List<Atom> atoms = getGaugeMetricDataList();
+        assertThat(atoms).hasSize(1);
+        IonHeapSize ionHeapSize = atoms.get(0).getIonHeapSize();
+        assertThat(ionHeapSize.getTotalSizeKb()).isGreaterThan(0);
+    }
+
+    private boolean fileExists(String path) throws Exception {
+        String commandFormat = "test -f %s && echo \"yes\" || echo \"no\"";
+        String result = getDevice().executeShellCommand(String.format(commandFormat, path));
+        return result.trim().equals("yes");
+    }
+
     /**
      * The the app id from a uid.
      *
diff --git a/tests/JobScheduler/OWNERS b/tests/JobScheduler/OWNERS
index ef7929f..3101b90 100644
--- a/tests/JobScheduler/OWNERS
+++ b/tests/JobScheduler/OWNERS
@@ -1,2 +1,5 @@
 # Bug component: 330738
-ctate@google.com
\ No newline at end of file
+ctate@google.com
+kwekua@google.com
+omakoto@google.com
+yamasani@google.com
\ No newline at end of file
diff --git a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
index 63ab4bb..d891e54 100644
--- a/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
+++ b/tests/JobScheduler/src/android/jobscheduler/cts/BatteryConstraintTest.java
@@ -109,19 +109,15 @@
             Thread.sleep(50);
             curSeq = Integer.parseInt(SystemUtil.runShellCommand(getInstrumentation(),
                     "cmd jobscheduler get-battery-seq").trim());
-            // The job scheduler actually looks at the charging/discharging state,
-            // which is currently determined by battery stats in response to the low-level
-            // plugged/unplugged events.  So we can get this updated after the last seq
-            // is received, so we need to make sure that has correctly changed.
             curCharging = Boolean.parseBoolean(SystemUtil.runShellCommand(getInstrumentation(),
                     "cmd jobscheduler get-battery-charging").trim());
-            if (curSeq == seq && curCharging == plugged) {
+            if (curSeq >= seq && curCharging == plugged) {
                 return;
             }
         } while ((SystemClock.elapsedRealtime() - startTime) < 5000);
 
         fail("Timed out waiting for job scheduler: expected seq=" + seq + ", cur=" + curSeq
-                + ", plugged=" + plugged + " curCharging=" + curCharging);
+                + ", expected plugged=" + plugged + " curCharging=" + curCharging);
     }
 
     void verifyChargingState(boolean charging) throws Exception {
diff --git a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
index a59330c..0539a31 100644
--- a/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
+++ b/tests/accessibility/src/android/view/accessibility/cts/AccessibilityNodeInfoTest.java
@@ -524,7 +524,6 @@
         //         labeledby: AccessibilityEndToEndTest#testLabelForReportedToAccessibility
         //         windowid: Not directly observable
         //         sourceid: Not directly observable
-        //         TODO(b/147393134): Need to test if we could get leashed child/parent properly.
         //         leashedChild: Not directly accessible
         //         leashedParent: Not directly accessible
         //         leashedParentNodeId: Not directly accessible
@@ -640,7 +639,6 @@
         //  labeledby (can't be performed on sealed instance, even if null)
         //  sourceId (not directly observable)
         //  windowId (not directly observable)
-        //  TODO(b/147393134): Need to test if we could get leashed child/parent properly.
         //  leashedChild (not directly observable)
         //  leashedParent (not directly observable)
         //  leashedParentNodeId (not directly observable)
diff --git a/tests/accessibilityservice/AndroidManifest.xml b/tests/accessibilityservice/AndroidManifest.xml
index e75a065..f656804 100644
--- a/tests/accessibilityservice/AndroidManifest.xml
+++ b/tests/accessibilityservice/AndroidManifest.xml
@@ -80,6 +80,12 @@
             android:name=".AccessibilityEmbeddedDisplayTest$EmbeddedDisplayActivity"
             android:screenOrientation="locked" />
 
+        <activity
+            android:label="@string/accessibility_embedded_hierarchy_test_activity"
+            android:name=".AccessibilityEmbeddedHierarchyTest$AccessibilityEmbeddedHierarchyActivity"
+            android:theme="@android:style/Theme.Dialog"
+            android:screenOrientation="locked"/>
+
         <service
                 android:name=".StubGestureAccessibilityService"
                 android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE">
diff --git a/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_embedded_side.xml b/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_embedded_side.xml
new file mode 100644
index 0000000..ab149f2
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_embedded_side.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<Button xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/embedded_button"
+        android:text="@string/button_title"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
\ No newline at end of file
diff --git a/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_host_side.xml b/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_host_side.xml
new file mode 100644
index 0000000..88a4100
--- /dev/null
+++ b/tests/accessibilityservice/res/layout/accessibility_embedded_hierarchy_test_host_side.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:layout_width="200px"
+              android:layout_height="200px"
+              android:orientation="vertical">
+
+    <SurfaceView
+        android:id="@+id/host_surfaceview"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_gravity="center" />
+
+</LinearLayout>
diff --git a/tests/accessibilityservice/res/values/strings.xml b/tests/accessibilityservice/res/values/strings.xml
index dc6102e..73ffb68 100644
--- a/tests/accessibilityservice/res/values/strings.xml
+++ b/tests/accessibilityservice/res/values/strings.xml
@@ -187,4 +187,9 @@
     <!-- String the default label of AccessibilityAction ACTION_IME_ENTER -->
     <string name="accessibility_action_ime_enter_label">Enter</string>
 
+    <!-- AccessibilityEmbeddedHierarchyTest -->
+
+    <!-- String title of accessibility embedded hierarchy test activity -->
+    <string name="accessibility_embedded_hierarchy_test_activity">Accessibility embedded hierarchy test</string>
+
 </resources>
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
new file mode 100644
index 0000000..4111baf
--- /dev/null
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityEmbeddedHierarchyTest.java
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 2020 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.accessibilityservice.cts;
+
+import static android.accessibilityservice.cts.utils.ActivityLaunchUtils.launchActivityAndWaitForItToBeOnscreen;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
+import android.accessibilityservice.AccessibilityServiceInfo;
+import android.accessibilityservice.cts.activities.AccessibilityTestActivity;
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.rule.ActivityTestRule;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.RuleChain;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Tests that AccessibilityNodeInfos from an embedded hierarchy that is present to another
+ * hierarchy are properly populated.
+ */
+@RunWith(AndroidJUnit4.class)
+public class AccessibilityEmbeddedHierarchyTest {
+    private static Instrumentation sInstrumentation;
+    private static UiAutomation sUiAutomation;
+
+    private final ActivityTestRule<AccessibilityEmbeddedHierarchyActivity> mActivityRule =
+            new ActivityTestRule<>(AccessibilityEmbeddedHierarchyActivity.class, false, false);
+
+    private static final String HOST_VIEW_RESOURCE_NAME =
+            "android.accessibilityservice.cts:id/host_surfaceview";
+    private static final String EMBEDDED_VIEW_RESOURCE_NAME =
+            "android.accessibilityservice.cts:id/embedded_button";
+
+    private final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
+            new AccessibilityDumpOnFailureRule();
+
+    @Rule
+    public final RuleChain mRuleChain = RuleChain
+            .outerRule(mActivityRule)
+            .around(mDumpOnFailureRule);
+
+    @BeforeClass
+    public static void oneTimeSetup() {
+        sInstrumentation = InstrumentationRegistry.getInstrumentation();
+        sUiAutomation = sInstrumentation.getUiAutomation();
+        AccessibilityServiceInfo info = sUiAutomation.getServiceInfo();
+        info.flags |= AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE;
+        sUiAutomation.setServiceInfo(info);
+    }
+
+    @AfterClass
+    public static void postTestTearDown() {
+        sUiAutomation.destroy();
+    }
+
+    @Before
+    public void setUp() throws Throwable {
+        launchActivityAndWaitForItToBeOnscreen(sInstrumentation, sUiAutomation, mActivityRule)
+                .waitForEmbeddedHierarchy();
+    }
+
+    @Test
+    public void testEmbeddedViewCanBeFound() {
+        final AccessibilityNodeInfo target =
+                findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+        assertNotNull(target);
+    }
+
+    @Test
+    public void testEmbeddedViewCanFindItsHostParent() {
+        final AccessibilityNodeInfo target =
+                findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+        final AccessibilityNodeInfo parent = target.getParent();
+        assertTrue(HOST_VIEW_RESOURCE_NAME.equals(parent.getViewIdResourceName()));
+    }
+
+    @Test
+    public void testEmbeddedViewHasCorrectBound() {
+        final AccessibilityNodeInfo target =
+                findEmbeddedAccessibilityNodeInfo(sUiAutomation.getRootInActiveWindow());
+        final AccessibilityNodeInfo parent = target.getParent();
+        final Rect hostViewBoundsInScreen = new Rect();
+        final Rect embeddedViewBoundsInScreen = new Rect();
+        parent.getBoundsInScreen(hostViewBoundsInScreen);
+        target.getBoundsInScreen(embeddedViewBoundsInScreen);
+
+        assertTrue("hostViewBoundsInScreen" + hostViewBoundsInScreen.toShortString()
+                        + " doesn't contain embeddedViewBoundsInScreen"
+                        + embeddedViewBoundsInScreen.toShortString(),
+                hostViewBoundsInScreen.contains(embeddedViewBoundsInScreen));
+    }
+
+    private AccessibilityNodeInfo findEmbeddedAccessibilityNodeInfo(AccessibilityNodeInfo root) {
+        final int childCount = root.getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final AccessibilityNodeInfo info = root.getChild(i);
+            if (info == null) {
+                continue;
+            }
+            if (EMBEDDED_VIEW_RESOURCE_NAME.equals(info.getViewIdResourceName())) {
+                return info;
+            }
+            if (info.getChildCount() != 0) {
+                return findEmbeddedAccessibilityNodeInfo(info);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * This class is an dummy {@link android.app.Activity} used to perform embedded hierarchy
+     * testing of the accessibility feature by interaction with the UI widgets.
+     */
+    public static class AccessibilityEmbeddedHierarchyActivity extends
+            AccessibilityTestActivity implements SurfaceHolder.Callback {
+        private final CountDownLatch mCountDownLatch = new CountDownLatch(1);
+
+        private static final int DEFAULT_WIDTH = 200;
+        private static final int DEFAULT_HEIGHT = 200;
+
+        private SurfaceView mSurfaceView;
+        private SurfaceControlViewHost mViewHost;
+
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setContentView(R.layout.accessibility_embedded_hierarchy_test_host_side);
+            mSurfaceView = findViewById(R.id.host_surfaceview);
+            mSurfaceView.getHolder().addCallback(this);
+        }
+
+        @Override
+        public void surfaceCreated(SurfaceHolder holder) {
+            mViewHost = new SurfaceControlViewHost(this, this.getDisplay(),
+                    mSurfaceView.getHostToken());
+
+            mSurfaceView.setChildSurfacePackage(mViewHost.getSurfacePackage());
+
+            View layout = getLayoutInflater().inflate(
+                    R.layout.accessibility_embedded_hierarchy_test_embedded_side, null);
+            mViewHost.addView(layout, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+            mCountDownLatch.countDown();
+        }
+
+        @Override
+        public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+            // No-op
+        }
+
+        @Override
+        public void surfaceDestroyed(SurfaceHolder holder) {
+            // No-op
+        }
+
+        public void waitForEmbeddedHierarchy() {
+            try {
+                assertTrue("timed out waiting for embedded hierarchy to init.",
+                        mCountDownLatch.await(3, TimeUnit.SECONDS));
+            } catch (InterruptedException e) {
+                throw new AssertionError(e);
+            }
+        }
+    }
+}
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
index 494d4d4..be678913 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityGestureDetectorTest.java
@@ -238,6 +238,10 @@
                 twoFingerDoubleTap(displayId),
                 AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP,
                 displayId);
+                testGesture(
+                twoFingerDoubleTapAndHold(displayId),
+                AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP_AND_HOLD,
+                displayId);
         testGesture(
                 twoFingerTripleTap(displayId),
                 AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP,
@@ -251,6 +255,10 @@
                 threeFingerDoubleTap(displayId),
                 AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP,
                 displayId);
+                testGesture(
+                threeFingerDoubleTapAndHold(displayId),
+                AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP_AND_HOLD,
+                displayId);
         testGesture(
                 threeFingerTripleTap(displayId),
                 AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP,
@@ -264,6 +272,10 @@
                 fourFingerDoubleTap(displayId),
                 AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP,
                 displayId);
+                testGesture(
+                fourFingerDoubleTapAndHold(displayId),
+                AccessibilityService.GESTURE_4_FINGER_DOUBLE_TAP_AND_HOLD,
+                displayId);
         testGesture(
                 fourFingerTripleTap(displayId),
                 AccessibilityService.GESTURE_4_FINGER_TRIPLE_TAP,
@@ -525,6 +537,10 @@
         return multiFingerMultiTap(2, 2, displayId);
     }
 
+    private GestureDescription twoFingerDoubleTapAndHold(int displayId) {
+        return multiFingerMultiTapAndHold(2, 2, displayId);
+    }
+ 
     private GestureDescription twoFingerTripleTap(int displayId) {
         return multiFingerMultiTap(2, 3, displayId);
     }
@@ -537,6 +553,10 @@
         return multiFingerMultiTap(3, 2, displayId);
     }
 
+    private GestureDescription threeFingerDoubleTapAndHold(int displayId) {
+        return multiFingerMultiTapAndHold(3, 2, displayId);
+    }
+
     private GestureDescription threeFingerTripleTap(int displayId) {
         return multiFingerMultiTap(3, 3, displayId);
     }
@@ -549,6 +569,10 @@
         return multiFingerMultiTap(4, 2, displayId);
     }
 
+    private GestureDescription fourFingerDoubleTapAndHold(int displayId) {
+        return multiFingerMultiTapAndHold(4, 2, displayId);
+    }
+
     private GestureDescription fourFingerTripleTap(int displayId) {
         return multiFingerMultiTap(4, 3, displayId);
     }
@@ -562,6 +586,16 @@
                 base, FINGER_OFFSET_PX, fingerCount, tapCount, /* slop= */ 0, displayId);
     }
 
+    private GestureDescription multiFingerMultiTapAndHold(
+            int fingerCount, int tapCount, int displayId) {
+        // We dispatch the first finger, base, placed at left down side by an offset
+        // from the center of the display and the rest ones at right up side by delta
+        // from the base.
+        final PointF base = diff(mTapLocation, FINGER_OFFSET_PX);
+        return GestureUtils.multiFingerMultiTapAndHold(
+                base, FINGER_OFFSET_PX, fingerCount, tapCount, /* slop= */ 0, displayId);
+    }
+
     private GestureDescription MultiFingerSwipe(
             int displayId, int fingerCount, float dx, float dy) {
         float fingerOffset = 10f;
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
index c67d8c2..b694767 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/AccessibilityTakeScreenshotTest.java
@@ -28,6 +28,7 @@
 import android.graphics.ColorSpace;
 import android.graphics.Point;
 import android.hardware.HardwareBuffer;
+import android.os.SystemClock;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -77,7 +78,7 @@
 
     @Test
     public void testTakeScreenshot_GetScreenshotResult() {
-        mStartTestingTime = System.currentTimeMillis();
+        mStartTestingTime = SystemClock.uptimeMillis();
         Consumer<AccessibilityService.ScreenshotResult> screenshotConsumer =
                 new TakeScreenshotConsumer();
         mService.takeScreenshot(Display.DEFAULT_DISPLAY, mContext.getMainExecutor(),
diff --git a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
index c37898f..7f8a33c 100644
--- a/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
+++ b/tests/accessibilityservice/src/android/accessibilityservice/cts/utils/GestureUtils.java
@@ -332,4 +332,54 @@
         }
         return getGestureBuilder(displayId, strokes).build();
     }
+
+    /**
+     * Simulates a user placing multiple fingers on the specified screen
+     * and then multi-tapping and holding with these fingers.
+     *
+     * The location of fingers based on <code>basePoint<code/> are shifted by <code>delta<code/>.
+     * Like (baseX, baseY), (baseX + deltaX, baseY + deltaY), and so on.
+     *
+     * @param basePoint Where to place the first finger.
+     * @param delta Offset to basePoint where to place the 2nd or 3rd finger.
+     * @param fingerCount The number of fingers.
+     * @param tapCount The number of taps to fingers.
+     * @param slop Slop range the finger tapped.
+     * @param displayId Which display to dispatch the gesture.
+     */
+    public static GestureDescription multiFingerMultiTapAndHold(
+            PointF basePoint,
+            PointF delta,
+            int fingerCount,
+            int tapCount,
+            int slop,
+            int displayId) {
+        assertTrue(fingerCount >= 2);
+        assertTrue(tapCount > 0);
+        final int strokeCount = fingerCount * tapCount;
+        final PointF[] pointers = new PointF[fingerCount];
+        final StrokeDescription[] strokes = new StrokeDescription[strokeCount];
+
+        // The first tap
+        for (int i = 0; i < fingerCount; i++) {
+            pointers[i] = add(basePoint, times(i, delta));
+            strokes[i] = click(pointers[i]);
+        }
+        // The rest of taps
+        for (int tapIndex = 1; tapIndex < tapCount; tapIndex++) {
+            for (int i = 0; i < fingerCount; i++) {
+                final StrokeDescription lastStroke = strokes[(tapIndex - 1) * fingerCount + i];
+                final long nextStartTime = endTimeOf(lastStroke) + STROKE_TIME_GAP_MS;
+                final int nextIndex = tapIndex * fingerCount + i;
+                pointers[i] = getPointWithinSlop(pointers[i], slop);
+                if (tapIndex + 1 == tapCount) {
+                    // Last tap so do long click.
+                    strokes[nextIndex] = startingAt(nextStartTime, longClick(pointers[i]));
+                } else {
+                    strokes[nextIndex] = startingAt(nextStartTime, click(pointers[i]));
+                }
+            }
+        }
+        return getGestureBuilder(displayId, strokes).build();
+    }
 }
diff --git a/tests/backup/AndroidManifest.xml b/tests/backup/AndroidManifest.xml
index 542c41f..22c2531 100644
--- a/tests/backup/AndroidManifest.xml
+++ b/tests/backup/AndroidManifest.xml
@@ -18,6 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.backup.cts">
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" />
diff --git a/tests/camera/libctscamera2jni/native-camera-jni.cpp b/tests/camera/libctscamera2jni/native-camera-jni.cpp
index db77d79..9dcc34f 100644
--- a/tests/camera/libctscamera2jni/native-camera-jni.cpp
+++ b/tests/camera/libctscamera2jni/native-camera-jni.cpp
@@ -4068,25 +4068,28 @@
 
     ret = ACameraMetadata_getConstEntry(ndkResult, ACAMERA_SENSOR_TIMESTAMP,
         &entry);
-    ACameraMetadata_free(ndkResult);
 
     if (ret != ACAMERA_OK) {
         ALOGE("validateCriticalTags failed: "
               "ACameraMetadata_getConstEntry returned %d.", ret);
+        ACameraMetadata_free(ndkResult);
         return false;
     }
     if (entry.type != ACAMERA_TYPE_INT64) {
         ALOGE("validateCriticalTags failed: entry.type is %u but should be %u.",
               entry.type, ACAMERA_TYPE_INT64);
+        ACameraMetadata_free(ndkResult);
         return false;
     }
     if (entry.count != 1) {
         ALOGE("validateCriticalTags failed: entry.count is %u but should be %u.",
               entry.count, 1);
+        ACameraMetadata_free(ndkResult);
         return false;
     }
     if (entry.data.i64 == nullptr) {
         ALOGE("validateCriticalTags failed: entry.data.i64 is nullptr.");
+        ACameraMetadata_free(ndkResult);
         return false;
     }
 
@@ -4094,9 +4097,82 @@
     const int64_t ndkTimestampI64 = *(entry.data.i64);
     ALOGV("javaTimestampI64 = %" PRId64 ", ndkTimestampI64 = %" PRId64,
           javaTimestampI64, ndkTimestampI64);
+
+    ACameraMetadata_free(ndkResult);
+
     return (javaTimestampI64 == ndkTimestampI64);
 }
 
+static ACameraMetadata *sStashedMetadata = nullptr;
+
+// Test holding on to a ACameraMetadata past a single local JNI call
+extern "C" jboolean
+Java_android_hardware_camera2_cts_CaptureResultTest_\
+stashACameraMetadataFromCameraMetadataNative(
+        JNIEnv* env, jclass /*clazz*/, jobject captureResult) {
+    ALOGV("%s", __FUNCTION__);
+    ACameraMetadata* ndkResult =
+        ACameraMetadata_fromCameraMetadata(env, captureResult);
+    if (ndkResult == nullptr) return false;
+    sStashedMetadata = ndkResult;
+
+    return true;
+}
+
+extern "C" jboolean
+Java_android_hardware_camera2_cts_CaptureResultTest_\
+validateStashedACameraMetadataFromCameraMetadataNative(
+        JNIEnv* env, jclass /*clazz*/, jlong timestamp) {
+    ALOGV("%s", __FUNCTION__);
+    if (sStashedMetadata == nullptr) return false;
+
+    camera_status_t ret;
+    ACameraMetadata_const_entry entry;
+
+    ret = ACameraMetadata_getConstEntry(sStashedMetadata, ACAMERA_SENSOR_TIMESTAMP,
+        &entry);
+
+    if (ret != ACAMERA_OK) {
+        ALOGE("validateStashed failed: "
+              "ACameraMetadata_getConstEntry returned %d.", ret);
+        ACameraMetadata_free(sStashedMetadata);
+        sStashedMetadata = nullptr;
+        return false;
+    }
+    if (entry.type != ACAMERA_TYPE_INT64) {
+        ALOGE("validateStashed failed: entry.type is %u but should be %u.",
+              entry.type, ACAMERA_TYPE_INT64);
+        ACameraMetadata_free(sStashedMetadata);
+        sStashedMetadata = nullptr;
+        return false;
+    }
+    if (entry.count != 1) {
+        ALOGE("validateStashed failed: entry.count is %u but should be %u.",
+              entry.count, 1);
+        ACameraMetadata_free(sStashedMetadata);
+        sStashedMetadata = nullptr;
+        return false;
+    }
+    if (entry.data.i64 == nullptr) {
+        ALOGE("validateStashed failed: entry.data.i64 is nullptr.");
+        ACameraMetadata_free(sStashedMetadata);
+        sStashedMetadata = nullptr;
+        return false;
+    }
+
+    const int64_t javaTimestampI64 = static_cast<int64_t>(timestamp);
+    const int64_t ndkTimestampI64 = *(entry.data.i64);
+
+    ACameraMetadata_free(sStashedMetadata);
+    sStashedMetadata = nullptr;
+    ALOGV("javaTimestampI64 = %" PRId64 ", ndkTimestampI64 = %" PRId64,
+          javaTimestampI64, ndkTimestampI64);
+    return (javaTimestampI64 == ndkTimestampI64);
+
+}
+
+
+
 extern "C" jboolean
 Java_android_hardware_camera2_cts_CameraManagerTest_\
 validateACameraMetadataFromCameraMetadataCriticalTagsNative(
diff --git a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
index e2d3a7b..5940493 100644
--- a/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
+++ b/tests/camera/src/android/hardware/camera2/cts/CaptureResultTest.java
@@ -270,6 +270,8 @@
             ImageReader previewReader = null;
             ImageReader jpegReader = null;
 
+            CaptureResult resultForNdk = null;
+
             SimpleImageReaderListener jpegListener = new SimpleImageReaderListener();
             SimpleImageReaderListener prevListener = new SimpleImageReaderListener();
             try {
@@ -368,11 +370,41 @@
                         resultDiff, clockDiff);
                 mCollector.expectGreater("Timestamps must be increasing.", result3.second,
                         result4.second);
+
+                resultForNdk = result.first;
             } finally {
                 closeDevice(id);
                 closeImageReader(previewReader);
                 closeImageReader(jpegReader);
             }
+
+            mCollector.expectTrue(
+                "validateACameraMetadataFromCameraMetadataCriticalTagsNative failed",
+                validateACameraMetadataFromCameraMetadataCriticalTagsNative(resultForNdk,
+                        resultForNdk.get(CaptureResult.SENSOR_TIMESTAMP)));
+
+            long timestamp = resultForNdk.get(CaptureResult.SENSOR_TIMESTAMP);
+            mCollector.expectTrue(
+                "stashACameraMetadataFromCameraMetadataNative failed",
+                stashACameraMetadataFromCameraMetadataNative(resultForNdk));
+
+            // Try to drop the Java side object here
+            resultForNdk = null;
+            int[] block = null;
+            final int count = 9;
+            for (int i = 0; i < count + 1; i++) {
+                block = new int[1000000];
+                block[1000 + i] = i;
+
+                Runtime.getRuntime().gc();
+                Runtime.getRuntime().runFinalization();
+
+                mCollector.expectTrue("This should never fail", block[1000 + i] == i);
+            }
+            mCollector.expectTrue(
+                "validateStashedACameraMetadataFromCameraMetadataNative failed",
+                validateStashedACameraMetadataFromCameraMetadataNative(timestamp));
+            mCollector.expectTrue("This should never fail", block[1000 + count] == count);
         }
     }
 
@@ -544,11 +576,6 @@
                 }
             }
         }
-
-        errorCollector.expectTrue(
-            "validateACameraMetadataFromCameraMetadataCriticalTagsNative failed",
-            validateACameraMetadataFromCameraMetadataCriticalTagsNative(result,
-                result.get(CaptureResult.SENSOR_TIMESTAMP)));
     }
 
     /*
@@ -924,6 +951,11 @@
     private static native boolean validateACameraMetadataFromCameraMetadataCriticalTagsNative(
         CaptureResult result, long sensorTimestamp);
 
+    // First stash a native ACameraMetadata created from a capture result, then compare the stored value
+    // to the passed-in timestamp.
+    private static native boolean stashACameraMetadataFromCameraMetadataNative(CaptureResult result);
+    private static native boolean validateStashedACameraMetadataFromCameraMetadataNative(long timestamp);
+
     /**
      * TODO: Use CameraCharacteristics.getAvailableCaptureResultKeys() once we can filter out
      * @hide keys.
diff --git a/tests/contentcaptureservice/AndroidManifest.xml b/tests/contentcaptureservice/AndroidManifest.xml
index f0d262f..3844378 100644
--- a/tests/contentcaptureservice/AndroidManifest.xml
+++ b/tests/contentcaptureservice/AndroidManifest.xml
@@ -90,6 +90,18 @@
             </intent-filter>
         </activity>
 
+        <activity android:name=".DataSharingActivity"
+                  android:label="DataSharing"
+                  android:taskAffinity=".DataSharingActivity"
+                  android:theme="@android:style/Theme.NoTitleBar">
+            <intent-filter>
+                <!-- This intent filter is not really needed by CTS, but it makes easier to launch
+                     this app during CTS development... -->
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
         <receiver android:name=".SelfDestructReceiver"
             android:exported="true"
             android:process="android.contentcapture.cts.outside"/>
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
index 840bd03..6f462a1 100644
--- a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/CtsContentCaptureService.java
@@ -22,8 +22,11 @@
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import android.content.ComponentName;
+import android.os.ParcelFileDescriptor;
 import android.service.contentcapture.ActivityEvent;
 import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.DataShareCallback;
+import android.service.contentcapture.DataShareReadAdapter;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
@@ -32,18 +35,23 @@
 import android.view.contentcapture.ContentCaptureEvent;
 import android.view.contentcapture.ContentCaptureSessionId;
 import android.view.contentcapture.DataRemovalRequest;
+import android.view.contentcapture.DataShareRequest;
 import android.view.contentcapture.ViewNode;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
 import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
 
 // TODO(b/123540602): if we don't move this service to a separate package, we need to handle the
 // onXXXX methods in a separate thread
@@ -58,6 +66,8 @@
     public static final ComponentName CONTENT_CAPTURE_SERVICE_COMPONENT_NAME =
             componentNameFor(CtsContentCaptureService.class);
 
+    private static final Executor sExecutor = Executors.newCachedThreadPool();
+
     private static int sIdCounter;
 
     private static ServiceWatcher sServiceWatcher;
@@ -125,6 +135,24 @@
      */
     private boolean mIgnoreOrphanSessionEvents;
 
+    /**
+     * Whether the service should accept a data share session.
+     */
+    private boolean mDataShareShouldAccept = false;
+
+    /**
+     * Bytes that were shared during the content capture
+     */
+    byte[] mDataShared = new byte[20_000];
+
+    /**
+     * The fields below represent state of the content capture data sharing session.
+     */
+    boolean mDataShareSessionStarted = false;
+    boolean mDataShareSessionFinished = false;
+    boolean mDataShareSessionSucceeded = false;
+    int mDataShareSessionErrorCode = 0;
+
     @NonNull
     public static ServiceWatcher setServiceWatcher() {
         if (sServiceWatcher != null) {
@@ -297,6 +325,43 @@
     }
 
     @Override
+    public void onDataShareRequest(DataShareRequest request, DataShareCallback callback) {
+        if (mDataShareShouldAccept) {
+            callback.onAccept(sExecutor, new DataShareReadAdapter() {
+                @Override
+                public void onStart(ParcelFileDescriptor fd) {
+                    mDataShareSessionStarted = true;
+
+                    int bytesReadTotal = 0;
+                    try (InputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(fd)) {
+                        while (true) {
+                            int bytesRead = fis.read(mDataShared, bytesReadTotal,
+                                    mDataShared.length - bytesReadTotal);
+                            if (bytesRead == -1) {
+                                break;
+                            }
+                            bytesReadTotal += bytesRead;
+                        }
+                        mDataShareSessionFinished = true;
+                        mDataShareSessionSucceeded = true;
+                    } catch (IOException e) {
+                        // fall through. dataShareSessionSucceeded will stay false.
+                    }
+                }
+
+                @Override
+                public void onError(int errorCode) {
+                    mDataShareSessionFinished = true;
+                    mDataShareSessionErrorCode = errorCode;
+                }
+            });
+        } else {
+            callback.onReject();
+            mDataShareSessionStarted = mDataShareSessionFinished = true;
+        }
+    }
+
+    @Override
     public void onActivityEvent(ActivityEvent event) {
         Log.i(TAG, "onActivityEvent(): " + event);
         mActivityEvents.add(new MyActivityEvent(event));
@@ -361,6 +426,10 @@
         return mOnDisconnectListener;
     }
 
+    public void setDataSharingEnabled(boolean enabled) {
+        this.mDataShareShouldAccept = enabled;
+    }
+
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         super.dump(fd, pw, args);
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivity.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivity.java
new file mode 100644
index 0000000..1964abf
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivity.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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.contentcaptureservice.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.LocusId;
+import android.contentcaptureservice.cts.CtsContentCaptureService.Session;
+import android.os.ParcelFileDescriptor;
+import android.view.contentcapture.ContentCaptureManager;
+import android.view.contentcapture.DataShareRequest;
+import android.view.contentcapture.DataShareWriteAdapter;
+
+import androidx.annotation.NonNull;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Random;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
+public class DataSharingActivity extends AbstractContentCaptureActivity {
+
+    private static final Executor sExecutor = Executors.newCachedThreadPool();
+    private static final Random sRandom = new Random();
+
+    boolean mSessionFinished = false;
+    boolean mSessionSucceeded = false;
+    int mSessionErrorCode = 0;
+    boolean mSessionRejected = false;
+    byte[] mDataWritten = new byte[10_000];
+
+    @Override
+    public void onStart() {
+        super.onStart();
+
+        ContentCaptureManager manager =
+                getApplicationContext().getSystemService(ContentCaptureManager.class);
+
+        assertThat(manager).isNotNull();
+        assertThat(manager.isContentCaptureEnabled()).isTrue();
+
+        manager.shareData(
+                new DataShareRequest(new LocusId("cts"), "application/octet-stream"),
+                sExecutor, new DataShareWriteAdapter() {
+                    @Override
+                    public void onWrite(ParcelFileDescriptor destination) {
+                        sRandom.nextBytes(mDataWritten);
+
+                        try (OutputStream outputStream =
+                                     new ParcelFileDescriptor.AutoCloseOutputStream(destination)) {
+                            outputStream.write(mDataWritten);
+                        } catch (IOException e) {
+                            // fall through, sessionSucceeded will stay false.
+                        }
+
+                        mSessionSucceeded = true;
+                        mSessionFinished = true;
+                    }
+
+                    @Override
+                    public void onRejected() {
+                        mSessionRejected = true;
+                        mSessionSucceeded = false;
+                        mSessionFinished = true;
+                    }
+
+                    @Override
+                    public void onError(int errorCode) {
+                        mSessionErrorCode = errorCode;
+                        mSessionSucceeded = false;
+                        mSessionFinished = true;
+                    }
+                });
+    }
+
+    @Override
+    public void assertDefaultEvents(@NonNull Session session) {
+        // Do nothing - this test operates with file sharing.
+    }
+}
diff --git a/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivityTest.java b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivityTest.java
new file mode 100644
index 0000000..4a2d4be
--- /dev/null
+++ b/tests/contentcaptureservice/src/android/contentcaptureservice/cts/DataSharingActivityTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2020 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.contentcaptureservice.cts;
+
+import static com.android.compatibility.common.util.ActivitiesWatcher.ActivityLifecycle.RESUMED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.rule.ActivityTestRule;
+
+import com.android.compatibility.common.util.ActivitiesWatcher;
+import com.android.compatibility.common.util.PollingCheck;
+
+import org.junit.Test;
+
+import java.util.Arrays;
+
+@AppModeFull(reason = "BlankWithTitleActivityTest is enough")
+public class DataSharingActivityTest
+        extends AbstractContentCaptureIntegrationAutoActivityLaunchTest<DataSharingActivity>  {
+
+    private static final String TAG = DataSharingActivityTest.class.getSimpleName();
+
+    private static final ActivityTestRule<DataSharingActivity> sActivityRule =
+            new ActivityTestRule<>(DataSharingActivity.class, false, false);
+
+    public DataSharingActivityTest() {
+        super(DataSharingActivity.class);
+    }
+
+    @Override
+    protected ActivityTestRule<DataSharingActivity> getActivityTestRule() {
+        return sActivityRule;
+    }
+
+    @Test
+    public void testHappyPath_dataCopiedSuccessfully() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivitiesWatcher.ActivityWatcher watcher = startWatcher();
+
+        service.setDataSharingEnabled(true);
+
+        DataSharingActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        PollingCheck.waitFor(() -> activity.mSessionFinished);
+        PollingCheck.waitFor(() -> service.mDataShareSessionFinished);
+
+        assertThat(activity.mSessionSucceeded).isTrue();
+        assertThat(service.mDataShareSessionSucceeded).isTrue();
+
+        assertThat(activity.mDataWritten).isEqualTo(
+                Arrays.copyOfRange(service.mDataShared, 0, activity.mDataWritten.length));
+    }
+
+    @Test
+    public void testDataSharingSessionIsRejected_propagatedToClient() throws Exception {
+        final CtsContentCaptureService service = enableService();
+        final ActivitiesWatcher.ActivityWatcher watcher = startWatcher();
+
+        service.setDataSharingEnabled(false);
+
+        DataSharingActivity activity = launchActivity();
+        watcher.waitFor(RESUMED);
+
+        PollingCheck.waitFor(() -> activity.mSessionFinished);
+        PollingCheck.waitFor(() -> service.mDataShareSessionFinished);
+
+        assertThat(activity.mSessionSucceeded).isFalse();
+        assertThat(service.mDataShareSessionSucceeded).isFalse();
+
+        assertThat(activity.mSessionRejected).isTrue();
+    }
+}
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 147fb8d..f6113bf 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -551,6 +551,9 @@
             android:name=".PopupMinimalPostProcessingActivity"
             android:theme="@android:style/Theme.Holo.Dialog.NoActionBar"
             android:exported="true" />
+        <activity
+            android:name=".PresentationActivity"
+            android:exported="true" />
     </application>
 </manifest>
 
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
index 75972b4..300398d 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/Components.java
@@ -17,8 +17,8 @@
 package android.server.wm.app;
 
 import android.content.ComponentName;
-import android.server.wm.component.ComponentsBase;
 import android.server.wm.TestJournalProvider;
+import android.server.wm.component.ComponentsBase;
 
 public class Components extends ComponentsBase {
     public static final ComponentName ALT_LAUNCHING_ACTIVITY = component("AltLaunchingActivity");
@@ -73,6 +73,7 @@
     public static final ComponentName NO_HISTORY_ACTIVITY = component("NoHistoryActivity");
     public static final ComponentName NO_RELAUNCH_ACTIVITY = component("NoRelaunchActivity");
     public static final ComponentName NON_RESIZEABLE_ACTIVITY = component("NonResizeableActivity");
+    public static final ComponentName PRESENTATION_ACTIVITY = component("PresentationActivity");
     public static final ComponentName PIP_ACTIVITY = component("PipActivity");
     public static final ComponentName PIP_ACTIVITY2 = component("PipActivity2");
     public static final ComponentName PIP_ACTIVITY_WITH_SAME_AFFINITY =
@@ -235,8 +236,10 @@
         public static final String EXTRA_FIXED_ORIENTATION = "fixed_orientation";
         public static final String EXTRA_CONFIGURATION = "configuration";
         public static final String EXTRA_CONFIG_ASSETS_SEQ = "config_assets_seq";
+        public static final String EXTRA_INTENT = "intent";
         public static final String EXTRA_INTENTS = "intents";
         public static final String EXTRA_NO_IDLE = "no_idle";
+        public static final String COMMAND_NAVIGATE_UP_TO = "navigate_up_to";
         public static final String COMMAND_START_ACTIVITIES = "start_activities";
     }
 
@@ -468,6 +471,10 @@
         public static final String ACTION_TOAST_TAP_DETECTED = "toast_tap_detected";
     }
 
+    public static class PresentationActivity {
+        public static final String KEY_DISPLAY_ID = "display_id";
+    }
+
     private static ComponentName component(String className) {
         return component(Components.class, className);
     }
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/PresentationActivity.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PresentationActivity.java
new file mode 100644
index 0000000..fc5490e
--- /dev/null
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/PresentationActivity.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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.app;
+
+import android.app.Activity;
+import android.app.Presentation;
+import android.graphics.Color;
+import android.hardware.display.DisplayManager;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Display;
+import android.view.Gravity;
+import android.view.WindowManager;
+import android.widget.TextView;
+
+public class PresentationActivity extends Activity {
+
+    private static final String TAG = PresentationActivity.class.getSimpleName();
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        int displayId = getIntent().getExtras().getInt(
+                Components.PresentationActivity.KEY_DISPLAY_ID);
+
+        Display presentationDisplay =
+                getSystemService(DisplayManager.class).getDisplay(displayId);
+
+        createPresentationWindow(presentationDisplay);
+    }
+
+    private void createPresentationWindow(Display display) {
+        final TextView view = new TextView(this);
+        view.setText("I'm a presentation");
+        view.setGravity(Gravity.CENTER);
+        view.setBackgroundColor(Color.RED);
+
+        final Presentation presentation = new Presentation(this, display);
+        presentation.setContentView(view);
+        presentation.setTitle(getPackageName());
+        try {
+            presentation.show();
+        } catch (WindowManager.InvalidDisplayException e) {
+            Log.w(TAG, "Presentation blocked", e);
+        }
+    }
+}
diff --git a/tests/framework/base/windowmanager/app_base/src/android/server/wm/app/TestActivity.java b/tests/framework/base/windowmanager/app_base/src/android/server/wm/app/TestActivity.java
index 2afd545..5bb4fd1 100644
--- a/tests/framework/base/windowmanager/app_base/src/android/server/wm/app/TestActivity.java
+++ b/tests/framework/base/windowmanager/app_base/src/android/server/wm/app/TestActivity.java
@@ -16,9 +16,11 @@
 
 package android.server.wm.app;
 
+import static android.server.wm.app.Components.TestActivity.COMMAND_NAVIGATE_UP_TO;
 import static android.server.wm.app.Components.TestActivity.EXTRA_CONFIG_ASSETS_SEQ;
 import static android.server.wm.app.Components.TestActivity.EXTRA_FIXED_ORIENTATION;
 import static android.server.wm.app.Components.TestActivity.EXTRA_INTENTS;
+import static android.server.wm.app.Components.TestActivity.EXTRA_INTENT;
 import static android.server.wm.app.Components.TestActivity.EXTRA_NO_IDLE;
 import static android.server.wm.app.Components.TestActivity.TEST_ACTIVITY_ACTION_FINISH_SELF;
 import static android.server.wm.app.Components.TestActivity.COMMAND_START_ACTIVITIES;
@@ -109,6 +111,9 @@
                 final Parcelable[] intents = data.getParcelableArray(EXTRA_INTENTS);
                 startActivities(Arrays.copyOf(intents, intents.length, Intent[].class));
                 break;
+            case COMMAND_NAVIGATE_UP_TO:
+                navigateUpTo(data.getParcelable(EXTRA_INTENT));
+                break;
             default:
                 super.handleCommand(command, data);
         }
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json b/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json
new file mode 100644
index 0000000..78fe375
--- /dev/null
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/single-instance_for-result.json
@@ -0,0 +1,66 @@
+{
+    "setup": {
+        "initialIntents": [
+            {
+                "flags": "FLAG_ACTIVITY_NEW_TASK",
+                "class": "android.server.wm.intent.Activities$TaskAffinity1Activity",
+                "package": "android.server.wm.cts",
+                "startForResult": false
+            }
+        ],
+        "act": [
+            {
+                "flags": "",
+                "class": "android.server.wm.intent.Activities$SingleInstanceActivity",
+                "package": "android.server.wm.cts",
+                "startForResult": true
+            }
+        ]
+    },
+    "initialState": {
+        "stacks": [
+            {
+                "tasks": [
+                    {
+                        "activities": [
+                            {
+                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
+                                "state": "RESUMED"
+                            }
+                        ]
+                    }
+                ],
+                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity"
+            }
+        ]
+    },
+    "endState": {
+        "stacks": [
+            {
+                "tasks": [
+                    {
+                        "activities": [
+                            {
+                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
+                                "state": "RESUMED"
+                            }
+                        ]
+                    }
+                ],
+                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity"
+            },
+            {
+                "tasks": [
+                    {
+                        "activities": [
+                            {
+                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$TaskAffinity1Activity",
+                                "state": "STOPPED"
+                            }
+                        ]
+                    }
+                ]
+            }
+        ]
+    }
+}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json b/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json
new file mode 100644
index 0000000..a288a9e
--- /dev/null
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/single-top_for-result.json
@@ -0,0 +1,54 @@
+{
+    "setup": {
+        "initialIntents": [
+            {
+                "flags": "FLAG_ACTIVITY_NEW_TASK",
+                "class": "android.server.wm.intent.Activities$SingleTopActivity",
+                "package": "android.server.wm.cts",
+                "startForResult": false
+            }
+        ],
+        "act": [
+            {
+                "flags": "",
+                "class": "android.server.wm.intent.Activities$SingleTopActivity",
+                "package": "android.server.wm.cts",
+                "startForResult": true
+            }
+        ]
+    },
+    "initialState": {
+        "stacks": [
+            {
+                "tasks": [
+                    {
+                        "activities": [
+                            {
+                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
+                                "state": "RESUMED"
+                            }
+                        ]
+                    }
+                ],
+                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+            }
+        ]
+    },
+    "endState": {
+        "stacks": [
+            {
+                "tasks": [
+                    {
+                        "activities": [
+                            {
+                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
+                                "state": "RESUMED"
+                            }
+                        ]
+                    }
+                ],
+                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity"
+            }
+        ]
+    }
+}
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
index 6e97377..a80e56b 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-2.json
@@ -43,10 +43,6 @@
                             {
                                 "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
                                 "state": "RESUMED"
-                            },
-                            {
-                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
-                                "state": "STOPPED"
                             }
                         ]
                     }
diff --git a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
index 2ed6023..a288a9e 100644
--- a/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
+++ b/tests/framework/base/windowmanager/intent_tests/forResult/test-4.json
@@ -43,10 +43,6 @@
                             {
                                 "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
                                 "state": "RESUMED"
-                            },
-                            {
-                                "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleTopActivity",
-                                "state": "STOPPED"
                             }
                         ]
                     }
diff --git a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
index 33419d6..be49412 100644
--- a/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
+++ b/tests/framework/base/windowmanager/intent_tests/newTask/test-15.json
@@ -43,15 +43,23 @@
                             {
                                 "name": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity",
                                 "state": "RESUMED"
-                            },
+                            }
+                        ]
+                    }
+                ],
+                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+            },
+            {
+                "tasks": [
+                    {
+                        "activities": [
                             {
                                 "name": "android.server.wm.cts\/android.server.wm.intent.Activities$SingleInstanceActivity",
                                 "state": "STOPPED"
                             }
                         ]
                     }
-                ],
-                "resumedActivity": "android.server.wm.cts\/android.server.wm.intent.Activities$RegularActivity"
+                ]
             }
         ]
     }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
index 2ec7a07..ec594d5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityMetricsLoggerTests.java
@@ -17,8 +17,11 @@
 package android.server.wm;
 
 import static android.os.SystemClock.sleep;
+import static android.server.wm.ActivityLauncher.KEY_LAUNCH_ACTIVITY;
+import static android.server.wm.ActivityLauncher.KEY_TARGET_COMPONENT;
 import static android.server.wm.WindowManagerState.STATE_STOPPED;
 import static android.server.wm.app.Components.ENTRY_POINT_ALIAS_ACTIVITY;
+import static android.server.wm.app.Components.LAUNCHING_ACTIVITY;
 import static android.server.wm.app.Components.NO_DISPLAY_ACTIVITY;
 import static android.server.wm.app.Components.REPORT_FULLY_DRAWN_ACTIVITY;
 import static android.server.wm.app.Components.SINGLE_TASK_ACTIVITY;
@@ -87,6 +90,9 @@
 @Presubmit
 public class ActivityMetricsLoggerTests extends ActivityManagerTestBase {
     private static final String TAG_ATM = "ActivityTaskManager";
+    private static final String LAUNCH_STATE_COLD = "COLD";
+    private static final String LAUNCH_STATE_WARM = "WARM";
+    private static final String LAUNCH_STATE_HOT = "HOT";
     private static final int EVENT_WM_ACTIVITY_LAUNCH_TIME = 30009;
     private final MetricsReader mMetricsReader = new MetricsReader();
     private long mPreUptimeMs;
@@ -246,17 +252,10 @@
 
         assertEquals("Expected a cold launch.", metricsLog.getType(), TYPE_TRANSITION_WARM_LAUNCH);
 
-        assertThat("did not find component in am start output.", amStartOutput,
-                containsString(TEST_ACTIVITY.flattenToShortString()));
-
-        assertThat("did not find windows drawn delay time in am start output.", amStartOutput,
-                containsString(Integer.toString(windowsDrawnDelayMs)));
-
-        assertThat("did not find launch state in am start output.", amStartOutput,
-                containsString("WARM"));
+        assertLaunchComponentStateAndTime(amStartOutput, TEST_ACTIVITY, LAUNCH_STATE_WARM,
+                windowsDrawnDelayMs);
     }
 
-
     /**
      * Hot launch an activity with wait option and verify that {@link android.app.WaitResult#totalTime}
      * totalTime is set correctly. Make sure the reported value is consistent with value reported to
@@ -283,14 +282,8 @@
 
         assertEquals("Expected a cold launch.", metricsLog.getType(), TYPE_TRANSITION_HOT_LAUNCH);
 
-        assertThat("did not find component in am start output.", amStartOutput,
-                containsString(TEST_ACTIVITY.flattenToShortString()));
-
-        assertThat("did not find windows drawn delay time in am start output.", amStartOutput,
-                containsString(Integer.toString(windowsDrawnDelayMs)));
-
-        assertThat("did not find launch state in am start output.", amStartOutput,
-                containsString("HOT"));
+        assertLaunchComponentStateAndTime(amStartOutput, TEST_ACTIVITY, LAUNCH_STATE_HOT,
+                windowsDrawnDelayMs);
     }
 
     /**
@@ -312,14 +305,8 @@
 
         assertEquals("Expected a cold launch.", metricsLog.getType(), TYPE_TRANSITION_COLD_LAUNCH);
 
-        assertThat("did not find component in am start output.", amStartOutput,
-                containsString(TEST_ACTIVITY.flattenToShortString()));
-
-        assertThat("did not find windows drawn delay time in am start output.", amStartOutput,
-                containsString(Integer.toString(windowsDrawnDelayMs)));
-
-        assertThat("did not find launch state in am start output.", amStartOutput,
-                containsString("COLD"));
+        assertLaunchComponentStateAndTime(amStartOutput, TEST_ACTIVITY, LAUNCH_STATE_COLD,
+                windowsDrawnDelayMs);
     }
 
     /**
@@ -412,6 +399,18 @@
                         postUptimeMs);
     }
 
+    /**
+     * Launch an activity which will start another activity immediately. The reported component
+     * name should be the last one with valid launch state.
+     */
+    @Test
+    public void testConsecutiveLaunch() {
+        final String amStartOutput = executeShellCommand("am start --ez " + KEY_LAUNCH_ACTIVITY
+                + " true --es " + KEY_TARGET_COMPONENT + " " + TEST_ACTIVITY.flattenToShortString()
+                + " -W " + LAUNCHING_ACTIVITY.flattenToShortString());
+        assertLaunchComponentState(amStartOutput, TEST_ACTIVITY, LAUNCH_STATE_COLD);
+    }
+
     @Test
     public void testLaunchTimeEventLogNonProcessSwitch() {
         launchAndWaitForActivity(SINGLE_TASK_ACTIVITY);
@@ -446,6 +445,21 @@
         return null;
     }
 
+    private static void assertLaunchComponentState(String amStartOutput, ComponentName component,
+            String state) {
+        assertThat("did not find component in am start output.", amStartOutput,
+                containsString(component.flattenToShortString()));
+        assertThat("did not find launch state in am start output.", amStartOutput,
+                containsString(state));
+    }
+
+    private static void assertLaunchComponentStateAndTime(String amStartOutput,
+            ComponentName component, String state, int windowsDrawnDelayMs) {
+        assertLaunchComponentState(amStartOutput, component, state);
+        assertThat("did not find windows drawn delay time in am start output.", amStartOutput,
+                containsString(Integer.toString(windowsDrawnDelayMs)));
+    }
+
     private void assertLogsContain(String[] logs, String expectedLog) {
         for (String line : logs) {
             if (line.contains(expectedLog)) {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AmProfileTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AmProfileTests.java
index 1a74ceb..a2c8a0e 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AmProfileTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AmProfileTests.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.CommandSession.ActivitySession;
+import android.server.wm.CommandSession.DefaultLaunchProxy;
 import android.server.wm.CommandSession.LaunchInjector;
 
 import androidx.test.filters.FlakyTest;
@@ -147,8 +148,7 @@
     /** Starts the activity with profiler. */
     private ActivitySession startActivityProfiling(ComponentName activityName, boolean sampling,
             boolean streaming) {
-        return createManagedActivityClientSession().startActivity(new CommandSession.LaunchProxy() {
-            LaunchInjector mLaunchInjector;
+        return createManagedActivityClientSession().startActivity(new DefaultLaunchProxy() {
 
             @Override
             public boolean shouldWaitForLaunched() {
@@ -157,11 +157,6 @@
             }
 
             @Override
-            public void setLaunchInjector(LaunchInjector injector) {
-                mLaunchInjector = injector;
-            }
-
-            @Override
             public void execute() {
                 final StringBuilder builder = new StringBuilder();
                 builder.append(String.format("am start -n %s -W -S --start-profiler %s",
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
index fe6b9c2..97a0bb8 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/KeyguardLockedTests.java
@@ -307,6 +307,8 @@
 
     @Test
     public void testShowWhenLockedAttrImeActivityAndShowSoftInput() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
 
@@ -326,6 +328,8 @@
 
     @Test
     public void testShowWhenLockedImeActivityAndShowSoftInput() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final LockScreenSession lockScreenSession = createManagedLockScreenSession();
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
         final TestActivitySession<ShowWhenLockedImeActivity> imeTestActivitySession =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
index bbde3a6..6d204a4 100755
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplayClientTests.java
@@ -151,6 +151,8 @@
 
     private void testDisplayIdUpdateWhenImeMove(Class<? extends ImeTestActivity> activityClass)
             throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final VirtualDisplaySession virtualDisplaySession = createManagedVirtualDisplaySession();
         final MockImeSession mockImeSession = MockImeHelper.createManagedMockImeSession(this);
 
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
index 842beb8..1e2e8c3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySecurityTests.java
@@ -836,6 +836,8 @@
 
     @Test
     public void testNoInputConnectionForUntrustedVirtualDisplay() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final long NOT_EXPECT_TIMEOUT = TimeUnit.SECONDS.toMillis(2);
 
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
index 41a7839..c454c84 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/MultiDisplaySystemDecorationTests.java
@@ -387,6 +387,8 @@
     // IME related tests
     @Test
     public void testImeWindowCanSwitchToDifferentDisplays() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
         final TestActivitySession<ImeTestActivity> imeTestActivitySession =
                 createManagedTestActivitySession();
@@ -434,6 +436,8 @@
 
     @Test
     public void testImeApiForBug118341760() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final long TIMEOUT_START_INPUT = TimeUnit.SECONDS.toMillis(5);
 
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
@@ -472,6 +476,7 @@
         // If config_perDisplayFocusEnabled, the focus will not move even if touching on
         // the Activity in the different display.
         assumeFalse(perDisplayFocusEnabled());
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
 
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
         final TestActivitySession<ImeTestActivity> imeTestActivitySession =
@@ -529,6 +534,8 @@
      */
     @Test
     public void testCrossDisplayBasicImeOperations() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
 
         final MockImeSession mockImeSession = createManagedMockImeSession(this);
@@ -581,6 +588,8 @@
 
     @Test
     public void testImeWindowCanShownWhenActivityMovedToDisplay() throws Exception {
+        assumeTrue(MSG_NO_MOCK_IME, supportsInstallableIme());
+
         // Launch a regular activity on default display at the test beginning to prevent the test
         // may mis-touch the launcher icon that breaks the test expectation.
         final TestActivitySession<Activities.RegularActivity> testActivitySession =
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java b/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java
new file mode 100644
index 0000000..77dc2c0
--- /dev/null
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PresentationTest.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright (C) 2020 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;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Intent;
+import android.hardware.display.DisplayManager;
+import android.platform.test.annotations.Presubmit;
+import android.server.wm.app.Components;
+import android.view.Display;
+
+import org.junit.Test;
+
+import java.util.List;
+
+@Presubmit
+public class PresentationTest extends MultiDisplayTestBase {
+
+    // WindowManager.LayoutParams.TYPE_PRESENTATION
+    private static final int TYPE_PRESENTATION = 2037;
+
+    @Test
+    public void testPresentationFollowsDisplayFlag() {
+        DisplayManager displayManager = mContext.getSystemService(DisplayManager.class);
+        for (Display display : displayManager.getDisplays()) {
+            launchPresentationActivity(display.getDisplayId());
+            if ((display.getFlags() & Display.FLAG_PRESENTATION) != Display.FLAG_PRESENTATION) {
+                assertNoPresentationDisplayed();
+            } else {
+                assertPresentationOnDisplay(display.getDisplayId());
+            }
+        }
+    }
+
+    @Test
+    public void testPresentationAllowedOnPresentationDisplay() {
+        WindowManagerState.DisplayContent display =
+                createManagedVirtualDisplaySession()
+                        .setPresentationDisplay(true)
+                        .setPublicDisplay(true)
+                        .createDisplay();
+
+        assertThat(display.getFlags() & Display.FLAG_PRESENTATION)
+                .isEqualTo(Display.FLAG_PRESENTATION);
+
+        launchPresentationActivity(display.mId);
+        assertPresentationOnDisplay(display.mId);
+    }
+
+    @Test
+    public void testPresentationBlockedOnNonPresentationDisplay() {
+        WindowManagerState.DisplayContent display =
+                createManagedVirtualDisplaySession()
+                        .setPresentationDisplay(false)
+                        .createDisplay();
+
+        assertThat(display.getFlags() & Display.FLAG_PRESENTATION).isEqualTo(0);
+        launchPresentationActivity(display.mId);
+        assertNoPresentationDisplayed();
+    }
+
+    private void assertNoPresentationDisplayed() {
+        final List<WindowManagerState.WindowState> presentationWindows =
+                mWmState.getWindowsByPackageName(
+                        Components.PRESENTATION_ACTIVITY.getPackageName(), TYPE_PRESENTATION);
+        assertThat(presentationWindows).isEmpty();
+    }
+
+    private void assertPresentationOnDisplay(int displayId) {
+        final List<WindowManagerState.WindowState> presentationWindows =
+                mWmState.getWindowsByPackageName(
+                        Components.PRESENTATION_ACTIVITY.getPackageName(), TYPE_PRESENTATION);
+        assertThat(presentationWindows).hasSize(1);
+        WindowManagerState.WindowState presentationWindowState = presentationWindows.get(0);
+        assertThat(presentationWindowState.getDisplayId()).isEqualTo(displayId);
+    }
+
+    private void launchPresentationActivity(int displayId) {
+        Intent intent = new Intent();
+        intent.setComponent(Components.PRESENTATION_ACTIVITY);
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(Components.PresentationActivity.KEY_DISPLAY_ID, displayId);
+        mContext.startActivity(intent);
+        waitAndAssertTopResumedActivity(
+                Components.PRESENTATION_ACTIVITY,
+                Display.DEFAULT_DISPLAY,
+                "Launched activity must be on top");
+    }
+}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
index 3f9d440..0b711b0 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/StartActivityTests.java
@@ -22,11 +22,14 @@
 import static android.server.wm.app.Components.NO_RELAUNCH_ACTIVITY;
 import static android.server.wm.app.Components.TEST_ACTIVITY;
 import static android.server.wm.app.Components.TRANSLUCENT_ACTIVITY;
+import static android.server.wm.app.Components.TestActivity.COMMAND_NAVIGATE_UP_TO;
+import static android.server.wm.app.Components.TestActivity.EXTRA_INTENT;
 import static android.server.wm.app.Components.TestActivity.EXTRA_INTENTS;
 import static android.server.wm.app.Components.TestActivity.COMMAND_START_ACTIVITIES;
 import static android.server.wm.app27.Components.SDK_27_LAUNCHING_ACTIVITY;
 import static android.server.wm.second.Components.SECOND_ACTIVITY;
 
+import static android.view.Display.DEFAULT_DISPLAY;
 import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertEquals;
@@ -38,6 +41,7 @@
 import android.os.Bundle;
 import android.platform.test.annotations.Presubmit;
 import android.server.wm.CommandSession.ActivitySession;
+import android.server.wm.intent.Activities;
 
 import androidx.test.rule.ActivityTestRule;
 
@@ -144,6 +148,51 @@
     }
 
     /**
+     * Starts 3 activities A, B, C in the same task. A and B belong to current package and are not
+     * exported. C belongs to a different package with different uid. After C called
+     * {@link Activity#navigateUpTo(Intent)} with the intent of A, the activities B, C should be
+     * finished and instead of creating a new instance of A, the original A should become the top
+     * activity because the caller C in different uid cannot launch a non-exported activity.
+     */
+    @Test
+    public void testStartActivityByNavigateUpToFromDiffUid() {
+        final Intent intent1 = new Intent(mContext, Activities.RegularActivity.class);
+        final TestActivitySession<Activities.RegularActivity> activitySession1 =
+                createManagedTestActivitySession();
+        activitySession1.launchTestActivityOnDisplaySync(intent1, DEFAULT_DISPLAY);
+        final TestActivitySession<Activities.SingleTopActivity> activitySession2 =
+                createManagedTestActivitySession();
+        activitySession2.launchTestActivityOnDisplaySync(Activities.SingleTopActivity.class,
+                DEFAULT_DISPLAY);
+
+        final CommandSession.ActivitySession activitySession3 =
+                createManagedActivityClientSession().startActivity(
+                        new CommandSession.DefaultLaunchProxy() {
+                            @Override
+                            public void execute() {
+                                final Intent intent = new Intent().setComponent(TEST_ACTIVITY);
+                                mLaunchInjector.setupIntent(intent);
+                                activitySession2.getActivity().startActivity(intent);
+                            }
+                        });
+
+        final Bundle data = new Bundle();
+        data.putParcelable(EXTRA_INTENT, intent1);
+        activitySession3.sendCommand(COMMAND_NAVIGATE_UP_TO, data);
+
+        waitAndAssertTopResumedActivity(intent1.getComponent(), DEFAULT_DISPLAY,
+                "navigateUpTo should return to the first activity");
+        // Make sure the resumed first activity is the original instance.
+        assertFalse("The target of navigateUpTo should not be destroyed",
+                activitySession1.getActivity().isDestroyed());
+
+        // The activities above the first one should be destroyed.
+        mWmState.waitAndAssertActivityRemoved(
+                activitySession3.getOriginalLaunchIntent().getComponent());
+        mWmState.waitAndAssertActivityRemoved(activitySession2.getActivity().getComponentName());
+    }
+
+    /**
      * Assume there are 3 activities (A1, A2, A3) with different task affinities and the same uid.
      * After A1 called {@link Activity#startActivities} to start A2 (with NEW_TASK) and A3, the
      * result should be 2 tasks: [A1] and [A2, A3].
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
index d007ebe..97377bf 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowCtsActivity.java
@@ -38,6 +38,7 @@
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         getWindow().requestFeature(Window.FEATURE_LEFT_ICON);
+        getWindow().setDecorFitsSystemWindows(true);
         setContentView(R.layout.windowstub_layout);
         getContentView().setOnApplyWindowInsetsListener((v, insets) -> {
             mLastInsets = insets;
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
index 4a4775f..60bc160 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -29,7 +29,7 @@
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowInsets.Type;
-import android.view.WindowInsetsAnimationCallback;
+import android.view.WindowInsetsAnimation;
 
 import com.android.compatibility.common.util.PollingCheck;
 import com.android.compatibility.common.util.SystemUtil;
@@ -37,6 +37,8 @@
 import org.junit.Ignore;
 import org.junit.Test;
 
+import java.util.List;
+
 /**
  * Test whether WindowInsetsController controls window insets as expected.
  *
@@ -199,22 +201,22 @@
                 () -> getInstrumentation().sendPointerSync(event));
     }
 
-    private static class AnimationCallback implements WindowInsetsAnimationCallback {
+    private static class AnimationCallback extends WindowInsetsAnimation.Callback {
 
         private boolean mFinished = false;
 
-        @Override
-        public int getDispatchMode() {
-            return DISPATCH_MODE_CONTINUE_ON_SUBTREE;
+        AnimationCallback() {
+            super(DISPATCH_MODE_CONTINUE_ON_SUBTREE);
         }
 
         @Override
-        public WindowInsets onProgress(WindowInsets insets) {
+        public WindowInsets onProgress(WindowInsets insets,
+                List<WindowInsetsAnimation> runningAnimations) {
             return insets;
         }
 
         @Override
-        public void onFinish(InsetsAnimation animation) {
+        public void onEnd(WindowInsetsAnimation animation) {
             synchronized (this) {
                 mFinished = true;
                 notify();
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
index 9ba003c..e4cb869 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/Activities.java
@@ -17,6 +17,7 @@
 package android.server.wm.intent;
 
 import android.app.Activity;
+import android.os.Bundle;
 
 /**
  * A collection of activities with various launch modes used in the intent tests.
@@ -27,60 +28,68 @@
  */
 public class Activities {
 
-    public static class TrackerActivity extends Activity {
+    private static class BaseActivity extends Activity {
+        @Override
+        protected void onCreate(Bundle savedInstanceState) {
+            super.onCreate(savedInstanceState);
+            setTitle(getClass().getSimpleName());
+        }
     }
 
-    public static class RegularActivity extends Activity {
+    public static class TrackerActivity extends BaseActivity {
     }
 
-    public static class SingleTopActivity extends Activity {
+    public static class RegularActivity extends BaseActivity {
     }
 
-    public static class SingleInstanceActivity extends Activity {
+    public static class SingleTopActivity extends BaseActivity {
     }
 
-    public static class SingleInstanceActivity2 extends Activity {
+    public static class SingleInstanceActivity extends BaseActivity {
     }
 
-    public static class SingleTaskActivity extends Activity {
+    public static class SingleInstanceActivity2 extends BaseActivity {
     }
 
-    public static class SingleTaskActivity2 extends Activity {
+    public static class SingleTaskActivity extends BaseActivity {
     }
 
-    public static class TaskAffinity1Activity extends Activity {
+    public static class SingleTaskActivity2 extends BaseActivity {
     }
 
-    public static class TaskAffinity1Activity2 extends Activity {
+    public static class TaskAffinity1Activity extends BaseActivity {
     }
 
-    public static class TaskAffinity2Activity extends Activity {
+    public static class TaskAffinity1Activity2 extends BaseActivity {
     }
 
-    public static class TaskAffinity3Activity extends Activity {
+    public static class TaskAffinity2Activity extends BaseActivity {
     }
 
-    public static class ClearTaskOnLaunchActivity extends Activity {
+    public static class TaskAffinity3Activity extends BaseActivity {
     }
 
-    public static class DocumentLaunchIntoActivity extends Activity {
+    public static class ClearTaskOnLaunchActivity extends BaseActivity {
     }
 
-    public static class DocumentLaunchAlwaysActivity extends Activity {
+    public static class DocumentLaunchIntoActivity extends BaseActivity {
     }
 
-    public static class DocumentLaunchNeverActivity extends Activity {
+    public static class DocumentLaunchAlwaysActivity extends BaseActivity {
     }
 
-    public static class NoHistoryActivity extends Activity {
+    public static class DocumentLaunchNeverActivity extends BaseActivity {
     }
 
-    public static class LauncherActivity extends Activity {
+    public static class NoHistoryActivity extends BaseActivity {
     }
 
-    public static class RelinquishTaskIdentityActivity extends Activity {
+    public static class LauncherActivity extends BaseActivity {
     }
 
-    public static class TaskAffinity1RelinquishTaskIdentityActivity extends Activity {
+    public static class RelinquishTaskIdentityActivity extends BaseActivity {
+    }
+
+    public static class TaskAffinity1RelinquishTaskIdentityActivity extends BaseActivity {
     }
 }
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
index 9e1d67a..950047d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/intent/LaunchRunner.java
@@ -264,6 +264,11 @@
 
         if (activity == null) {
             return activityContext;
+        } else if (startForResult && activityContext == activity) {
+            // The result might have send back to caller activity and forced the caller activity
+            // to resumed again, before the started activity actually resumed. Just wait for idle
+            // for that case.
+            getInstrumentation().waitForIdleSync();
         } else {
             waitAndAssertActivityLaunched(activity, intent);
         }
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
index fceab7d..b6fa201 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/ActivityManagerTestBase.java
@@ -34,6 +34,7 @@
 import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
 import static android.content.pm.PackageManager.FEATURE_EMBEDDED;
 import static android.content.pm.PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT;
+import static android.content.pm.PackageManager.FEATURE_INPUT_METHODS;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
 import static android.content.pm.PackageManager.FEATURE_SCREEN_LANDSCAPE;
@@ -198,6 +199,9 @@
     protected static final String AM_START_HOME_ACTIVITY_COMMAND =
             "am start -a android.intent.action.MAIN -c android.intent.category.HOME";
 
+    protected static final String MSG_NO_MOCK_IME =
+            "MockIme cannot be used for devices that do not support installable IMEs";
+
     private static final String LOCK_CREDENTIAL = "1234";
 
     private static final int UI_MODE_TYPE_MASK = 0x0f;
@@ -1541,6 +1545,10 @@
                 FEATURE_ACTIVITIES_ON_SECONDARY_DISPLAYS);
     }
 
+    protected boolean supportsInstallableIme() {
+        return mContext.getPackageManager().hasSystemFeature(FEATURE_INPUT_METHODS);
+    }
+
     static class CountSpec<T> {
         static final int DONT_CARE = Integer.MIN_VALUE;
         static final int EQUALS = 1;
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
index a50e0c6c..e3a1b62 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/CommandSession.java
@@ -374,6 +374,20 @@
         boolean shouldWaitForLaunched();
     }
 
+    abstract static class DefaultLaunchProxy implements LaunchProxy {
+        LaunchInjector mLaunchInjector;
+
+        @Override
+        public boolean shouldWaitForLaunched() {
+            return true;
+        }
+
+        @Override
+        public void setLaunchInjector(LaunchInjector injector) {
+            mLaunchInjector = injector;
+        }
+    }
+
     /** Created by test case to control testing activity that implements the session protocol. */
     public static class ActivitySessionClient extends BroadcastReceiver implements AutoCloseable {
         private final Context mContext;
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/EditorInfoTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/EditorInfoTest.java
index 81a3735..d783104 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/EditorInfoTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/EditorInfoTest.java
@@ -20,12 +20,12 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
 
 import android.os.Bundle;
 import android.os.LocaleList;
 import android.os.Parcel;
 import android.test.MoreAsserts;
-import android.text.Selection;
 import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.util.StringBuilderPrinter;
@@ -41,13 +41,16 @@
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class EditorInfoTest {
-    private static final int LONG_TEXT_LENGTH = 2048;
+    private static final int TEST_TEXT_LENGTH = 2048;
+    /** A text with 1 million chars! This is way too long. */
+    private static final int OVER_SIZED_TEXT_LENGTH = 1 * 1024 * 1024;
+    /** To get the longest available text from getInitialText methods. */
+    private static final int REQUEST_LONGEST_AVAILABLE_TEXT = OVER_SIZED_TEXT_LENGTH; //
 
     @Test
     public void testEditorInfo() {
         EditorInfo info = new EditorInfo();
-        CharSequence testInitialText = createTestText(
-                LONG_TEXT_LENGTH,/* selStart= */0, /* selEnd= */0);
+        CharSequence testInitialText = createTestText(TEST_TEXT_LENGTH);
 
         info.actionId = 1;
         info.actionLabel = "actionLabel";
@@ -117,26 +120,205 @@
         assertNull(targetInfo.hintLocales);
     }
 
-    // TODO(b/147793399): Increase test coverage on initial surrounding text APIs.
+    @Test
+    public void testInitialSurroundingText_nullInput_throwsException() {
+        final EditorInfo info = new EditorInfo();
 
-    private static CharSequence createTestText(int size, int selStart, int selLength) {
+        try {
+            info.setInitialSurroundingText(null);
+            fail("Shall not take null input");
+        } catch (NullPointerException expected) {
+            // Expected behavior, nothing to do.
+        }
+    }
+
+    @Test
+    public void testInitialSurroundingText_passwordTypes_notObtain() {
+        final EditorInfo info = new EditorInfo();
+        final CharSequence testInitialText = createTestText(/* size= */ 10);
+        info.initialSelStart = 1;
+        info.initialSelEnd = 2;
+
+        // Text password type
+        info.inputType = (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_PASSWORD);
+
+        info.setInitialSurroundingText(testInitialText);
+
+        assertExpectedTextLength(info,
+                /* expectBeforeCursorLength= */null,
+                /* expectSelectionLength= */null,
+                /* expectAfterCursorLength= */null);
+
+        // Web password type
+        info.inputType = (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_VARIATION_WEB_PASSWORD);
+
+        info.setInitialSurroundingText(testInitialText);
+
+        assertExpectedTextLength(info,
+                /* expectBeforeCursorLength= */null,
+                /* expectSelectionLength= */null,
+                /* expectAfterCursorLength= */null);
+
+        // Number password type
+        info.inputType = (EditorInfo.TYPE_CLASS_NUMBER | EditorInfo.TYPE_NUMBER_VARIATION_PASSWORD);
+
+        info.setInitialSurroundingText(testInitialText);
+
+        assertExpectedTextLength(info,
+                /* expectBeforeCursorLength= */null,
+                /* expectSelectionLength= */null,
+                /* expectAfterCursorLength= */null);
+    }
+
+    @Test
+    public void testInitialSurroundingText_cursorAtHead_emptyBeforeCursorText() {
+        final EditorInfo info = new EditorInfo();
+        final CharSequence testText = createTestText(TEST_TEXT_LENGTH);
+        final int selLength = 10;
+        info.initialSelStart = 0;
+        info.initialSelEnd = info.initialSelStart + selLength;
+        final int expectedTextBeforeCursorLength = 0;
+        final int expectedTextAfterCursorLength = testText.length() - selLength;
+
+        info.setInitialSurroundingText(testText);
+
+        assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength,
+                expectedTextAfterCursorLength);
+    }
+
+    @Test
+    public void testInitialSurroundingText_cursorAtTail_emptyAfterCursorText() {
+        final EditorInfo info = new EditorInfo();
+        final CharSequence testText = createTestText(TEST_TEXT_LENGTH);
+        final int selLength = 10;
+        info.initialSelStart = testText.length() - selLength;
+        info.initialSelEnd = testText.length();
+        final int expectedTextBeforeCursorLength = testText.length() - selLength;
+        final int expectedTextAfterCursorLength = 0;
+
+        info.setInitialSurroundingText(testText);
+
+        assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength,
+                expectedTextAfterCursorLength);
+    }
+
+    @Test
+    public void testInitialSurroundingText_noSelection_emptySelectionText() {
+        final EditorInfo info = new EditorInfo();
+        final CharSequence testText = createTestText(TEST_TEXT_LENGTH);
+        final int selLength = 0;
+        info.initialSelStart = 0;
+        info.initialSelEnd = info.initialSelStart + selLength;
+        final int expectedTextBeforeCursorLength = 0;
+        final int expectedTextAfterCursorLength = testText.length();
+
+        info.setInitialSurroundingText(testText);
+
+        assertExpectedTextLength(info, expectedTextBeforeCursorLength, selLength,
+                expectedTextAfterCursorLength);
+    }
+
+    @Test
+    public void testInitialSurroundingText_overSizedSeleciton_keepsBeforeAfterTextValid() {
+        final EditorInfo info = new EditorInfo();
+        final CharSequence testText = createTestText(OVER_SIZED_TEXT_LENGTH);
+        final int selLength = OVER_SIZED_TEXT_LENGTH - 2;
+        info.initialSelStart = 1;
+        info.initialSelEnd = info.initialSelStart + selLength;
+        final int expectedTextBeforeCursorLength = 1;
+        final int expectedTextAfterCursorLength = 1;
+
+        info.setInitialSurroundingText(testText);
+
+        assertExpectedTextLength(info, expectedTextBeforeCursorLength,
+                /* expectSelectionLength= */null, expectedTextAfterCursorLength);
+    }
+
+    @Test
+    public void testInitialSurroundingSubText_keepsOriginalCursorPosition() {
+        final EditorInfo info = new EditorInfo();
+        final String prefixString = "prefix";
+        final CharSequence subText = createTestText(TEST_TEXT_LENGTH);
+        final CharSequence originalText = TextUtils.concat(prefixString, subText);
+        final int selLength = 2;
+        info.initialSelStart = originalText.length() / 2;
+        info.initialSelEnd = info.initialSelStart + selLength;
+        final CharSequence expectedTextBeforeCursor = createExpectedText(/* startNumber= */0,
+                info.initialSelStart - prefixString.length());
+        final CharSequence expectedSelectedText = createExpectedText(
+                info.initialSelStart - prefixString.length(), selLength);
+        final CharSequence expectedTextAfterCursor = createExpectedText(
+                info.initialSelEnd - prefixString.length(),
+                originalText.length() - info.initialSelEnd);
+
+        info.setInitialSurroundingSubText(subText, prefixString.length());
+
+        assertTrue(TextUtils.equals(expectedTextBeforeCursor,
+                info.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
+                        InputConnection.GET_TEXT_WITH_STYLES)));
+        assertTrue(TextUtils.equals(expectedSelectedText,
+                info.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES)));
+        assertTrue(TextUtils.equals(expectedTextAfterCursor,
+                info.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
+                        InputConnection.GET_TEXT_WITH_STYLES)));
+    }
+
+    private static void assertExpectedTextLength(EditorInfo editorInfo,
+            Integer expectBeforeCursorLength, Integer expectSelectionLength,
+            Integer expectAfterCursorLength) {
+        final CharSequence textBeforeCursor =
+                editorInfo.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
+                        InputConnection.GET_TEXT_WITH_STYLES);
+        final CharSequence selectedText =
+                editorInfo.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES);
+        final CharSequence textAfterCursor =
+                editorInfo.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
+                        InputConnection.GET_TEXT_WITH_STYLES);
+
+        if (expectBeforeCursorLength == null) {
+            assertNull(textBeforeCursor);
+        } else {
+            assertEquals(expectBeforeCursorLength.intValue(), textBeforeCursor.length());
+        }
+
+        if (expectSelectionLength == null) {
+            assertNull(selectedText);
+        } else {
+            assertEquals(expectSelectionLength.intValue(), selectedText.length());
+        }
+
+        if (expectAfterCursorLength == null) {
+            assertNull(textAfterCursor);
+        } else {
+            assertEquals(expectAfterCursorLength.intValue(), textAfterCursor.length());
+        }
+    }
+
+    private static CharSequence createTestText(int size) {
         final SpannableStringBuilder builder = new SpannableStringBuilder();
         for (int i = 0; i < size; i++) {
             builder.append(Integer.toString(i % 10));
         }
-        Selection.setSelection(builder, selStart, selStart+selLength);
+        return builder;
+    }
+
+    private static CharSequence createExpectedText(int startNumber, int length) {
+        final SpannableStringBuilder builder = new SpannableStringBuilder();
+        for (int i = startNumber; i < startNumber + length; i++) {
+            builder.append(Integer.toString(i % 10));
+        }
         return builder;
     }
 
     private static CharSequence concateInitialSurroundingText(EditorInfo info) {
         final CharSequence textBeforeCursor =
-                nullToEmpty(info.getInitialTextBeforeCursor(LONG_TEXT_LENGTH,
+                nullToEmpty(info.getInitialTextBeforeCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
                         InputConnection.GET_TEXT_WITH_STYLES));
         final CharSequence selectedText =
                 nullToEmpty(info.getInitialSelectedText(InputConnection.GET_TEXT_WITH_STYLES));
         final CharSequence textAfterCursor =
-                nullToEmpty(info.getInitialTextAfterCursor(LONG_TEXT_LENGTH,
-                InputConnection.GET_TEXT_WITH_STYLES));
+                nullToEmpty(info.getInitialTextAfterCursor(REQUEST_LONGEST_AVAILABLE_TEXT,
+                        InputConnection.GET_TEXT_WITH_STYLES));
 
         return TextUtils.concat(textBeforeCursor, selectedText, textAfterCursor);
     }
diff --git a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
index 50abb7a..a0cc196 100644
--- a/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
+++ b/tests/inputmethod/src/android/view/inputmethod/cts/InlineSuggestionTest.java
@@ -99,6 +99,19 @@
         latch.await();
     }
 
+    @Test
+    public void testInflateTwiceThrowsException() {
+        InlineSuggestion suggestion = createInlineSuggestion();
+        Context context = InstrumentationRegistry.getTargetContext();
+        Consumer<View> mockConsumer = mock(Consumer.class);
+
+        suggestion.inflate(context, new Size(100, 100), AsyncTask.THREAD_POOL_EXECUTOR,
+                mockConsumer);
+        assertThrows(IllegalStateException.class,
+                () -> suggestion.inflate(context, new Size(100, 100),
+                        AsyncTask.THREAD_POOL_EXECUTOR, mockConsumer));
+    }
+
     private InlineSuggestion createInlineSuggestion() {
         InlineSuggestionInfo info = InlineSuggestionInfo.newInlineSuggestionInfo(
                 mInlinePresentationSpec, InlineSuggestionInfo.SOURCE_AUTOFILL, new String[]{""});
diff --git a/tests/media/Android.bp b/tests/media/Android.bp
index 889b123..b813fb2 100644
--- a/tests/media/Android.bp
+++ b/tests/media/Android.bp
@@ -26,6 +26,7 @@
     ],
     jni_libs: [
         "libctsmediav2muxer_jni",
+        "libctsmediav2extractor_jni",
     ],
     srcs: ["src/**/*.java"],
     // Tag this module as a cts test artifact
diff --git a/tests/media/jni/Android.bp b/tests/media/jni/Android.bp
index 339ca79..10f0f59 100644
--- a/tests/media/jni/Android.bp
+++ b/tests/media/jni/Android.bp
@@ -30,3 +30,21 @@
     ],
     gtest: false,
 }
+
+cc_test_library {
+    name: "libctsmediav2extractor_jni",
+    srcs: [
+        "NativeMediaConstants.cpp",
+        "NativeExtractorTest.cpp",
+    ],
+    shared_libs: [
+        "libmediandk",
+        "liblog",
+    ],
+    stl: "libc++_static",
+    cflags: [
+        "-Werror",
+        "-Wall",
+    ],
+    gtest: false,
+}
diff --git a/tests/media/jni/NativeExtractorTest.cpp b/tests/media/jni/NativeExtractorTest.cpp
new file mode 100644
index 0000000..42876f0
--- /dev/null
+++ b/tests/media/jni/NativeExtractorTest.cpp
@@ -0,0 +1,735 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NativeExtractorTest"
+#include <log/log.h>
+
+#include <jni.h>
+#include <sys/stat.h>
+
+#include <cstdlib>
+#include <random>
+
+#include "media/NdkMediaExtractor.h"
+
+static bool isExtractorOKonEOS(AMediaExtractor* extractor) {
+    return AMediaExtractor_getSampleTrackIndex(extractor) < 0 &&
+           AMediaExtractor_getSampleSize(extractor) < 0 &&
+           (int)AMediaExtractor_getSampleFlags(extractor) < 0 &&
+           AMediaExtractor_getSampleTime(extractor) < 0;
+}
+
+static bool isSampleInfoIdentical(AMediaCodecBufferInfo* refSample,
+                                  AMediaCodecBufferInfo* testSample) {
+    return refSample->flags == testSample->flags && refSample->size == testSample->size &&
+           refSample->presentationTimeUs == testSample->presentationTimeUs;
+}
+
+static bool isSampleInfoValidAndIdentical(AMediaCodecBufferInfo* refSample,
+                                          AMediaCodecBufferInfo* testSample) {
+    return refSample->flags == testSample->flags && refSample->size == testSample->size &&
+           abs(refSample->presentationTimeUs - testSample->presentationTimeUs) <= 1 &&
+           (int)refSample->flags >= 0 && refSample->size >= 0 && refSample->presentationTimeUs >= 0;
+}
+
+static bool isFormatSimilar(AMediaFormat* refFormat, AMediaFormat* testFormat) {
+    const char *refMime = nullptr, *testMime = nullptr;
+    bool hasRefMime = AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &refMime);
+    bool hasTestMime = AMediaFormat_getString(testFormat, AMEDIAFORMAT_KEY_MIME, &testMime);
+
+    if (!hasRefMime || !hasTestMime || strcmp(refMime, testMime) != 0) return false;
+    if (!strncmp(refMime, "audio/", strlen("audio/"))) {
+        int32_t refSampleRate, testSampleRate, refNumChannels, testNumChannels;
+        bool hasRefSampleRate =
+                AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &refSampleRate);
+        bool hasTestSampleRate =
+                AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_SAMPLE_RATE, &testSampleRate);
+        bool hasRefNumChannels =
+                AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &refNumChannels);
+        bool hasTestNumChannels =
+                AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &testNumChannels);
+        return hasRefSampleRate && hasTestSampleRate && hasRefNumChannels && hasTestNumChannels &&
+               refNumChannels == testNumChannels && refSampleRate == testSampleRate;
+    } else if (!strncmp(refMime, "video/", strlen("video/"))) {
+        int32_t refWidth, testWidth, refHeight, testHeight;
+        bool hasRefWidth = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_WIDTH, &refWidth);
+        bool hasTestWidth = AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_WIDTH, &testWidth);
+        bool hasRefHeight = AMediaFormat_getInt32(refFormat, AMEDIAFORMAT_KEY_HEIGHT, &refHeight);
+        bool hasTestHeight =
+                AMediaFormat_getInt32(testFormat, AMEDIAFORMAT_KEY_HEIGHT, &testHeight);
+        return hasRefWidth && hasTestWidth && hasRefHeight && hasTestHeight &&
+               refWidth == testWidth && refHeight == testHeight;
+    }
+    return true;
+}
+
+static void inline setSampleInfo(AMediaExtractor* extractor, AMediaCodecBufferInfo* info) {
+    info->flags = AMediaExtractor_getSampleFlags(extractor);
+    info->offset = 0;
+    info->size = AMediaExtractor_getSampleSize(extractor);
+    info->presentationTimeUs = AMediaExtractor_getSampleTime(extractor);
+}
+
+static bool isMediaSimilar(AMediaExtractor* refExtractor, AMediaExtractor* testExtractor,
+                           const char* mime, int sampleLimit = INT32_MAX) {
+    const int maxSampleSize = (4 * 1024 * 1024);
+    auto refBuffer = new uint8_t[maxSampleSize];
+    auto testBuffer = new uint8_t[maxSampleSize];
+    int noOfTracksMatched = 0;
+    for (size_t refTrackID = 0; refTrackID < AMediaExtractor_getTrackCount(refExtractor);
+         refTrackID++) {
+        AMediaFormat* refFormat = AMediaExtractor_getTrackFormat(refExtractor, refTrackID);
+        const char* refMime = nullptr;
+        bool hasKey = AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &refMime);
+        if (!hasKey || (mime != nullptr && strcmp(refMime, mime) != 0)) {
+            AMediaFormat_delete(refFormat);
+            continue;
+        }
+        for (size_t testTrackID = 0; testTrackID < AMediaExtractor_getTrackCount(testExtractor);
+             testTrackID++) {
+            AMediaFormat* testFormat = AMediaExtractor_getTrackFormat(testExtractor, testTrackID);
+            if (!isFormatSimilar(refFormat, testFormat)) {
+                AMediaFormat_delete(testFormat);
+                continue;
+            }
+            AMediaExtractor_selectTrack(refExtractor, refTrackID);
+            AMediaExtractor_selectTrack(testExtractor, testTrackID);
+
+            AMediaCodecBufferInfo refSampleInfo, testSampleInfo;
+            bool areTracksIdentical = true;
+            for (int frameCount = 0;; frameCount++) {
+                setSampleInfo(refExtractor, &refSampleInfo);
+                setSampleInfo(testExtractor, &testSampleInfo);
+                if (!isSampleInfoValidAndIdentical(&refSampleInfo, &testSampleInfo)) {
+                    ALOGD(" Mime: %s mismatch for sample: %d", refMime, frameCount);
+                    ALOGD(" flags exp/got: %d / %d", refSampleInfo.flags, testSampleInfo.flags);
+                    ALOGD(" size exp/got: %d / %d ", refSampleInfo.size, testSampleInfo.size);
+                    ALOGD(" ts exp/got: %d / %d ", (int)refSampleInfo.presentationTimeUs,
+                          (int)testSampleInfo.presentationTimeUs);
+                    areTracksIdentical = false;
+                    break;
+                }
+                ssize_t refSz =
+                        AMediaExtractor_readSampleData(refExtractor, refBuffer, maxSampleSize);
+                if (refSz != refSampleInfo.size) {
+                    ALOGD("Mime: %s Size exp/got:  %d / %zd ", refMime, refSampleInfo.size, refSz);
+                    areTracksIdentical = false;
+                    break;
+                }
+                ssize_t testSz =
+                        AMediaExtractor_readSampleData(testExtractor, testBuffer, maxSampleSize);
+                if (testSz != testSampleInfo.size) {
+                    ALOGD("Mime: %s Size exp/got:  %d / %zd ", refMime, testSampleInfo.size,
+                          testSz);
+                    areTracksIdentical = false;
+                    break;
+                }
+                int trackIndex = AMediaExtractor_getSampleTrackIndex(refExtractor);
+                if (trackIndex != refTrackID) {
+                    ALOGD("Mime: %s TrackID exp/got: %zu / %d", refMime, refTrackID, trackIndex);
+                    areTracksIdentical = false;
+                    break;
+                }
+                trackIndex = AMediaExtractor_getSampleTrackIndex(testExtractor);
+                if (trackIndex != testTrackID) {
+                    ALOGD("Mime: %s  TrackID exp/got %zd / %d : ", refMime, testTrackID,
+                          trackIndex);
+                    areTracksIdentical = false;
+                    break;
+                }
+                bool haveRefSamples = AMediaExtractor_advance(refExtractor);
+                bool haveTestSamples = AMediaExtractor_advance(testExtractor);
+                if (haveRefSamples != haveTestSamples) {
+                    ALOGD("Mime: %s Mismatch in sampleCount", refMime);
+                    areTracksIdentical = false;
+                    break;
+                }
+
+                if (!haveRefSamples && !isExtractorOKonEOS(refExtractor)) {
+                    ALOGD("Mime: %s calls post advance() are not OK", refMime);
+                    areTracksIdentical = false;
+                    break;
+                }
+                if (!haveTestSamples && !isExtractorOKonEOS(testExtractor)) {
+                    ALOGD("Mime: %s calls post advance() are not OK", refMime);
+                    areTracksIdentical = false;
+                    break;
+                }
+                ALOGV("Mime: %s Sample: %d flags: %d size: %d ts: %d", refMime, frameCount,
+                      refSampleInfo.flags, refSampleInfo.size,
+                      (int)refSampleInfo.presentationTimeUs);
+                if (!haveRefSamples || frameCount >= sampleLimit) {
+                    break;
+                }
+            }
+            AMediaExtractor_unselectTrack(testExtractor, testTrackID);
+            AMediaExtractor_unselectTrack(refExtractor, refTrackID);
+            AMediaFormat_delete(testFormat);
+            if (areTracksIdentical) {
+                noOfTracksMatched++;
+                break;
+            }
+        }
+        AMediaFormat_delete(refFormat);
+        if (mime != nullptr && noOfTracksMatched > 0) break;
+    }
+    delete[] refBuffer;
+    delete[] testBuffer;
+    if (mime == nullptr) {
+        return noOfTracksMatched == AMediaExtractor_getTrackCount(refExtractor);
+    } else {
+        return noOfTracksMatched > 0;
+    }
+}
+
+static bool validateCachedDuration(AMediaExtractor* extractor, bool isNetworkSource) {
+    if (isNetworkSource) {
+        AMediaExtractor_selectTrack(extractor, 0);
+        for (unsigned cnt = 0;; cnt++) {
+            if ((cnt & (cnt - 1)) == 0) {
+                if (AMediaExtractor_getCachedDuration(extractor) < 0) {
+                    ALOGE("getCachedDuration is less than zero for network source");
+                    return false;
+                }
+            }
+            if (!AMediaExtractor_advance(extractor)) break;
+        }
+        AMediaExtractor_unselectTrack(extractor, 0);
+    } else {
+        if (AMediaExtractor_getCachedDuration(extractor) != -1) {
+            ALOGE("getCachedDuration != -1 for non-network source");
+            return false;
+        }
+    }
+    return true;
+}
+
+static AMediaExtractor* createExtractorFromFD(FILE* fp) {
+    AMediaExtractor* extractor = nullptr;
+    struct stat buf {};
+    if (fp && !fstat(fileno(fp), &buf)) {
+        extractor = AMediaExtractor_new();
+        media_status_t res = AMediaExtractor_setDataSourceFd(extractor, fileno(fp), 0, buf.st_size);
+        if (res != AMEDIA_OK) {
+            AMediaExtractor_delete(extractor);
+            extractor = nullptr;
+        }
+    }
+    return extractor;
+}
+
+// content necessary for testing seek are grouped in this class
+class SeekTestParams {
+  public:
+    SeekTestParams(AMediaCodecBufferInfo expected, int64_t timeStamp, SeekMode mode)
+        : mExpected{expected}, mTimeStamp{timeStamp}, mMode{mode} {}
+
+    AMediaCodecBufferInfo mExpected;
+    int64_t mTimeStamp;
+    SeekMode mMode;
+};
+
+static std::vector<AMediaCodecBufferInfo*> getSeekablePoints(const char* srcFile,
+                                                             const char* mime) {
+    std::vector<AMediaCodecBufferInfo*> bookmarks;
+    if (mime == nullptr) return bookmarks;
+    FILE* srcFp = fopen(srcFile, "rbe");
+    if (!srcFp) {
+        ALOGE("fopen failed for srcFile %s", srcFile);
+        return bookmarks;
+    }
+    AMediaExtractor* extractor = createExtractorFromFD(srcFp);
+    if (!extractor) {
+        if (srcFp) fclose(srcFp);
+        ALOGE("createExtractorFromFD failed");
+        return bookmarks;
+    }
+
+    for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
+        AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
+        const char* currMime = nullptr;
+        bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &currMime);
+        if (!hasKey || strcmp(currMime, mime) != 0) {
+            AMediaFormat_delete(format);
+            continue;
+        }
+        AMediaExtractor_selectTrack(extractor, trackID);
+        do {
+            uint32_t sampleFlags = AMediaExtractor_getSampleFlags(extractor);
+            if ((sampleFlags & AMEDIAEXTRACTOR_SAMPLE_FLAG_SYNC) != 0) {
+                auto sampleInfo = new AMediaCodecBufferInfo;
+                setSampleInfo(extractor, sampleInfo);
+                bookmarks.push_back(sampleInfo);
+            }
+        } while (AMediaExtractor_advance(extractor));
+        AMediaExtractor_unselectTrack(extractor, trackID);
+        AMediaFormat_delete(format);
+        break;
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    return bookmarks;
+}
+
+static constexpr unsigned kSeed = 0x7ab7;
+
+static std::vector<SeekTestParams*> generateSeekTestArgs(const char* srcFile, const char* mime,
+                                                         bool isRandom) {
+    std::vector<SeekTestParams*> testArgs;
+    if (mime == nullptr) return testArgs;
+    const int MAX_SEEK_POINTS = 7;
+    std::srand(kSeed);
+    if (isRandom) {
+        FILE* srcFp = fopen(srcFile, "rbe");
+        if (!srcFp) {
+            ALOGE("fopen failed for srcFile %s", srcFile);
+            return testArgs;
+        }
+        AMediaExtractor* extractor = createExtractorFromFD(srcFp);
+        if (!extractor) {
+            if (srcFp) fclose(srcFp);
+            ALOGE("createExtractorFromFD failed");
+            return testArgs;
+        }
+
+        const int64_t maxEstDuration = 4000000;
+        for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
+            AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
+            const char* currMime = nullptr;
+            bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &currMime);
+            if (!hasKey || strcmp(currMime, mime) != 0) {
+                AMediaFormat_delete(format);
+                continue;
+            }
+            AMediaExtractor_selectTrack(extractor, trackID);
+            for (int i = 0; i < MAX_SEEK_POINTS; i++) {
+                double r = ((double)rand() / (RAND_MAX));
+                long pts = (long)(r * maxEstDuration);
+
+                for (int mode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
+                     mode <= AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC; mode++) {
+                    AMediaExtractor_seekTo(extractor, pts, (SeekMode)mode);
+                    AMediaCodecBufferInfo currInfo;
+                    setSampleInfo(extractor, &currInfo);
+                    testArgs.push_back((new SeekTestParams(currInfo, pts, (SeekMode)mode)));
+                }
+            }
+            AMediaExtractor_unselectTrack(extractor, trackID);
+            AMediaFormat_delete(format);
+            break;
+        }
+        AMediaExtractor_delete(extractor);
+        if (srcFp) fclose(srcFp);
+    } else {
+        std::vector<AMediaCodecBufferInfo*> bookmarks = getSeekablePoints(srcFile, mime);
+        if (bookmarks.empty()) return testArgs;
+        int size = bookmarks.size();
+        int* indices;
+        int indexSize = 0;
+        if (size > MAX_SEEK_POINTS) {
+            indices = new int[MAX_SEEK_POINTS];
+            indexSize = MAX_SEEK_POINTS;
+            indices[0] = 0;
+            indices[MAX_SEEK_POINTS - 1] = size - 1;
+            for (int i = 1; i < MAX_SEEK_POINTS - 1; i++) {
+                double r = ((double)rand() / (RAND_MAX));
+                indices[i] = (int)(r * (MAX_SEEK_POINTS - 1) + 1);
+            }
+        } else {
+            indices = new int[size];
+            indexSize = size;
+            for (int i = 0; i < size; i++) indices[i] = i;
+        }
+        for (int i = 0; i < indexSize; i++) {
+            AMediaCodecBufferInfo currInfo = *bookmarks[i];
+            int64_t pts = currInfo.presentationTimeUs;
+            testArgs.push_back(
+                    (new SeekTestParams(currInfo, pts, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC)));
+            testArgs.push_back((new SeekTestParams(currInfo, pts, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC)));
+            testArgs.push_back(
+                    (new SeekTestParams(currInfo, pts, AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC)));
+            if (i > 0) {
+                AMediaCodecBufferInfo prevInfo = *bookmarks[i - 1];
+                int64_t ptsMinus = prevInfo.presentationTimeUs;
+                ptsMinus = pts - ((pts - ptsMinus) >> 3);
+                testArgs.push_back((
+                        new SeekTestParams(currInfo, ptsMinus, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC)));
+                testArgs.push_back(
+                        (new SeekTestParams(currInfo, ptsMinus, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC)));
+                testArgs.push_back((new SeekTestParams(prevInfo, ptsMinus,
+                                                       AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC)));
+            }
+            if (i < size - 1) {
+                AMediaCodecBufferInfo nextInfo = *bookmarks[i + 1];
+                int64_t ptsPlus = nextInfo.presentationTimeUs;
+                ptsPlus = pts + ((ptsPlus - pts) >> 3);
+                testArgs.push_back(
+                        (new SeekTestParams(currInfo, ptsPlus, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC)));
+                testArgs.push_back(
+                        (new SeekTestParams(nextInfo, ptsPlus, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC)));
+                testArgs.push_back((
+                        new SeekTestParams(currInfo, ptsPlus, AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC)));
+            }
+        }
+        for (auto bookmark : bookmarks) {
+            delete bookmark;
+        }
+        bookmarks.clear();
+        delete[] indices;
+    }
+    return testArgs;
+}
+
+static int checkSeekPoints(const char* srcFile, const char* mime,
+                           const std::vector<SeekTestParams*>& seekTestArgs) {
+    int errCnt = 0;
+    FILE* srcFp = fopen(srcFile, "rbe");
+    AMediaExtractor* extractor = createExtractorFromFD(srcFp);
+    if (!extractor) {
+        if (srcFp) fclose(srcFp);
+        ALOGE("createExtractorFromFD failed");
+        return -1;
+    }
+    for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
+        AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
+        const char* currMime = nullptr;
+        bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &currMime);
+        if (!hasKey || strcmp(currMime, mime) != 0) {
+            continue;
+        }
+        AMediaExtractor_selectTrack(extractor, trackID);
+        AMediaCodecBufferInfo received;
+        for (auto arg : seekTestArgs) {
+            AMediaExtractor_seekTo(extractor, arg->mTimeStamp, arg->mMode);
+            setSampleInfo(extractor, &received);
+            if (!isSampleInfoIdentical(&arg->mExpected, &received)) {
+                ALOGE(" flags exp/got: %d / %d", arg->mExpected.flags, received.flags);
+                ALOGE(" size exp/got: %d / %d ", arg->mExpected.size, received.size);
+                ALOGE(" ts exp/got: %d / %d ", (int)arg->mExpected.presentationTimeUs,
+                      (int)received.presentationTimeUs);
+                errCnt++;
+            }
+        }
+        AMediaExtractor_unselectTrack(extractor, trackID);
+        AMediaFormat_delete(format);
+        break;
+    }
+    AMediaExtractor_delete(extractor);
+    if (srcFp) fclose(srcFp);
+    return errCnt;
+}
+
+static bool isFileFormatIdentical(AMediaExtractor* refExtractor, AMediaExtractor* testExtractor) {
+    bool result = false;
+    if (refExtractor && testExtractor) {
+        AMediaFormat* refFormat = AMediaExtractor_getFileFormat(refExtractor);
+        AMediaFormat* testFormat = AMediaExtractor_getFileFormat(testExtractor);
+        if (refFormat && testFormat) {
+            const char *refMime = nullptr, *testMime = nullptr;
+            bool hasRefKey = AMediaFormat_getString(refFormat, AMEDIAFORMAT_KEY_MIME, &refMime);
+            bool hasTestKey = AMediaFormat_getString(testFormat, AMEDIAFORMAT_KEY_MIME, &testMime);
+            /* TODO: Not Sure if we need to verify any other parameter of file format */
+            if (hasRefKey && hasTestKey && strcmp(refMime, testMime) == 0) {
+                result = true;
+            } else {
+                ALOGE("file format exp/got : %s/%s", refMime, testMime);
+            }
+        }
+        if (refFormat) AMediaFormat_delete(refFormat);
+        if (testFormat) AMediaFormat_delete(testFormat);
+    }
+    return result;
+}
+
+static bool isSeekOk(AMediaExtractor* refExtractor, AMediaExtractor* testExtractor) {
+    const long maxEstDuration = 14000000;
+    const int MAX_SEEK_POINTS = 7;
+    std::srand(kSeed);
+    AMediaCodecBufferInfo refSampleInfo, testSampleInfo;
+    bool result = true;
+    for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(refExtractor); trackID++) {
+        AMediaExtractor_selectTrack(refExtractor, trackID);
+        AMediaExtractor_selectTrack(testExtractor, trackID);
+        for (int i = 0; i < MAX_SEEK_POINTS && result; i++) {
+            double r = ((double)rand() / (RAND_MAX));
+            long pts = (long)(r * maxEstDuration);
+            for (int mode = AMEDIAEXTRACTOR_SEEK_PREVIOUS_SYNC;
+                 mode <= AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC; mode++) {
+                AMediaExtractor_seekTo(refExtractor, pts, (SeekMode)mode);
+                AMediaExtractor_seekTo(testExtractor, pts, (SeekMode)mode);
+                setSampleInfo(refExtractor, &refSampleInfo);
+                setSampleInfo(testExtractor, &testSampleInfo);
+                result = isSampleInfoIdentical(&refSampleInfo, &testSampleInfo);
+                if (!result) {
+                    ALOGE(" flags exp/got: %d / %d", refSampleInfo.flags, testSampleInfo.flags);
+                    ALOGE(" size exp/got: %d / %d ", refSampleInfo.size, testSampleInfo.size);
+                    ALOGE(" ts exp/got: %d / %d ", (int)refSampleInfo.presentationTimeUs,
+                          (int)testSampleInfo.presentationTimeUs);
+                }
+                int refTrackIdx = AMediaExtractor_getSampleTrackIndex(refExtractor);
+                int testTrackIdx = AMediaExtractor_getSampleTrackIndex(testExtractor);
+                if (refTrackIdx != testTrackIdx) {
+                    ALOGE("trackIdx exp/got: %d/%d ", refTrackIdx, testTrackIdx);
+                    result = false;
+                }
+            }
+        }
+        AMediaExtractor_unselectTrack(refExtractor, trackID);
+        AMediaExtractor_unselectTrack(testExtractor, trackID);
+    }
+    return result;
+}
+
+static jboolean nativeTestExtract(JNIEnv* env, jobject, jstring jsrcPath, jstring jrefPath,
+                                  jstring jmime) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* ctestPath = env->GetStringUTFChars(jrefPath, nullptr);
+    const char* cmime = env->GetStringUTFChars(jmime, nullptr);
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    AMediaExtractor* srcExtractor = createExtractorFromFD(srcFp);
+    FILE* testFp = fopen(ctestPath, "rbe");
+    AMediaExtractor* testExtractor = createExtractorFromFD(testFp);
+    if (srcExtractor && testExtractor) {
+        isPass = isMediaSimilar(srcExtractor, testExtractor, cmime);
+        if (!isPass) {
+            ALOGE(" Src and test are different from extractor perspective");
+        }
+        AMediaExtractor_delete(srcExtractor);
+        AMediaExtractor_delete(testExtractor);
+    }
+    if (srcFp) fclose(srcFp);
+    if (testFp) fclose(testFp);
+    env->ReleaseStringUTFChars(jmime, cmime);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    env->ReleaseStringUTFChars(jrefPath, ctestPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSeek(JNIEnv* env, jobject, jstring jsrcPath, jstring jmime) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* cmime = env->GetStringUTFChars(jmime, nullptr);
+    std::vector<SeekTestParams*> seekTestArgs = generateSeekTestArgs(csrcPath, cmime, false);
+    if (!seekTestArgs.empty()) {
+        std::shuffle(seekTestArgs.begin(), seekTestArgs.end(), std::default_random_engine(kSeed));
+        int seekAccErrCnt = checkSeekPoints(csrcPath, cmime, seekTestArgs);
+        if (seekAccErrCnt != 0) {
+            ALOGE("For %s seek chose inaccurate Sync point in: %d / %d", csrcPath, seekAccErrCnt,
+                  (int)seekTestArgs.size());
+            isPass = false;
+        } else {
+            isPass = true;
+        }
+        for (auto seekTestArg : seekTestArgs) {
+            delete seekTestArg;
+        }
+        seekTestArgs.clear();
+    } else {
+        ALOGE("No sync samples found.");
+    }
+    env->ReleaseStringUTFChars(jmime, cmime);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSeekFlakiness(JNIEnv* env, jobject, jstring jsrcPath, jstring jmime) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* cmime = env->GetStringUTFChars(jmime, nullptr);
+    std::vector<SeekTestParams*> seekTestArgs = generateSeekTestArgs(csrcPath, cmime, true);
+    if (!seekTestArgs.empty()) {
+        std::shuffle(seekTestArgs.begin(), seekTestArgs.end(), std::default_random_engine(kSeed));
+        int flakyErrCnt = checkSeekPoints(csrcPath, cmime, seekTestArgs);
+        if (flakyErrCnt != 0) {
+            ALOGE("No. of Samples where seek showed flakiness is: %d", flakyErrCnt);
+            isPass = false;
+        } else {
+            isPass = true;
+        }
+        for (auto seekTestArg : seekTestArgs) {
+            delete seekTestArg;
+        }
+        seekTestArgs.clear();
+    } else {
+        ALOGE("No sync samples found.");
+    }
+    env->ReleaseStringUTFChars(jmime, cmime);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestSeekToZero(JNIEnv* env, jobject, jstring jsrcPath, jstring jmime) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    const char* cmime = env->GetStringUTFChars(jmime, nullptr);
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    AMediaExtractor* extractor = createExtractorFromFD(srcFp);
+    if (extractor) {
+        AMediaCodecBufferInfo sampleInfoAtZero;
+        AMediaCodecBufferInfo currInfo;
+        static long randomPts = 1 << 20;
+        for (size_t trackID = 0; trackID < AMediaExtractor_getTrackCount(extractor); trackID++) {
+            AMediaFormat* format = AMediaExtractor_getTrackFormat(extractor, trackID);
+            if (format) {
+                const char* currMime = nullptr;
+                bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &currMime);
+                if (!hasKey || strcmp(currMime, cmime) != 0) {
+                    AMediaFormat_delete(format);
+                    continue;
+                }
+                AMediaExtractor_selectTrack(extractor, trackID);
+                setSampleInfo(extractor, &sampleInfoAtZero);
+                AMediaExtractor_seekTo(extractor, randomPts, AMEDIAEXTRACTOR_SEEK_NEXT_SYNC);
+                AMediaExtractor_seekTo(extractor, 0, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
+                setSampleInfo(extractor, &currInfo);
+                isPass = isSampleInfoIdentical(&sampleInfoAtZero, &currInfo);
+                if (!isPass) {
+                    ALOGE("seen mismatch seekTo(0, SEEK_TO_CLOSEST_SYNC)");
+                    ALOGE(" flags exp/got: %d / %d", sampleInfoAtZero.flags, currInfo.flags);
+                    ALOGE(" size exp/got: %d / %d ", sampleInfoAtZero.size, currInfo.size);
+                    ALOGE(" ts exp/got: %d / %d ", (int)sampleInfoAtZero.presentationTimeUs,
+                          (int)currInfo.presentationTimeUs);
+                    AMediaFormat_delete(format);
+                    break;
+                }
+                AMediaExtractor_seekTo(extractor, -1L, AMEDIAEXTRACTOR_SEEK_CLOSEST_SYNC);
+                setSampleInfo(extractor, &currInfo);
+                isPass = isSampleInfoIdentical(&sampleInfoAtZero, &currInfo);
+                if (!isPass) {
+                    ALOGE("seen mismatch seekTo(-1, SEEK_TO_CLOSEST_SYNC)");
+                    ALOGE(" flags exp/got: %d / %d", sampleInfoAtZero.flags, currInfo.flags);
+                    ALOGE(" size exp/got: %d / %d ", sampleInfoAtZero.size, currInfo.size);
+                    ALOGE(" ts exp/got: %d / %d ", (int)sampleInfoAtZero.presentationTimeUs,
+                          (int)currInfo.presentationTimeUs);
+                    AMediaFormat_delete(format);
+                    break;
+                }
+                AMediaExtractor_unselectTrack(extractor, trackID);
+                AMediaFormat_delete(format);
+            }
+        }
+        AMediaExtractor_delete(extractor);
+    }
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jmime, cmime);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestFileFormat(JNIEnv* env, jobject, jstring jsrcPath) {
+    bool isPass = false;
+    const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+    FILE* srcFp = fopen(csrcPath, "rbe");
+    AMediaExtractor* extractor = createExtractorFromFD(srcFp);
+    if (extractor) {
+        AMediaFormat* format = AMediaExtractor_getFileFormat(extractor);
+        const char* mime = nullptr;
+        bool hasKey = AMediaFormat_getString(format, AMEDIAFORMAT_KEY_MIME, &mime);
+        /* TODO: Not Sure if we need to verify any other parameter of file format */
+        if (hasKey && mime && strlen(mime) > 0) {
+            isPass = true;
+        }
+        AMediaFormat_delete(format);
+        AMediaExtractor_delete(extractor);
+    }
+    if (srcFp) fclose(srcFp);
+    env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    return static_cast<jboolean>(isPass);
+}
+
+static jboolean nativeTestDataSource(JNIEnv* env, jobject, jstring jsrcPath, jstring jsrcUrl) {
+    bool isPass = true;
+    const char* csrcUrl = env->GetStringUTFChars(jsrcUrl, nullptr);
+    AMediaExtractor* refExtractor = AMediaExtractor_new();
+    media_status_t status = AMediaExtractor_setDataSource(refExtractor, csrcUrl);
+    if (status == AMEDIA_OK) {
+        isPass &= validateCachedDuration(refExtractor, true);
+        const char* csrcPath = env->GetStringUTFChars(jsrcPath, nullptr);
+        AMediaDataSource* dataSource = AMediaDataSource_newUri(csrcUrl, 0, nullptr);
+        AMediaExtractor* testExtractor = AMediaExtractor_new();
+        status = AMediaExtractor_setDataSourceCustom(testExtractor, dataSource);
+        if (status != AMEDIA_OK) {
+            ALOGE("setDataSourceCustom failed");
+            isPass = false;
+        } else {
+            isPass &= validateCachedDuration(testExtractor, true);
+            if (!(isMediaSimilar(refExtractor, testExtractor, nullptr) &&
+                  isFileFormatIdentical(refExtractor, testExtractor) &&
+                  isSeekOk(refExtractor, testExtractor))) {
+                isPass = false;
+            }
+        }
+        if (testExtractor) AMediaExtractor_delete(testExtractor);
+        if (dataSource) AMediaDataSource_delete(dataSource);
+
+        FILE* testFp = fopen(csrcPath, "rbe");
+        testExtractor = createExtractorFromFD(testFp);
+        if (testExtractor == nullptr) {
+            ALOGE("createExtractorFromFD failed for test extractor");
+            isPass = false;
+        } else {
+            isPass &= validateCachedDuration(testExtractor, false);
+            if (!(isMediaSimilar(refExtractor, testExtractor, nullptr) &&
+                  isFileFormatIdentical(refExtractor, testExtractor) &&
+                  isSeekOk(refExtractor, testExtractor))) {
+                isPass = false;
+            }
+        }
+        if (testExtractor) AMediaExtractor_delete(testExtractor);
+        if (testFp) fclose(testFp);
+        env->ReleaseStringUTFChars(jsrcPath, csrcPath);
+    } else {
+        ALOGE("setDataSource failed");
+        isPass = false;
+    }
+    if (refExtractor) AMediaExtractor_delete(refExtractor);
+    env->ReleaseStringUTFChars(jsrcUrl, csrcUrl);
+    return static_cast<jboolean>(isPass);
+}
+
+int registerAndroidMediaV2CtsExtractorTestSetDS(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestDataSource", "(Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestDataSource},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/ExtractorTest$SetDataSourceTest");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+int registerAndroidMediaV2CtsExtractorTestFunc(JNIEnv* env) {
+    const JNINativeMethod methodTable[] = {
+            {"nativeTestExtract", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestExtract},
+            {"nativeTestSeek", "(Ljava/lang/String;Ljava/lang/String;)Z", (void*)nativeTestSeek},
+            {"nativeTestSeekFlakiness", "(Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestSeekFlakiness},
+            {"nativeTestSeekToZero", "(Ljava/lang/String;Ljava/lang/String;)Z",
+             (void*)nativeTestSeekToZero},
+            {"nativeTestFileFormat", "(Ljava/lang/String;)Z", (void*)nativeTestFileFormat},
+    };
+    jclass c = env->FindClass("android/mediav2/cts/ExtractorTest$FunctionalityTest");
+    return env->RegisterNatives(c, methodTable, sizeof(methodTable) / sizeof(JNINativeMethod));
+}
+
+extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* vm, void*) {
+    JNIEnv* env;
+    if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsExtractorTestSetDS(env) != JNI_OK) return JNI_ERR;
+    if (registerAndroidMediaV2CtsExtractorTestFunc(env) != JNI_OK) return JNI_ERR;
+    return JNI_VERSION_1_6;
+}
\ No newline at end of file
diff --git a/tests/media/src/android/mediav2/cts/ExtractorTest.java b/tests/media/src/android/mediav2/cts/ExtractorTest.java
index b4c4d01..8a71d14 100644
--- a/tests/media/src/android/mediav2/cts/ExtractorTest.java
+++ b/tests/media/src/android/mediav2/cts/ExtractorTest.java
@@ -254,15 +254,25 @@
                                     '/' + testSampleInfo.presentationTimeUs);
                         }
                         areTracksIdentical = false;
+                        break;
                     }
                     int refSz = refExtractor.readSampleData(refBuffer, 0);
-                    int testSz = testExtractor.readSampleData(testBuffer, 0);
-                    if (refSz != testSz || refSz != refSampleInfo.size) {
+                    if (refSz != refSampleInfo.size) {
                         if (ENABLE_LOGS) {
-                            Log.d(LOG_TAG, "Mime: " + refMime + " Size exp/got/got: " +
-                                    refSz + '/' + testSz + '/' + refSampleInfo.size);
+                            Log.d(LOG_TAG, "Mime: " + refMime + " Size exp/got: " +
+                                    refSampleInfo.size + '/' + refSz);
                         }
                         areTracksIdentical = false;
+                        break;
+                    }
+                    int testSz = testExtractor.readSampleData(testBuffer, 0);
+                    if (testSz != testSampleInfo.size) {
+                        if (ENABLE_LOGS) {
+                            Log.d(LOG_TAG, "Mime: " + refMime + " Size exp/got: " +
+                                    testSampleInfo.size + '/' + testSz);
+                        }
+                        areTracksIdentical = false;
+                        break;
                     }
                     int trackIndex = refExtractor.getSampleTrackIndex();
                     if (trackIndex != refTrackID) {
@@ -271,6 +281,7 @@
                                     " TrackID exp/got: " + refTrackID + '/' + trackIndex);
                         }
                         areTracksIdentical = false;
+                        break;
                     }
                     trackIndex = testExtractor.getSampleTrackIndex();
                     if (trackIndex != testTrackID) {
@@ -279,6 +290,7 @@
                                     " TrackID exp/got: " + testTrackID + '/' + trackIndex);
                         }
                         areTracksIdentical = false;
+                        break;
                     }
                     boolean haveRefSamples = refExtractor.advance();
                     boolean haveTestSamples = testExtractor.advance();
@@ -287,6 +299,7 @@
                             Log.d(LOG_TAG, "Mime: " + refMime + " Mismatch in sampleCount");
                         }
                         areTracksIdentical = false;
+                        break;
                     }
 
                     if (!haveRefSamples && !isExtractorOKonEOS(refExtractor)) {
@@ -294,12 +307,14 @@
                             Log.d(LOG_TAG, "Mime: " + refMime + " calls post advance() are not OK");
                         }
                         areTracksIdentical = false;
+                        break;
                     }
                     if (!haveTestSamples && !isExtractorOKonEOS(testExtractor)) {
                         if (ENABLE_LOGS) {
                             Log.d(LOG_TAG, "Mime: " + refMime + " calls post advance() are not OK");
                         }
                         areTracksIdentical = false;
+                        break;
                     }
                     if (ENABLE_LOGS) {
                         Log.v(LOG_TAG, "Mime: " + refMime + " Sample: " + frameCount +
@@ -307,8 +322,7 @@
                                 " size: " + refSampleInfo.size +
                                 " ts: " + refSampleInfo.presentationTimeUs);
                     }
-                    if (!areTracksIdentical || !haveRefSamples || !haveTestSamples ||
-                            frameCount >= sampleLimit) {
+                    if (!haveRefSamples || frameCount >= sampleLimit) {
                         break;
                     }
                 }
@@ -343,6 +357,10 @@
 
         private MediaExtractor mRefExtractor;
 
+        static {
+            System.loadLibrary("ctsmediav2extractor_jni");
+        }
+
         @Before
         public void setUp() throws IOException {
             mRefExtractor = new MediaExtractor();
@@ -538,6 +556,14 @@
             testExtractor.unselectTrack(0);
             testExtractor.release();
         }
+
+        private native boolean nativeTestDataSource(String srcPath, String srcUrl);
+
+        @Test
+        public void testDataSourceNative() {
+            assertTrue(testName.getMethodName() + " failed ",
+                    nativeTestDataSource(mInpPrefix + mInpMedia, mInpMediaUrl));
+        }
     }
 
     /**
@@ -551,6 +577,10 @@
         private String[] mSrcFiles;
         private String mMime;
 
+        static {
+            System.loadLibrary("ctsmediav2extractor_jni");
+        }
+
         @Rule
         public TestName testName = new TestName();
 
@@ -618,6 +648,16 @@
             });
         }
 
+        private native boolean nativeTestExtract(String srcPath, String refPath, String mime);
+
+        private native boolean nativeTestSeek(String srcPath, String mime);
+
+        private native boolean nativeTestSeekFlakiness(String srcPath, String mime);
+
+        private native boolean nativeTestSeekToZero(String srcPath, String mime);
+
+        private native boolean nativeTestFileFormat(String srcPath);
+
         public FunctionalityTest(String mime, String[] srcFiles) {
             mMime = mime;
             mSrcFiles = srcFiles;
@@ -763,12 +803,13 @@
                     if (!isSampleInfoIdentical(arg.mExpected, received)) {
                         errCnt++;
                         if (ENABLE_LOGS) {
-                            Log.d(LOG_TAG, " flags exp/got: " +
-                                    received.flags + '/' + arg.mExpected.flags);
-                            Log.d(LOG_TAG, " size exp/got: " +
-                                    received.size + '/' + arg.mExpected.size);
-                            Log.d(LOG_TAG, " ts exp/got: " + received.presentationTimeUs +
-                                    '/' + arg.mExpected.presentationTimeUs);
+                            Log.d(LOG_TAG, " flags exp/got: " + arg.mExpected.flags + '/' +
+                                    received.flags);
+                            Log.d(LOG_TAG,
+                                    " size exp/got: " + arg.mExpected.size + '/' + received.size);
+                            Log.d(LOG_TAG,
+                                    " ts exp/got: " + arg.mExpected.presentationTimeUs + '/' +
+                                            received.presentationTimeUs);
                         }
                     }
                 }
@@ -798,7 +839,7 @@
             MediaExtractor refExtractor = new MediaExtractor();
             refExtractor.setDataSource(mInpPrefix + mSrcFiles[0]);
             boolean isOk = true;
-            for (int i = 1; i < mSrcFiles.length; i++) {
+            for (int i = 1; i < mSrcFiles.length && isOk; i++) {
                 MediaExtractor testExtractor = new MediaExtractor();
                 testExtractor.setDataSource(mInpPrefix + mSrcFiles[i]);
                 if (!isMediaSimilar(refExtractor, testExtractor, mMime, Integer.MAX_VALUE)) {
@@ -840,6 +881,7 @@
                     }
                     if (!codecListSupp.contains(mMime)) {
                         isOk = false;
+                        break;
                     }
                 }
             }
@@ -867,6 +909,7 @@
                     }
                     if (!codecListSupp.contains(mMime)) {
                         isOk = false;
+                        break;
                     }
                 }
             }
@@ -900,12 +943,42 @@
                     extractor.seekTo(0, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
                     currInfo.set(0, (int) extractor.getSampleSize(),
                             extractor.getSampleTime(), extractor.getSampleFlags());
-                    extractor.unselectTrack(trackID);
                     if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) {
                         if (!codecListSupp.contains(mMime)) {
+                            if (ENABLE_LOGS) {
+                                Log.d(LOG_TAG, "seen mismatch seekTo(0, SEEK_TO_CLOSEST_SYNC)");
+                                Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' +
+                                        currInfo.flags);
+                                Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' +
+                                        currInfo.size);
+                                Log.d(LOG_TAG,
+                                        " ts exp/got: " + sampleInfoAtZero.presentationTimeUs +
+                                                '/' + currInfo.presentationTimeUs);
+                            }
                             isOk = false;
+                            break;
                         }
                     }
+                    extractor.seekTo(-1L, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+                    currInfo.set(0, (int) extractor.getSampleSize(),
+                            extractor.getSampleTime(), extractor.getSampleFlags());
+                    if (!isSampleInfoIdentical(sampleInfoAtZero, currInfo)) {
+                        if (!codecListSupp.contains(mMime)) {
+                            if (ENABLE_LOGS) {
+                                Log.d(LOG_TAG, "seen mismatch seekTo(-1, SEEK_TO_CLOSEST_SYNC)");
+                                Log.d(LOG_TAG, " flags exp/got: " + sampleInfoAtZero.flags + '/' +
+                                        currInfo.flags);
+                                Log.d(LOG_TAG, " size exp/got: " + sampleInfoAtZero.size + '/' +
+                                        currInfo.size);
+                                Log.d(LOG_TAG,
+                                        " ts exp/got: " + sampleInfoAtZero.presentationTimeUs +
+                                                '/' + currInfo.presentationTimeUs);
+                            }
+                            isOk = false;
+                            break;
+                        }
+                    }
+                    extractor.unselectTrack(trackID);
                 }
                 extractor.release();
             }
@@ -928,5 +1001,94 @@
                 extractor.release();
             }
         }
+
+        @LargeTest
+        @Test
+        public void testExtractNative() {
+            assumeTrue(shouldRunTest(mMime));
+            assertTrue(mSrcFiles.length > 1);
+            assumeTrue("TODO(b/146925481)", mMime == MediaFormat.MIMETYPE_VIDEO_VP8 ||
+                    mMime == MediaFormat.MIMETYPE_VIDEO_VP9 ||
+                    mMime == MediaFormat.MIMETYPE_VIDEO_AV1 ||
+                    mMime == MediaFormat.MIMETYPE_AUDIO_FLAC);
+            boolean isOk = true;
+            for (int i = 1; i < mSrcFiles.length; i++) {
+                if (!nativeTestExtract(mInpPrefix + mSrcFiles[0], mInpPrefix + mSrcFiles[i],
+                        mMime)) {
+                    Log.d(LOG_TAG, "Files: " + mSrcFiles[0] + ", " + mSrcFiles[i] +
+                            " are different from extractor perpsective");
+                    if (!codecListSupp.contains(mMime)) {
+                        isOk = false;
+                        break;
+                    }
+                }
+            }
+            assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk);
+        }
+
+        @LargeTest
+        @Test
+        @Ignore("TODO(b/146420831)")
+        public void testSeekNative() {
+            assumeTrue(shouldRunTest(mMime));
+            boolean isOk = true;
+            for (String srcFile : mSrcFiles) {
+                if (!nativeTestSeek(mInpPrefix + srcFile, mMime)) {
+                    if (!codecListSupp.contains(mMime)) {
+                        isOk = false;
+                        break;
+                    }
+                }
+            }
+            assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk);
+        }
+
+        @LargeTest
+        @Test
+        public void testSeekFlakinessNative() {
+            assumeTrue(shouldRunTest(mMime));
+            boolean isOk = true;
+            for (String srcFile : mSrcFiles) {
+                if (!nativeTestSeekFlakiness(mInpPrefix + srcFile, mMime)) {
+                    if (!codecListSupp.contains(mMime)) {
+                        isOk = false;
+                        break;
+                    }
+                }
+            }
+            assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk);
+        }
+
+        @SmallTest
+        @Test
+        public void testSeekToZeroNative() {
+            assumeTrue(shouldRunTest(mMime));
+            assumeTrue("TODO(b/146925481)", mMime != MediaFormat.MIMETYPE_AUDIO_MPEG &&
+                    mMime != MediaFormat.MIMETYPE_AUDIO_AAC);
+            boolean isOk = true;
+            for (String srcFile : mSrcFiles) {
+                if (!nativeTestSeekToZero(mInpPrefix + srcFile, mMime)) {
+                    if (!codecListSupp.contains(mMime)) {
+                        isOk = false;
+                        break;
+                    }
+                }
+            }
+            assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk);
+        }
+
+        @SmallTest
+        @Test
+        public void testFileFormatNative() {
+            assumeTrue(shouldRunTest(mMime));
+            boolean isOk = true;
+            for (String srcFile : mSrcFiles) {
+                if (!nativeTestFileFormat(mInpPrefix + srcFile)) {
+                    isOk = false;
+                    break;
+                }
+                assertTrue(testName.getMethodName() + " failed for mime: " + mMime, isOk);
+            }
+        }
     }
 }
diff --git a/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java b/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java
new file mode 100644
index 0000000..84122cd
--- /dev/null
+++ b/tests/media/src/android/mediav2/cts/ExtractorUnitTest.java
@@ -0,0 +1,793 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.mediav2.cts;
+
+import android.content.res.AssetFileDescriptor;
+import android.media.MediaDataSource;
+import android.media.MediaExtractor;
+import android.os.ParcelFileDescriptor;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.experimental.runners.Enclosed;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+@RunWith(Enclosed.class)
+public class ExtractorUnitTest {
+    private static final int MAX_SAMPLE_SIZE = 4 * 1024 * 1024;
+    private static final String mInpPrefix = WorkDir.getMediaDirString();
+    private static final String mInpMedia = "ForBiggerEscapes.mp4";
+
+    @SmallTest
+    public static class TestApi {
+        @Rule
+        public TestName testName = new TestName();
+
+        @Test
+        public void testGetTrackCountBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid trackCount before setDataSource",
+                        extractor.getTrackCount() <= 0);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetTrackCountAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getTrackCount();
+                fail("getTrackCount succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testSelectTrackBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.selectTrack(0);
+                fail("selectTrack succeeds before setDataSource");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testSelectTrackForInvalidIndex() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                try {
+                    extractor.selectTrack(-1);
+                    fail("selectTrack succeeds for track index: -1");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    extractor.selectTrack(extractor.getTrackCount());
+                    fail("selectTrack succeeds for out of bounds track index: " +
+                            extractor.getTrackCount());
+                } catch (Exception e) {
+                    // expected
+                }
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIdempotentSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                extractor.selectTrack(0);
+                extractor.selectTrack(0);
+            } catch (Exception e) {
+                fail("multiple selection of same track has failed");
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testSelectTrackAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.selectTrack(0);
+                fail("selectTrack succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testUnselectTrackBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.unselectTrack(0);
+                fail("unselectTrack succeeds before setDataSource");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testUnselectTrackForInvalidIndex() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                try {
+                    extractor.unselectTrack(-1);
+                    fail("unselectTrack succeeds for track index: -1");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    extractor.unselectTrack(extractor.getTrackCount());
+                    fail("unselectTrack succeeds for out of bounds track index: " +
+                            extractor.getTrackCount());
+                } catch (Exception e) {
+                    // expected
+                }
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testUnselectTrackForUnSelectedTrackIndex() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                extractor.unselectTrack(0);
+            } catch (Exception e) {
+                fail("un-selection of non-selected track has failed");
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIdempotentUnselectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                extractor.selectTrack(0);
+                extractor.unselectTrack(0);
+                extractor.unselectTrack(0);
+            } catch (Exception e) {
+                fail("multiple un-selection of selected track has failed");
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testUnselectTrackAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.unselectTrack(0);
+                fail("unselectTrack succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testSeekToBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.seekTo(33000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+                if (extractor.getSampleTime() != -1 || extractor.getSampleSize() != -1 ||
+                        extractor.getSampleFlags() != -1) {
+                    fail("seekTo() succeeds before setting data source, returns non-negative " +
+                            "sampleTime / sampleSize / sampleFlags");
+                }
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testSeekToBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                extractor.seekTo(33000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+                if (extractor.getSampleTime() != -1 || extractor.getSampleSize() != -1 ||
+                        extractor.getSampleFlags() != -1) {
+                    fail("seekTo() succeeds before selectTrack, returns non-negative " +
+                            "sampleTime / sampleSize / sampleFlags");
+                }
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testSeekToForInvalidMode() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            extractor.selectTrack(0);
+            long pts = 33000;
+            try {
+                extractor.seekTo(pts, (int) pts);
+                fail("seekTo() succeeds for invalid mode: " + pts);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testSeekToAfterRelease() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            extractor.release();
+            try {
+                extractor.seekTo(33000, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
+                fail("seekTo() succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        @Ignore("TODO(b/148205432)")
+        public void testGetCachedDurationBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid cachedDuration before setDataSource",
+                        extractor.getCachedDuration() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetCachedDurationAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getCachedDuration();
+                fail("cachedDuration succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        @Ignore("TODO(b/148204634)")
+        public void testHasCacheReachedEOSBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("unexpected value received from hasCacheReachedEndOfStream before" +
+                        " setDataSource", !extractor.hasCacheReachedEndOfStream());
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testHasCacheReachedEOSAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.hasCacheReachedEndOfStream();
+                fail("hasCacheReachedEndOfStream succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetMetricsBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid metrics before setDataSource",
+                        extractor.getMetrics() == null);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetMetricsAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getMetrics();
+                fail("getMetrics() succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testIdempotentRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.release();
+                extractor.release();
+            } catch (Exception e) {
+                fail(e.getMessage());
+            }
+        }
+
+        @Test
+        public void testAdvanceBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("advance succeeds before setDataSource", !extractor.advance());
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testAdvanceBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("advance succeeds without any active tracks", !extractor.advance());
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testAdvanceAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.advance();
+                fail("advance succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetSampleFlagsBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid sampleFlag before setDataSource",
+                        extractor.getSampleFlags() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleFlagsBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("received valid sampleFlag without any active tracks",
+                        extractor.getSampleFlags() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleFlagsAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getSampleFlags();
+                fail("getSampleFlags succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetSampleTimeBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid sampleTime before setDataSource",
+                        extractor.getSampleTime() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleTimeBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("received valid sampleTime without any active tracks",
+                        extractor.getSampleTime() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleTimeAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getSampleTime();
+                fail("getSampleTime succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetSampleSizeBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid sampleSize before setDataSource",
+                        extractor.getSampleSize() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleSizeBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("received valid sampleSize without any active tracks",
+                        extractor.getSampleSize() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleSizeAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getSampleSize();
+                fail("getSampleSize succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetSampleTrackIndexBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                assertTrue("received valid sampleTrackIndex before setDataSource",
+                        extractor.getSampleTrackIndex() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleTrackIndexBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("received valid sampleTrackIndex without any active tracks",
+                        extractor.getSampleTrackIndex() == -1);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetSampleTrackIndexAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getSampleTrackIndex();
+                fail("getSampleTrackIndex succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testGetTrackFormatBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.getTrackFormat(0);
+                fail("getTrackFormat succeeds before setDataSource");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetTrackFormatForInvalidIndex() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                try {
+                    extractor.getTrackFormat(-1);
+                    fail("getTrackFormat succeeds for track index: -1");
+                } catch (Exception e) {
+                    // expected
+                }
+                try {
+                    extractor.getTrackFormat(extractor.getTrackCount());
+                    fail("getTrackFormat succeeds for out of bounds track index: " +
+                            extractor.getTrackCount());
+                } catch (Exception e) {
+                    // expected
+                }
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testGetTrackFormatAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            extractor.release();
+            try {
+                extractor.getTrackFormat(0);
+                fail("getTrackFormat succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testReadSampleDataBeforeSetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
+            try {
+                assertTrue("readSampleData returns val >= 0 before setDataSource",
+                        extractor.readSampleData(byteBuffer, 0) < 0);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testReadSampleDataBeforeSelectTrack() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            try {
+                assertTrue("readSampleData returns val >= 0 without any active tracks",
+                        extractor.readSampleData(byteBuffer, 0) < 0);
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIfInvalidOffsetIsRejectedByReadSampleData() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
+            extractor.setDataSource(mInpPrefix + mInpMedia);
+            extractor.selectTrack(0);
+            try {
+                // readSampleData with negative offset
+                try {
+                    extractor.readSampleData(byteBuffer, -1);
+                    fail("readSampleData succeeds with negative offset");
+                } catch (Exception e) {
+                    // expected
+                }
+
+                // readSampleData with byteBuffer's capacity - offset < frame size
+                int sampleSize = (int) extractor.getSampleSize();
+                try {
+                    extractor.readSampleData(byteBuffer, MAX_SAMPLE_SIZE - sampleSize + 1);
+                    fail("readSampleData succeeds when available size of byteBuffer is less than " +
+                            "frame size");
+                } catch (Exception e) {
+                    // expected
+                }
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testReadSampleDataAfterRelease() {
+            MediaExtractor extractor = new MediaExtractor();
+            ByteBuffer byteBuffer = ByteBuffer.allocate(MAX_SAMPLE_SIZE);
+            extractor.release();
+            try {
+                extractor.readSampleData(byteBuffer, 0);
+                fail("readSampleData succeeds after release");
+            } catch (Exception e) {
+                // expected
+            }
+        }
+
+        @Test
+        public void testIfInvalidDataSourceIsRejectedBySetDataSource() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            TestMediaDataSource dataSource =
+                    TestMediaDataSource.fromString(mInpPrefix + mInpMedia, true, false);
+            try {
+                try {
+                    extractor.setDataSource(dataSource);
+                    fail("setDataSource succeeds with malformed media data source");
+                } catch (Exception e) {
+                    // expected
+                }
+                assertTrue(dataSource.isClosed());
+                dataSource = TestMediaDataSource.fromString(mInpPrefix + mInpMedia, false, true);
+
+                try {
+                    extractor.setDataSource(dataSource);
+                    fail("setDataSource succeeds with malformed media data source");
+                } catch (Exception e) {
+                    // expected
+                }
+            } finally {
+                assertTrue(dataSource.isClosed());
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIfNullFDIsRejectedBySetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.setDataSource((FileDescriptor) null);
+                fail("setDataSource succeeds with null fd");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIfWriteOnlyAssetFDIsRejectedBySetDataSource() throws IOException {
+            File inpFile = File.createTempFile("ExtractorTestApisetDSAFD", ".in");
+            MediaExtractor extractor = new MediaExtractor();
+            try (ParcelFileDescriptor parcelFD = ParcelFileDescriptor
+                    .open(inpFile, ParcelFileDescriptor.MODE_WRITE_ONLY);
+                 AssetFileDescriptor afd = new AssetFileDescriptor(parcelFD, 0,
+                         AssetFileDescriptor.UNKNOWN_LENGTH)) {
+                extractor.setDataSource(afd);
+                fail("setDataSource succeeds write only afd");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+            inpFile.delete();
+        }
+
+        @Test
+        public void testIfWriteOnlyFDIsRejectedBySetDataSource() throws IOException {
+            MediaExtractor extractor = new MediaExtractor();
+            File inpFile = File.createTempFile("ExtractorTestApisetDSFD", ".in");
+            try (FileOutputStream fOut = new FileOutputStream(inpFile)) {
+                extractor.setDataSource(fOut.getFD());
+                fail("setDataSource succeeds write only fd");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+            inpFile.delete();
+        }
+
+        @Test
+        public void testIfNullMediaDataSourceIsRejectedBySetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.setDataSource((MediaDataSource) null);
+                fail("setDataSource succeeds with null data source");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIfNullFileIsRejectedBySetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.setDataSource((String) null);
+                fail("setDataSource succeeds with null file path");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+
+        @Test
+        public void testIfNullAssetFDIsRejectedBySetDataSource() {
+            MediaExtractor extractor = new MediaExtractor();
+            try {
+                extractor.setDataSource((AssetFileDescriptor) null);
+                fail("setDataSource succeeds with null asset fd");
+            } catch (Exception e) {
+                // expected
+            } finally {
+                extractor.release();
+            }
+        }
+    }
+}
diff --git a/tests/quickaccesswallet/AndroidManifest.xml b/tests/quickaccesswallet/AndroidManifest.xml
index 914d809..2765dd2 100755
--- a/tests/quickaccesswallet/AndroidManifest.xml
+++ b/tests/quickaccesswallet/AndroidManifest.xml
@@ -20,6 +20,17 @@
           android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <!-- Required to update Secure Settings to set default payment app -->
+    <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+    <!-- Required for HostApduService -->
+    <uses-permission android:name="android.permission.NFC"/>
+    <!-- Required to test QuickAccessWalletClient feature availability -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
+    <uses-permission android:name="android.permission.CREATE_USERS" />
+    <!-- Required to bind to the QuickAccessWalletService -->
+    <uses-permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE" />
+
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="android.quickaccesswallet.QuickAccessWalletActivity" >
@@ -28,6 +39,47 @@
                 <category android:name="android.intent.category.LAUNCHER" />
             </intent-filter>
         </activity>
+
+        <service
+            android:name="android.quickaccesswallet.TestHostApduService"
+            android:exported="true"
+            android:permission="android.permission.BIND_NFC_SERVICE"
+            android:label="@string/app_name">
+            <intent-filter>
+                <action android:name="android.nfc.cardemulation.action.HOST_APDU_SERVICE"/>
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data
+                android:name="android.nfc.cardemulation.host_apdu_service"
+                android:resource="@xml/hce_aids"/>
+        </service>
+
+        <service
+            android:name="android.quickaccesswallet.TestQuickAccessWalletService"
+            android:enabled="true"
+            android:label="@string/app_name"
+            android:icon="@drawable/android"
+            android:permission="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.quickaccesswallet"
+                       android:resource="@xml/quickaccesswallet_configuration" />;
+        </service>
+
+        <service
+            android:name="android.quickaccesswallet.NoPermissionQuickAccessWalletService"
+            android:enabled="false"
+            android:label="@string/app_name"
+            android:icon="@drawable/android">
+            <intent-filter>
+                <action android:name="android.service.quickaccesswallet.QuickAccessWalletService" />
+                <category android:name="android.intent.category.DEFAULT"/>
+            </intent-filter>
+            <meta-data android:name="android.quickaccesswallet"
+                       android:resource="@xml/quickaccesswallet_configuration" />;
+        </service>
     </application>
 
     <!--  self-instrumenting test package. -->
diff --git a/tests/quickaccesswallet/res/drawable/android.png b/tests/quickaccesswallet/res/drawable/android.png
new file mode 100644
index 0000000..8a9e698
--- /dev/null
+++ b/tests/quickaccesswallet/res/drawable/android.png
Binary files differ
diff --git a/tests/quickaccesswallet/res/values/strings.xml b/tests/quickaccesswallet/res/values/strings.xml
new file mode 100644
index 0000000..e1c9e08
--- /dev/null
+++ b/tests/quickaccesswallet/res/values/strings.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<resources>
+    <string name="app_name">Test Wallet</string>
+</resources>
diff --git a/tests/quickaccesswallet/res/xml/hce_aids.xml b/tests/quickaccesswallet/res/xml/hce_aids.xml
new file mode 100644
index 0000000..30d985f
--- /dev/null
+++ b/tests/quickaccesswallet/res/xml/hce_aids.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<host-apdu-service
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:requireDeviceUnlock="false"
+    android:description="@string/app_name">
+    <aid-group android:category="payment">
+        <!-- PPSE aid -->
+        <aid-filter android:name="325041592E5359532E4444463031"/>
+    </aid-group>
+</host-apdu-service>
+
diff --git a/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml b/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml
new file mode 100644
index 0000000..1e14677
--- /dev/null
+++ b/tests/quickaccesswallet/res/xml/quickaccesswallet_configuration.xml
@@ -0,0 +1,20 @@
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<quickaccesswallet-service
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:settingsActivity="android.quickaccesswallet.QuickAccessWalletSettingsActivity"
+    android:targetActivity="android.quickaccesswallet.QuickAccessWalletActivity"/>
\ No newline at end of file
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/NoPermissionQuickAccessWalletService.java b/tests/quickaccesswallet/src/android/quickaccesswallet/NoPermissionQuickAccessWalletService.java
new file mode 100644
index 0000000..3c36971
--- /dev/null
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/NoPermissionQuickAccessWalletService.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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.quickaccesswallet;
+
+import android.service.quickaccesswallet.GetWalletCardsCallback;
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.service.quickaccesswallet.SelectWalletCardRequest;
+
+public class NoPermissionQuickAccessWalletService extends QuickAccessWalletService {
+
+    @Override
+    public void onWalletCardsRequested(
+            GetWalletCardsRequest request,
+            GetWalletCardsCallback callback) {
+    }
+
+    @Override
+    public void onWalletCardSelected(SelectWalletCardRequest request) {
+    }
+
+    @Override
+    public void onWalletDismissed() {
+    }
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletActivity.java b/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletActivity.java
index 639bf7c..4931ecb 100644
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletActivity.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletActivity.java
@@ -19,7 +19,7 @@
 import android.app.Activity;
 
 /**
- * A simple activity.
+ * A simple activity that would show the wallet
  */
 public class QuickAccessWalletActivity extends Activity {
 }
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletSettingsActivity.java b/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletSettingsActivity.java
new file mode 100644
index 0000000..af5a6d5
--- /dev/null
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/QuickAccessWalletSettingsActivity.java
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.quickaccesswallet;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+/**
+ * A simple activity for wallet settings
+ */
+public class QuickAccessWalletSettingsActivity extends Activity {
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/TestHostApduService.java b/tests/quickaccesswallet/src/android/quickaccesswallet/TestHostApduService.java
new file mode 100644
index 0000000..15b42a0
--- /dev/null
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/TestHostApduService.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2020 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.quickaccesswallet;
+
+import android.nfc.cardemulation.HostApduService;
+import android.os.Bundle;
+
+public class TestHostApduService extends HostApduService {
+
+    @Override
+    public byte[] processCommandApdu(byte[] commandApdu, Bundle extras) {
+        return new byte[0];
+    }
+
+    @Override
+    public void onDeactivated(int reason) {
+
+    }
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/TestQuickAccessWalletService.java b/tests/quickaccesswallet/src/android/quickaccesswallet/TestQuickAccessWalletService.java
new file mode 100644
index 0000000..7aa2c3e
--- /dev/null
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/TestQuickAccessWalletService.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2020 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.quickaccesswallet;
+
+import android.app.PendingIntent;
+import android.content.Intent;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.service.quickaccesswallet.GetWalletCardsCallback;
+import android.service.quickaccesswallet.GetWalletCardsError;
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.GetWalletCardsResponse;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.service.quickaccesswallet.SelectWalletCardRequest;
+import android.service.quickaccesswallet.WalletCard;
+import android.service.quickaccesswallet.WalletServiceEvent;
+import android.util.Log;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+public class TestQuickAccessWalletService extends QuickAccessWalletService {
+
+    private static final String TAG = "TestQAWalletSvc";
+    private static GetWalletCardsResponse sWalletCardsResponse;
+    private static GetWalletCardsError sWalletCardsError;
+    private static List<SelectWalletCardRequest> sSelectWalletCardRequests = new ArrayList<>();
+    private static boolean sWalletDismissed;
+    private static WeakReference<TestQuickAccessWalletService> sServiceRef =
+            new WeakReference<>(null);
+    private static CountDownLatch sRequestCountDownLatch = new CountDownLatch(0);
+    private static CountDownLatch sBindCounter = new CountDownLatch(0);
+    private static CountDownLatch sUnbindCounter = new CountDownLatch(0);
+
+    public static void resetStaticFields() {
+        sWalletCardsResponse = null;
+        sWalletCardsError = null;
+        sSelectWalletCardRequests = new ArrayList<>();
+        sWalletDismissed = false;
+        sRequestCountDownLatch = new CountDownLatch(0);
+        sBindCounter = new CountDownLatch(0);
+        sUnbindCounter = new CountDownLatch(0);
+    }
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        sServiceRef = new WeakReference<>(this);
+    }
+
+    @Override
+    public boolean onUnbind(Intent intent) {
+        sUnbindCounter.countDown();
+        return super.onUnbind(intent);
+    }
+
+    @Override
+    public void onDestroy() {
+        sServiceRef.clear();
+        super.onDestroy();
+    }
+
+    @Override
+    public void onWalletCardsRequested(
+            GetWalletCardsRequest request,
+            GetWalletCardsCallback callback) {
+        Log.i(TAG, "onWalletCardsRequested");
+        GetWalletCardsError error = sWalletCardsError;
+        if (error != null) {
+            callback.onFailure(error);
+            return;
+        }
+        GetWalletCardsResponse response = sWalletCardsResponse;
+        if (response == null) {
+            Bitmap bitmap = Bitmap.createBitmap(
+                    request.getCardWidthPx(), request.getCardHeightPx(), Bitmap.Config.ARGB_8888);
+            Icon cardImage = Icon.createWithBitmap(bitmap.copy(Bitmap.Config.HARDWARE, false));
+            Intent intent = new Intent(this, QuickAccessWalletActivity.class);
+            PendingIntent pendingIntent =
+                    PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+            WalletCard walletCard = new WalletCard.Builder("card1", cardImage, "Card 1",
+                    pendingIntent).build();
+            List<WalletCard> walletCards = Collections.singletonList(walletCard);
+            response = new GetWalletCardsResponse(walletCards, 0);
+        }
+        callback.onSuccess(response);
+    }
+
+    @Override
+    public void onWalletCardSelected(SelectWalletCardRequest request) {
+        Log.i(TAG, "onWalletCardSelected");
+        sSelectWalletCardRequests.add(request);
+        sRequestCountDownLatch.countDown();
+    }
+
+    @Override
+    public void onWalletDismissed() {
+        Log.i(TAG, "onWalletDismissed");
+        sWalletDismissed = true;
+        sRequestCountDownLatch.countDown();
+    }
+
+    public static void sendEvent(WalletServiceEvent event) {
+        TestQuickAccessWalletService service = sServiceRef.get();
+        if (service != null) {
+            service.sendWalletServiceEvent(event);
+        }
+    }
+
+    public static List<SelectWalletCardRequest> getSelectRequests() {
+        return new ArrayList<>(sSelectWalletCardRequests);
+    }
+
+    public static void setWalletCardsResponse(GetWalletCardsResponse response) {
+        sWalletCardsResponse = response;
+    }
+
+    public static void setWalletCardsError(GetWalletCardsError error) {
+        sWalletCardsError = error;
+    }
+
+    public static boolean isWalletDismissed() {
+        return sWalletDismissed;
+    }
+
+    public static void setExpectedRequestCount(int countdown) {
+        sRequestCountDownLatch = new CountDownLatch(countdown);
+    }
+
+    public static void awaitRequests(long timeout, TimeUnit timeUnit) throws InterruptedException {
+        sRequestCountDownLatch.await(timeout, timeUnit);
+    }
+
+    public static void setExpectedBindCount(int count) {
+        sBindCounter = new CountDownLatch(count);
+    }
+
+    public static void awaitBinding(long timeout, TimeUnit unit) throws InterruptedException {
+        sBindCounter.await(timeout, unit);
+    }
+
+    public static void setExpectedUnbindCount(int count) {
+        sUnbindCounter = new CountDownLatch(count);
+    }
+
+    public static void awaitUnbinding(long timeout, TimeUnit unit) throws InterruptedException {
+        sUnbindCounter.await(timeout, unit);
+    }
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsErrorTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsErrorTest.java
index 6e9075e..f38639a 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsErrorTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsErrorTest.java
@@ -22,14 +22,12 @@
 import android.content.Context;
 import android.graphics.drawable.Icon;
 import android.os.Parcel;
-import android.quickaccesswallet.QuickAccessWalletActivity;
 import android.service.quickaccesswallet.GetWalletCardsError;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.rule.ActivityTestRule;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -39,19 +37,15 @@
 @RunWith(AndroidJUnit4.class)
 public class GetWalletCardsErrorTest {
 
-    @Rule
-    public ActivityTestRule<QuickAccessWalletActivity> mActivityRule =
-            new ActivityTestRule<>(QuickAccessWalletActivity.class);
-
     private Context mContext;
 
     @Before
     public void setup() {
-        mContext = mActivityRule.getActivity().getApplicationContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
 
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         Icon icon = Icon.createWithResource(mContext, android.R.drawable.ic_dialog_info);
         GetWalletCardsError error = new GetWalletCardsError(icon, "error");
 
@@ -64,7 +58,7 @@
     }
 
     @Test
-    public void parcel_withNullIcon_toParcel() {
+    public void testParcel_withNullIcon_toParcel() {
         GetWalletCardsError error = new GetWalletCardsError(null, "error");
 
         Parcel p = Parcel.obtain();
@@ -76,7 +70,7 @@
     }
 
     @Test
-    public void parcel_withNullIconAndMessage_toParcel() {
+    public void testParcel_withNullIconAndMessage_toParcel() {
         GetWalletCardsError error = new GetWalletCardsError(null, null);
 
         Parcel p = Parcel.obtain();
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsRequestTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsRequestTest.java
index 44520d1..a5aa694 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsRequestTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsRequestTest.java
@@ -32,7 +32,7 @@
 public class GetWalletCardsRequestTest {
 
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         GetWalletCardsRequest request = new GetWalletCardsRequest(100, 70, 32, 5);
 
         Parcel p = Parcel.obtain();
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsResponseTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsResponseTest.java
index 605efd2..92b7550 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsResponseTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/GetWalletCardsResponseTest.java
@@ -31,10 +31,9 @@
 import android.service.quickaccesswallet.WalletCard;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.rule.ActivityTestRule;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -49,19 +48,15 @@
     private static final int CARD_WIDTH = 70;
     private static final int CARD_HEIGHT = 44;
 
-    @Rule
-    public ActivityTestRule<QuickAccessWalletActivity> mActivityRule =
-            new ActivityTestRule<>(QuickAccessWalletActivity.class);
-
     private Context mContext;
 
     @Before
     public void setup() {
-        mContext = mActivityRule.getActivity().getApplicationContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
 
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         Intent intent = new Intent(mContext, QuickAccessWalletActivity.class);
         WalletCard card1 = new WalletCard.Builder(
                 "card1",
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/PowerMenuTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/PowerMenuTest.java
deleted file mode 100755
index e80a92a..0000000
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/PowerMenuTest.java
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2020 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.quickaccesswallet.cts;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.app.Instrumentation;
-import android.app.UiAutomation;
-import android.os.SystemClock;
-import android.quickaccesswallet.QuickAccessWalletActivity;
-import android.service.quickaccesswallet.WalletCard;
-import android.view.KeyEvent;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.platform.app.InstrumentationRegistry;
-import androidx.test.rule.ActivityTestRule;
-import androidx.test.uiautomator.UiDevice;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Tests parceling of the {@link WalletCard}
- */
-@RunWith(AndroidJUnit4.class)
-public class PowerMenuTest {
-
-    @Rule
-    public ActivityTestRule<QuickAccessWalletActivity> mActivityRule =
-            new ActivityTestRule<>(QuickAccessWalletActivity.class);
-
-    @Test
-    public void longPress_showsPowerMenu() throws Exception {
-        // TODO: provide wallet card service, provide hce service, make app default nfc payment app.
-
-        Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
-        UiAutomation uiAutomation = instrumentation.getUiAutomation();
-        UiDevice uiDevice = UiDevice.getInstance(instrumentation);
-        uiDevice.wakeUp();
-
-        assertThat(uiDevice.isScreenOn()).isTrue();
-
-        long eventTime = SystemClock.uptimeMillis();
-        int keyCode = 26;
-        int metaState = 0;
-        KeyEvent downEvent = new KeyEvent(eventTime, eventTime, 0, keyCode, 0, metaState, -1, 0, 0,
-                257);
-        assertThat(uiAutomation.injectInputEvent(downEvent, true)).isTrue();
-        Thread.sleep(1_500);
-        KeyEvent upEvent = new KeyEvent(eventTime, eventTime, 1, keyCode, 0, metaState, -1, 0, 0,
-                257);
-        assertThat(uiAutomation.injectInputEvent(upEvent, true)).isTrue();
-        Thread.sleep(5_00);
-
-        uiDevice.pressBack();
-        uiDevice.pressBack();
-
-        // TODO: verify that wallet service provided cards to UI
-    }
-}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
new file mode 100755
index 0000000..7130765
--- /dev/null
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/QuickAccessWalletClientTest.java
@@ -0,0 +1,512 @@
+/*
+ * Copyright (C) 2020 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.quickaccesswallet.cts;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
+import android.graphics.drawable.Icon;
+import android.provider.Settings;
+import android.quickaccesswallet.NoPermissionQuickAccessWalletService;
+import android.quickaccesswallet.QuickAccessWalletActivity;
+import android.quickaccesswallet.QuickAccessWalletSettingsActivity;
+import android.quickaccesswallet.TestHostApduService;
+import android.quickaccesswallet.TestQuickAccessWalletService;
+import android.service.quickaccesswallet.GetWalletCardsError;
+import android.service.quickaccesswallet.GetWalletCardsRequest;
+import android.service.quickaccesswallet.GetWalletCardsResponse;
+import android.service.quickaccesswallet.QuickAccessWalletClient;
+import android.service.quickaccesswallet.QuickAccessWalletClient.WalletServiceEventListener;
+import android.service.quickaccesswallet.QuickAccessWalletService;
+import android.service.quickaccesswallet.SelectWalletCardRequest;
+import android.service.quickaccesswallet.WalletCard;
+import android.service.quickaccesswallet.WalletServiceEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+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.Collections;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * Tests parceling of the {@link WalletCard}
+ */
+@RunWith(AndroidJUnit4.class)
+public class QuickAccessWalletClientTest {
+
+    private static final GetWalletCardsRequest GET_WALLET_CARDS_REQUEST =
+            new GetWalletCardsRequest(700, 440, 64, 5);
+
+    private static final int SETTING_DISABLED = 0;
+    private static final int SETTING_ENABLED = 1;
+    private Context mContext;
+    private String mDefaultPaymentApp;
+
+    @Before
+    public void setUp() {
+        // Save current default payment app
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
+        ContentResolver cr = mContext.getContentResolver();
+        mDefaultPaymentApp = Settings.Secure.getString(cr,
+                Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
+
+        ComponentName component =
+                ComponentName.createRelative(mContext, TestHostApduService.class.getName());
+        Settings.Secure.putString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+                component.flattenToString());
+        TestQuickAccessWalletService.resetStaticFields();
+    }
+
+    @After
+    public void tearDown() {
+        // Restore saved default payment app
+        ContentResolver cr = mContext.getContentResolver();
+        Settings.Secure.putString(cr, Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
+                mDefaultPaymentApp);
+
+        // Return all services to default state
+        setServiceState(TestQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+        setServiceState(NoPermissionQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
+        TestQuickAccessWalletService.resetStaticFields();
+    }
+
+    @Test
+    public void testIsWalletServiceAvailable_returnsFalseIfNoServiceAvailable() {
+        setServiceState(TestQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        assertThat(client.isWalletServiceAvailable()).isFalse();
+    }
+
+    @Test
+    public void testIsWalletFeatureAvailableWhenDeviceLocked_checksSecureSettings() {
+        ContentResolver cr = mContext.getContentResolver();
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+
+        int showNotif = Settings.Secure.getInt(
+                cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
+        int allowPriv = Settings.Secure.getInt(
+                cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+
+        try {
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_ENABLED);
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_ENABLED);
+            assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isTrue();
+
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_ENABLED);
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+            assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
+
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_ENABLED);
+            assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
+
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, SETTING_DISABLED);
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, SETTING_DISABLED);
+            assertThat(client.isWalletFeatureAvailableWhenDeviceLocked()).isFalse();
+        } finally {
+            // return settings to original values
+            Settings.Secure.putInt(cr, Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, showNotif);
+            Settings.Secure.putInt(
+                    cr, Settings.Secure.LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, allowPriv);
+        }
+    }
+
+    @Test
+    public void testGetWalletCards_success() throws Exception {
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        assertThat(client.isWalletServiceAvailable()).isTrue();
+        TestCallback callback = new TestCallback();
+
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mResponse).isNotNull();
+        assertThat(callback.mResponse.getWalletCards()).hasSize(1);
+        assertThat(callback.mError).isNull();
+    }
+
+    @Test
+    public void testGetWalletCards_failsIfNoServiceAvailable() throws Exception {
+        setServiceState(TestQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        assertThat(client.isWalletServiceAvailable()).isFalse();
+        TestCallback callback = new TestCallback();
+
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mResponse).isNull();
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_failsIfServiceDoesNotRequirePermission() throws Exception {
+        setServiceState(NoPermissionQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        setServiceState(TestQuickAccessWalletService.class,
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        assertThat(client.isWalletServiceAvailable()).isFalse();
+        TestCallback callback = new TestCallback();
+
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mResponse).isNull();
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidCard_nullId_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder(null, createCardImage(), "Card",
+                createPendingIntent()).build();
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(Collections.singletonList(card), 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidCard_nullImage_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", null, "Card",
+                createPendingIntent()).build();
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(Collections.singletonList(card), 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidCard_nullContentDesc_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", createCardImage(), null,
+                createPendingIntent()).build();
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(Collections.singletonList(card), 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+        callback.await(3, TimeUnit.SECONDS);
+
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidCard_nullPendingIntent_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", createCardImage(), "card", null).build();
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(Collections.singletonList(card), 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidResponse_tooManyCards_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", createCardImage(), "card",
+                createPendingIntent()).build();
+        List<WalletCard> walletCards = Arrays.asList(card, card, card, card, card, card, card);
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(walletCards, 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_zeroCards_isAllowed() throws Exception {
+        List<WalletCard> walletCards = Collections.emptyList();
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(walletCards, 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mResponse).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidResponse_nullCards_fails() throws Exception {
+        TestQuickAccessWalletService.setWalletCardsResponse(new GetWalletCardsResponse(null, 0));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidResponse_negativeIndex_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", createCardImage(), "card",
+                createPendingIntent()).build();
+        List<WalletCard> walletCards = Arrays.asList(card, card, card);
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(walletCards, -1));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+
+        callback.await(3, TimeUnit.SECONDS);
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_invalidResponse_indexOutOfBounds_fails() throws Exception {
+        WalletCard card = new WalletCard.Builder("cardId", createCardImage(), "card",
+                createPendingIntent()).build();
+        List<WalletCard> walletCards = Arrays.asList(card, card, card);
+        TestQuickAccessWalletService.setWalletCardsResponse(
+                new GetWalletCardsResponse(walletCards, 3));
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+        callback.await(3, TimeUnit.SECONDS);
+
+        assertThat(callback.mError).isNotNull();
+    }
+
+    @Test
+    public void testGetWalletCards_serviceResponseWithError_success() throws Exception {
+        GetWalletCardsError error = new GetWalletCardsError(null, "error");
+        TestQuickAccessWalletService.setWalletCardsError(error);
+
+        TestCallback callback = new TestCallback();
+
+        QuickAccessWalletClient.create(mContext).getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+        callback.await(3, TimeUnit.SECONDS);
+
+        assertThat(callback.mError).isNotNull();
+        assertThat(callback.mError.getMessage()).isEqualTo(error.getMessage());
+    }
+
+    @Test
+    public void testSelectWalletCard_success() throws Exception {
+        TestQuickAccessWalletService.setExpectedRequestCount(1);
+        QuickAccessWalletClient.create(mContext).selectWalletCard(
+                new SelectWalletCardRequest("card1"));
+        TestQuickAccessWalletService.awaitRequests(3, TimeUnit.SECONDS);
+
+        List<SelectWalletCardRequest> selectRequests =
+                TestQuickAccessWalletService.getSelectRequests();
+
+        assertThat(selectRequests).hasSize(1);
+        assertThat(selectRequests.get(0).getCardId()).isEqualTo("card1");
+    }
+
+    @Test
+    public void testNotifyWalletDismissed_success() throws Exception {
+        assertThat(TestQuickAccessWalletService.isWalletDismissed()).isFalse();
+        TestQuickAccessWalletService.setExpectedRequestCount(1);
+
+        QuickAccessWalletClient.create(mContext).notifyWalletDismissed();
+        TestQuickAccessWalletService.awaitRequests(3, TimeUnit.SECONDS);
+
+        assertThat(TestQuickAccessWalletService.isWalletDismissed()).isTrue();
+    }
+
+    @Test
+    public void testAddListener_sendEvent_success() throws Exception {
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        TestEventListener listener = new TestEventListener();
+        TestQuickAccessWalletService.setExpectedRequestCount(1);
+        client.addWalletServiceEventListener(listener);
+        TestQuickAccessWalletService.awaitRequests(1, TimeUnit.SECONDS);
+
+        TestQuickAccessWalletService.sendEvent(
+                new WalletServiceEvent(WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED));
+        listener.await(300, TimeUnit.SECONDS);
+
+        assertThat(listener.mEvents).hasSize(1);
+    }
+
+    @Test
+    public void testRemoveListener_sendEvent_shouldNotBeDelivered() {
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        TestEventListener listener = new TestEventListener();
+        client.addWalletServiceEventListener(listener);
+        client.removeWalletServiceEventListener(listener);
+
+        TestQuickAccessWalletService.sendEvent(
+                new WalletServiceEvent(WalletServiceEvent.TYPE_NFC_PAYMENT_STARTED));
+        try {
+            listener.await(250, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException ignored) {
+            // It is expected that this time out
+        }
+
+        assertThat(listener.mEvents).hasSize(0);
+    }
+
+    @Test
+    public void testDisconnect_shouldClearListenersAndDisconnect() throws Exception {
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+        TestQuickAccessWalletService.setExpectedBindCount(1);
+        TestQuickAccessWalletService.setExpectedUnbindCount(1);
+
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, new TestCallback());
+
+        TestQuickAccessWalletService.awaitBinding(3, TimeUnit.SECONDS);
+        client.disconnect();
+        TestQuickAccessWalletService.awaitUnbinding(3, TimeUnit.SECONDS);
+    }
+
+    @Test
+    public void testConnect_disconnect_reconnect_shouldWork() throws Exception {
+        QuickAccessWalletClient client = QuickAccessWalletClient.create(mContext);
+
+        TestCallback callback = new TestCallback();
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, callback);
+        callback.await(3, TimeUnit.SECONDS);
+
+        TestQuickAccessWalletService.setExpectedUnbindCount(1);
+        client.disconnect();
+        TestQuickAccessWalletService.awaitUnbinding(3, TimeUnit.SECONDS);
+
+        TestCallback callback2 = new TestCallback();
+        client.getWalletCards(GET_WALLET_CARDS_REQUEST, callback2);
+        callback2.await(3, TimeUnit.SECONDS);
+
+        assertThat(callback.mResponse).isNotNull();
+        assertThat(callback2.mResponse).isNotNull();
+    }
+
+    @Test
+    public void testCreateWalletIntent_parsesXmlAndUsesCorrectIntentAction() {
+        Intent walletIntent = QuickAccessWalletClient.create(mContext).createWalletIntent();
+        assertThat(walletIntent).isNotNull();
+        assertThat(walletIntent.getAction()).isEqualTo(QuickAccessWalletService.ACTION_VIEW_WALLET);
+        ComponentName expectedComponent = ComponentName.createRelative(mContext,
+                QuickAccessWalletActivity.class.getName());
+        assertThat(walletIntent.getComponent()).isEqualTo(expectedComponent);
+    }
+
+    @Test
+    public void testCreateWalletSettingsIntent_parsesXmlAndUsesCorrectIntentAction() {
+        Intent settingsIntent =
+                QuickAccessWalletClient.create(mContext).createWalletSettingsIntent();
+        assertThat(settingsIntent).isNotNull();
+        assertThat(settingsIntent.getAction()).isEqualTo(
+                QuickAccessWalletService.ACTION_VIEW_WALLET_SETTINGS);
+        ComponentName expectedComponent = ComponentName.createRelative(mContext,
+                QuickAccessWalletSettingsActivity.class.getName());
+        assertThat(settingsIntent.getComponent()).isEqualTo(expectedComponent);
+    }
+
+    private void setServiceState(
+            Class<? extends QuickAccessWalletService> cls, int state) {
+        ComponentName componentName = ComponentName.createRelative(mContext, cls.getName());
+        mContext.getPackageManager().setComponentEnabledSetting(
+                componentName, state, PackageManager.DONT_KILL_APP);
+    }
+
+    private Icon createCardImage() {
+        Bitmap bitmap = Bitmap.createBitmap(
+                GET_WALLET_CARDS_REQUEST.getCardWidthPx(),
+                GET_WALLET_CARDS_REQUEST.getCardHeightPx(),
+                Bitmap.Config.ARGB_8888);
+        return Icon.createWithBitmap(bitmap.copy(Bitmap.Config.HARDWARE, false));
+    }
+
+    private PendingIntent createPendingIntent() {
+        Intent intent = new Intent(mContext, QuickAccessWalletActivity.class);
+        return PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_IMMUTABLE);
+    }
+
+    private static class TestCallback implements
+            QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+        private GetWalletCardsResponse mResponse;
+        private GetWalletCardsError mError;
+
+        @Override
+        public void onWalletCardsRetrieved(GetWalletCardsResponse response) {
+            mResponse = response;
+            mLatch.countDown();
+        }
+
+        @Override
+        public void onWalletCardRetrievalError(GetWalletCardsError error) {
+            mError = error;
+            mLatch.countDown();
+        }
+
+        public void await(int time, TimeUnit unit) throws InterruptedException {
+            mLatch.await(time, unit);
+        }
+    }
+
+    private static class TestEventListener implements WalletServiceEventListener {
+
+        private final List<WalletServiceEvent> mEvents = new ArrayList<>();
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+
+
+        @Override
+        public void onWalletServiceEvent(WalletServiceEvent event) {
+            mEvents.add(event);
+            mLatch.countDown();
+        }
+
+        public void await(int time, TimeUnit unit) throws InterruptedException {
+            mLatch.await(time, unit);
+        }
+    }
+}
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/SelectWalletCardRequestTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/SelectWalletCardRequestTest.java
index 3d2674d..8818726 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/SelectWalletCardRequestTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/SelectWalletCardRequestTest.java
@@ -32,7 +32,7 @@
 public class SelectWalletCardRequestTest {
 
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         SelectWalletCardRequest request = new SelectWalletCardRequest("card1");
 
         Parcel p = Parcel.obtain();
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletCardTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletCardTest.java
index dc64af8..7b472bb 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletCardTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletCardTest.java
@@ -29,10 +29,9 @@
 import android.service.quickaccesswallet.WalletCard;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.rule.ActivityTestRule;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import org.junit.Before;
-import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -42,14 +41,11 @@
 @RunWith(AndroidJUnit4.class)
 public class WalletCardTest {
 
-    @Rule
-    public ActivityTestRule<QuickAccessWalletActivity> mActivityRule =
-            new ActivityTestRule<>(QuickAccessWalletActivity.class);
     private Context mContext;
 
     @Before
     public void setup() {
-        mContext = mActivityRule.getActivity().getApplicationContext();
+        mContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
     }
 
     /**
@@ -57,7 +53,7 @@
      * preferences and asserts they can no longer be retrieved.
      */
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         Bitmap bitmap = Bitmap.createBitmap(70, 44, Bitmap.Config.ARGB_8888);
         Intent intent = new Intent(mContext, QuickAccessWalletActivity.class);
         WalletCard card = new WalletCard.Builder(
@@ -82,7 +78,7 @@
     }
 
     @Test
-    public void parcel_noIconOrLabel_toParcel() {
+    public void testParcel_noIconOrLabel_toParcel() {
         Bitmap bitmap = Bitmap.createBitmap(70, 44, Bitmap.Config.ARGB_8888);
         Intent intent = new Intent(mContext, QuickAccessWalletActivity.class);
         WalletCard card = new WalletCard.Builder(
diff --git a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletServiceEventTest.java b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletServiceEventTest.java
index 2693ba8..af638e8 100755
--- a/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletServiceEventTest.java
+++ b/tests/quickaccesswallet/src/android/quickaccesswallet/cts/WalletServiceEventTest.java
@@ -34,7 +34,7 @@
 public class WalletServiceEventTest {
 
     @Test
-    public void parcel_toParcel() {
+    public void testParcel_toParcel() {
         WalletServiceEvent event = new WalletServiceEvent(TYPE_NFC_PAYMENT_STARTED);
 
         Parcel p = Parcel.obtain();
diff --git a/tests/rollback/AndroidManifest.xml b/tests/rollback/AndroidManifest.xml
index 3203f25..ab1ec0f 100644
--- a/tests/rollback/AndroidManifest.xml
+++ b/tests/rollback/AndroidManifest.xml
@@ -18,6 +18,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.cts.rollback" >
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
diff --git a/tests/tests/app.usage/OWNERS b/tests/tests/app.usage/OWNERS
index b4efc68..0c47ac2 100644
--- a/tests/tests/app.usage/OWNERS
+++ b/tests/tests/app.usage/OWNERS
@@ -1,3 +1,5 @@
 # Bug component: 532296
 mwachens@google.com
+varunshah@google.com
+yamasani@google.com
 per-file NetworkUsageStatsTest.java = file:/tests/tests/net/OWNERS
diff --git a/tests/tests/app.usage/TestApp1/AndroidManifest.xml b/tests/tests/app.usage/TestApp1/AndroidManifest.xml
index d4306e5..8d18d86 100644
--- a/tests/tests/app.usage/TestApp1/AndroidManifest.xml
+++ b/tests/tests/app.usage/TestApp1/AndroidManifest.xml
@@ -22,5 +22,8 @@
         <activity android:name=".SomeActivity"
                   android:exported="true"
         />
+        <activity android:name=".SomeActivityWithLocus"
+                  android:exported="true"
+        />
     </application>
 </manifest>
diff --git a/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/SomeActivityWithLocus.java b/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/SomeActivityWithLocus.java
new file mode 100644
index 0000000..f49e0da
--- /dev/null
+++ b/tests/tests/app.usage/TestApp1/src/android/app/usage/cts/test1/SomeActivityWithLocus.java
@@ -0,0 +1,38 @@
+/**
+ * Copyright (C) 2020 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.app.usage.cts.test1;
+
+import android.annotation.Nullable;
+import android.app.Activity;
+import android.content.LocusId;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.WindowManager;
+
+public final class SomeActivityWithLocus extends Activity {
+    @Override
+    protected void onCreate(@Nullable Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        LocusId locus = new LocusId("Locus1");
+        setLocusContext(locus, null);
+    }
+
+    @Override
+    protected void onStart() {
+        setLocusContext(new LocusId("Locus11"), null);
+    }
+}
diff --git a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
index 4dc64a4..b228c49 100644
--- a/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
+++ b/tests/tests/app.usage/src/android/app/usage/cts/UsageStatsTest.java
@@ -58,6 +58,7 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.compatibility.common.util.AppStandbyUtils;
+import com.android.compatibility.common.util.BatteryUtils;
 import com.android.compatibility.common.util.SystemUtil;
 
 import org.junit.After;
@@ -74,6 +75,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
+import java.util.function.BooleanSupplier;
 
 /**
  * Test the UsageStats API. It is difficult to test the entire surface area
@@ -108,6 +110,8 @@
 
     private static final String TEST_APP_PKG = "android.app.usage.cts.test1";
     private static final String TEST_APP_CLASS = "android.app.usage.cts.test1.SomeActivity";
+    private static final String TEST_APP_CLASS_LOCUS
+            = "android.app.usage.cts.test1.SomeActivityWithLocus";
 
     private static final long TIMEOUT = TimeUnit.SECONDS.toMillis(5);
     private static final long MINUTE = TimeUnit.MINUTES.toMillis(1);
@@ -533,11 +537,31 @@
         assertTrue(stats.isEmpty());
     }
 
+    private void generateAndSendNotification(Context context) throws Exception {
+        final NotificationManager mNotificationManager =
+                (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
+        final NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, "Channel",
+                NotificationManager.IMPORTANCE_DEFAULT);
+        // Configure the notification channel.
+        mChannel.setDescription("Test channel");
+        mNotificationManager.createNotificationChannel(mChannel);
+        final Notification.Builder mBuilder =
+                new Notification.Builder(context, CHANNEL_ID)
+                        .setSmallIcon(R.drawable.ic_notification)
+                        .setContentTitle("My notification")
+                        .setContentText("Hello World!");
+        final PendingIntent pi = PendingIntent.getActivity(context, 1,
+                new Intent(Settings.ACTION_SETTINGS), 0);
+        mBuilder.setContentIntent(pi);
+        mNotificationManager.notify(1, mBuilder.build());
+        Thread.sleep(500);
+    }
+
     @AppModeFull(reason = "No usage events access in instant apps")
     @Test
     public void testNotificationSeen() throws Exception {
         final long startTime = System.currentTimeMillis();
-        Context context = InstrumentationRegistry.getContext();
+        final Context context = InstrumentationRegistry.getContext();
 
         // Skip the test for wearable devices and televisions; neither has a notification shade.
         assumeFalse("Test cannot run on a watch- notification shade is not shown",
@@ -545,26 +569,10 @@
         assumeFalse("Test cannot run on a television- notifications are not shown",
                 context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY));
 
-        NotificationManager mNotificationManager =
-            (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
-        int importance = NotificationManager.IMPORTANCE_DEFAULT;
-        NotificationChannel mChannel = new NotificationChannel(CHANNEL_ID, "Channel",
-            importance);
-        // Configure the notification channel.
-        mChannel.setDescription("Test channel");
-        mNotificationManager.createNotificationChannel(mChannel);
-        Notification.Builder mBuilder =
-                new Notification.Builder(context, CHANNEL_ID)
-                    .setSmallIcon(R.drawable.ic_notification)
-                    .setContentTitle("My notification")
-                    .setContentText("Hello World!");
-        PendingIntent pi = PendingIntent.getActivity(context, 1,
-                new Intent(Settings.ACTION_SETTINGS), 0);
-        mBuilder.setContentIntent(pi);
-        mNotificationManager.notify(1, mBuilder.build());
-        Thread.sleep(500);
+        generateAndSendNotification(context);
+
         long endTime = System.currentTimeMillis();
-        UsageEvents events = mUsageStatsManager.queryEvents(startTime, endTime);
+        UsageEvents events = queryEventsAsShell(startTime, endTime);
         boolean found = false;
         Event event = new Event();
         while (events.hasNextEvent()) {
@@ -580,7 +588,7 @@
         for (int i = 0; i < 5; i++) {
             Thread.sleep(500);
             endTime = System.currentTimeMillis();
-            events = mUsageStatsManager.queryEvents(startTime, endTime);
+            events = queryEventsAsShell(startTime, endTime);
             found = false;
             while (events.hasNextEvent()) {
                 events.getNextEvent(event);
@@ -596,6 +604,47 @@
 
     @AppModeFull(reason = "No usage events access in instant apps")
     @Test
+    public void testNotificationInterruptionEventsObfuscation() throws Exception {
+        final long startTime = System.currentTimeMillis();
+        final Context context = InstrumentationRegistry.getContext();
+
+        // Skip the test for wearable devices and televisions; neither has a notification shade.
+        assumeFalse("Test cannot run on a watch- notification shade is not shown",
+                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH));
+        assumeFalse("Test cannot run on a television- notifications are not shown",
+                context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK_ONLY));
+
+        generateAndSendNotification(context);
+        final long endTime = System.currentTimeMillis();
+
+        final UsageEvents obfuscatedEvents = mUsageStatsManager.queryEvents(startTime, endTime);
+        final UsageEvents unobfuscatedEvents = queryEventsAsShell(startTime, endTime);
+        verifyNotificationInterruptionEvent(obfuscatedEvents, true);
+        verifyNotificationInterruptionEvent(unobfuscatedEvents, false);
+    }
+
+    private void verifyNotificationInterruptionEvent(UsageEvents events, boolean obfuscated) {
+        boolean found = false;
+        Event event = new Event();
+        while (events.hasNextEvent()) {
+            events.getNextEvent(event);
+            if (event.getEventType() == Event.NOTIFICATION_INTERRUPTION) {
+                found = true;
+                break;
+            }
+        }
+        assertTrue(found);
+        if (obfuscated) {
+            assertEquals("Notification channel id was not obfuscated.",
+                    UsageEvents.OBFUSCATED_NOTIFICATION_CHANNEL_ID, event.mNotificationChannelId);
+        } else {
+            assertEquals("Failed to verify notification channel id.",
+                    CHANNEL_ID, event.mNotificationChannelId);
+        }
+    }
+
+    @AppModeFull(reason = "No usage events access in instant apps")
+    @Test
     public void testUserUnlockedEventExists() throws Exception {
         final UsageEvents events = mUsageStatsManager.queryEvents(0, System.currentTimeMillis());
         while (events.hasNextEvent()) {
@@ -640,6 +689,24 @@
                 mUsageStatsManager.getAppStandbyBucket(mTargetPackage));
     }
 
+    @Test
+    public void testIsAppInactive_Charging() throws Exception {
+        mUiDevice.executeShellCommand("am set-standby-bucket " + TEST_APP_PKG + " rare");
+
+        try {
+            BatteryUtils.runDumpsysBatteryUnplug();
+            // Plug/unplug change takes a while to propagate inside the system.
+            waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), true);
+
+            BatteryUtils.runDumpsysBatterySetPluggedIn(true);
+            BatteryUtils.runDumpsysBatterySetLevel(100);
+            // Plug/unplug change takes a while to propagate inside the system.
+            waitUntil(() -> mUsageStatsManager.isAppInactive(TEST_APP_PKG), false);
+        } finally {
+            BatteryUtils.runDumpsysBatteryReset();
+        }
+    }
+
     static final int[] INTERACTIVE_EVENTS = new int[] {
             Event.SCREEN_INTERACTIVE,
             Event.SCREEN_NON_INTERACTIVE
@@ -708,6 +775,18 @@
         return events;
     }
 
+    private void waitUntil(BooleanSupplier condition, boolean expected) throws Exception {
+        final long sleepTimeMs = 500;
+        final int count = 10;
+        for (int i = 0; i < count; ++i) {
+            if (condition.getAsBoolean() == expected) {
+                return;
+            }
+            Thread.sleep(sleepTimeMs);
+        }
+        fail("Condition wasn't satisfied after " + (sleepTimeMs * count) + "ms");
+    }
+
     static class AggrEventData {
         final String label;
         int count;
@@ -1259,6 +1338,55 @@
         assertEquals("Unexpected number of activity stops", 1, stops);
     }
 
+    @AppModeFull(reason = "No usage events access in instant apps")
+    @Test
+    public void testLocusIdEventsVisibility() throws Exception {
+        final long startTime = System.currentTimeMillis();
+        startAndDestroyActivityWithLocus();
+        final long endTime = System.currentTimeMillis();
+
+        final UsageEvents restrictedEvents = mUsageStatsManager.queryEvents(startTime, endTime);
+        final UsageEvents allEvents = queryEventsAsShell(startTime, endTime);
+        verifyLocusIdEventVisibility(restrictedEvents, false);
+        verifyLocusIdEventVisibility(allEvents, true);
+    }
+
+    private void startAndDestroyActivityWithLocus() {
+        final Context context = InstrumentationRegistry.getInstrumentation().getContext();
+        final ActivityManager mAm = context.getSystemService(ActivityManager.class);
+
+        Intent intent = new Intent();
+        intent.setClassName(TEST_APP_PKG, TEST_APP_CLASS_LOCUS);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        context.startActivity(intent);
+        mUiDevice.wait(Until.hasObject(By.clazz(TEST_APP_PKG, TEST_APP_CLASS_LOCUS)), TIMEOUT);
+        SystemClock.sleep(500);
+
+        // Destroy the activity
+        SystemUtil.runWithShellPermissionIdentity(() -> mAm.forceStopPackage(TEST_APP_PKG));
+        mUiDevice.wait(Until.gone(By.clazz(TEST_APP_PKG, TEST_APP_CLASS_LOCUS)), TIMEOUT);
+        SystemClock.sleep(500);
+    }
+
+    private void verifyLocusIdEventVisibility(UsageEvents events, boolean hasPermission) {
+        int locuses = 0;
+        while (events.hasNextEvent()) {
+            final Event event = new UsageEvents.Event();
+            assertTrue(events.getNextEvent(event));
+
+            if (TEST_APP_PKG.equals(event.getPackageName())
+                    && event.mEventType == Event.LOCUS_ID_SET) {
+                locuses++;
+            }
+        }
+
+        if (hasPermission) {
+            assertEquals("LOCUS_ID_SET events were not visible.", 2, locuses);
+        } else {
+            assertEquals("LOCUS_ID_SET events were visible.", 0, locuses);
+        }
+    }
+
     private void pressWakeUp() {
         mUiDevice.pressKeyCode(KeyEvent.KEYCODE_WAKEUP);
     }
@@ -1292,4 +1420,9 @@
                     + activeUsages, found);
         }
     }
+
+    private UsageEvents queryEventsAsShell(long start, long end) {
+        return SystemUtil.runWithShellPermissionIdentity(() ->
+                mUsageStatsManager.queryEvents(start, end));
+    }
 }
diff --git a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
index 81149f0..0a4974d 100644
--- a/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
+++ b/tests/tests/appenumeration/src/android/appenumeration/cts/AppEnumerationTests.java
@@ -122,7 +122,7 @@
                                 + "package_query_filtering_enabled")
                         .trim();
         if ("null".equalsIgnoreCase(deviceConfigResponse) || deviceConfigResponse.isEmpty()) {
-            sGlobalFeatureEnabled = false;
+            sGlobalFeatureEnabled = true;
         } else {
             sGlobalFeatureEnabled = Boolean.parseBoolean(deviceConfigResponse);
         }
diff --git a/tests/tests/appop/AndroidManifest.xml b/tests/tests/appop/AndroidManifest.xml
index ffee886..ab36586 100644
--- a/tests/tests/appop/AndroidManifest.xml
+++ b/tests/tests/appop/AndroidManifest.xml
@@ -41,6 +41,8 @@
 
   <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
 
+  <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
+
   <application>
       <uses-library android:name="android.test.runner"/>
       <activity android:name=".UidStateForceActivity" />
diff --git a/tests/tests/appop/AndroidTest.xml b/tests/tests/appop/AndroidTest.xml
index 6e08309..a911b20 100644
--- a/tests/tests/appop/AndroidTest.xml
+++ b/tests/tests/appop/AndroidTest.xml
@@ -36,6 +36,7 @@
     <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer" >
         <option name="push-file" key="CtsAppToBlame1.apk" value="/data/local/tmp/cts/appops/CtsAppToBlame1.apk" />
         <option name="push-file" key="CtsAppToBlame2.apk" value="/data/local/tmp/cts/appops/CtsAppToBlame2.apk" />
+        <option name="push-file" key="CtsAppToCollect.apk" value="/data/local/tmp/cts/appops/CtsAppToCollect.apk" />
         <option name="push-file" key="AppWithDuplicateFeature.apk" value="/data/local/tmp/cts/appops/AppWithDuplicateFeature.apk" />
         <option name="push-file" key="AppWithFeatureInheritingFromExisting.apk" value="/data/local/tmp/cts/appops/AppWithFeatureInheritingFromExisting.apk" />
         <option name="push-file" key="AppWithFeatureInheritingFromSameAsOther.apk" value="/data/local/tmp/cts/appops/AppWithFeatureInheritingFromSameAsOther.apk" />
diff --git a/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml b/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
index 20e61f6..e3e4937 100644
--- a/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
+++ b/tests/tests/appop/AppThatUsesAppOps/AndroidManifest.xml
@@ -22,6 +22,9 @@
 
   <application>
       <service android:name=".AppOpsUserService" android:exported="true" />
+      <activity android:name=".AutoClosingActivity"
+          android:exported="true"
+          android:permission="android.permission.ACCESS_FINE_LOCATION" />
   </application>
 
 </manifest>
diff --git a/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AutoClosingActivity.kt b/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AutoClosingActivity.kt
new file mode 100644
index 0000000..222059f
--- /dev/null
+++ b/tests/tests/appop/AppThatUsesAppOps/src/android/app/appops/cts/appthatusesappops/AutoClosingActivity.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2020 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.app.appops.cts.appthatusesappops
+
+import android.app.Activity
+import android.os.Bundle
+
+class AutoClosingActivity : Activity() {
+    override fun onCreate(savedInstanceState: Bundle?) {
+        finish()
+    }
+}
diff --git a/tests/tests/appop/AppToCollect/Android.bp b/tests/tests/appop/AppToCollect/Android.bp
new file mode 100644
index 0000000..1e90444
--- /dev/null
+++ b/tests/tests/appop/AppToCollect/Android.bp
@@ -0,0 +1,23 @@
+// Copyright (C) 2020 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.
+
+android_test_helper_app {
+    name: "CtsAppToCollect",
+
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ]
+}
\ No newline at end of file
diff --git a/tests/tests/appop/AppToCollect/AndroidManifest.xml b/tests/tests/appop/AppToCollect/AndroidManifest.xml
new file mode 100644
index 0000000..e67cb57
--- /dev/null
+++ b/tests/tests/appop/AppToCollect/AndroidManifest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.app.appops.cts.apptocollect"
+    android:version="1">
+  <feature android:featureId="testFeature" android:label="@string/dummyLabel" />
+
+  <uses-permission android:name="android.permission.READ_CONTACTS"></uses-permission>
+
+  <application />
+
+</manifest>
diff --git a/tests/tests/appop/AppToCollect/res/values/strings.xml b/tests/tests/appop/AppToCollect/res/values/strings.xml
new file mode 100644
index 0000000..ab27f6a
--- /dev/null
+++ b/tests/tests/appop/AppToCollect/res/values/strings.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="dummyLabel">A feature</string>
+</resources>
diff --git a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
index e3141b4..7b94625 100644
--- a/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/AppOpsLoggingTest.kt
@@ -40,6 +40,7 @@
 import android.content.Context
 import android.content.Context.BIND_AUTO_CREATE
 import android.content.Intent
+import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
 import android.content.IntentFilter
 import android.content.ServiceConnection
 import android.content.pm.PackageManager.FEATURE_BLUETOOTH
@@ -664,6 +665,21 @@
         assertThat(noted[0].second.map { it.methodName }).contains("isInCall")
     }
 
+    /**
+     * Realistic end-to-end test for starting a permission protected activity
+     */
+    @Test
+    fun startActivity() {
+        context.createFeatureContext(TEST_FEATURE_ID).startActivity(
+                Intent().setComponent(ComponentName(TEST_SERVICE_PKG,
+                        TEST_SERVICE_PKG + ".AutoClosingActivity"))
+                        .setFlags(FLAG_ACTIVITY_NEW_TASK))
+
+        assertThat(noted[0].first.op).isEqualTo(OPSTR_FINE_LOCATION)
+        assertThat(noted[0].first.featureId).isEqualTo(TEST_FEATURE_ID)
+        assertThat(noted[0].second.map { it.methodName }).contains("startActivity")
+    }
+
     @After
     fun removeNotedAppOpsCollector() {
         appOpsManager.setNotedAppOpsCollector(null)
diff --git a/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt b/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt
index 9aa2209..d199055 100644
--- a/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/FeatureTest.kt
@@ -47,7 +47,7 @@
     private val appUid by lazy { context.packageManager.getPackageUid(APP_PKG, 0) }
 
     private fun installApk(apk: String) {
-        val result = runCommand("pm install -r $APK_PATH$apk")
+        val result = runCommand("pm install -r --force-queryable $APK_PATH$apk")
         assertThat(result.trim()).isEqualTo("Success")
     }
 
diff --git a/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt b/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt
index 008fef8..257b6ad 100644
--- a/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt
+++ b/tests/tests/appop/src/android/app/appops/cts/ForegroundModeTest.kt
@@ -33,6 +33,7 @@
 import android.content.Intent.FLAG_ACTIVITY_NEW_TASK
 import android.content.ServiceConnection
 import android.os.IBinder
+import android.platform.test.annotations.AppModeFull
 import android.provider.Settings
 import android.provider.Settings.Global.APP_OPS_CONSTANTS
 import android.support.test.uiautomator.UiDevice
@@ -50,6 +51,7 @@
 private const val TEST_SERVICE_PKG = "android.app.appops.cts.appthatcanbeforcedintoforegroundstates"
 private const val TIMEOUT_MILLIS = 45000L
 
+@AppModeFull(reason = "This test connects to other test app")
 class ForegroundModeTest {
     private var previousAppOpsConstants: String? = null
 
diff --git a/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
new file mode 100644
index 0000000..e6730c1
--- /dev/null
+++ b/tests/tests/appop/src/android/app/appops/cts/RuntimeMessageCollectionTest.kt
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 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.app.appops.cts
+
+import org.junit.Assert.fail
+import android.app.AppOpsManager
+import android.platform.test.annotations.AppModeFull
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.internal.util.FrameworkStatsLog.RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import java.lang.Thread.sleep
+
+private const val APK_PATH = "/data/local/tmp/cts/appops/"
+
+private const val APP_PKG = "android.app.appops.cts.apptocollect"
+private const val MESSAGE = "Stack trace message"
+
+@AppModeFull(reason = "Test relies on seeing other apps. Instant apps can't see other apps")
+class RuntimeMessageCollectionTest {
+    private val TIMEOUT_MILLIS = 15000L
+    private val instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val context = instrumentation.targetContext
+    private val appOpsManager = context.getSystemService(AppOpsManager::class.java)
+    private var appUid = -1
+
+    private fun installApk(apk: String) {
+        val result = runCommand("pm install -r -g --force-queryable $APK_PATH$apk")
+        assertThat(result.trim()).isEqualTo("Success")
+        appUid = context.packageManager.getPackageUid(APP_PKG, 0)
+    }
+
+    @Before
+    fun resetTestApp() {
+        runCommand("pm uninstall $APP_PKG")
+        installApk("CtsAppToCollect.apk")
+    }
+
+    @Test
+    fun collectAsyncStackTrace() {
+        for (attempt in 0..20) {
+            installApk("CtsAppToCollect.apk")
+            val start = System.currentTimeMillis()
+            runWithShellPermissionIdentity {
+                appOpsManager.noteOp(AppOpsManager.OPSTR_READ_CONTACTS, appUid, APP_PKG,
+                        TEST_FEATURE_ID, MESSAGE)
+            }
+            while (System.currentTimeMillis() - start < TIMEOUT_MILLIS) {
+                sleep(200)
+
+                runWithShellPermissionIdentity {
+                    val message = appOpsManager.collectRuntimeAppOpAccessMessage()
+                    if (message != null && message.packageName.equals(APP_PKG)) {
+                        assertThat(message.op).isEqualTo(AppOpsManager.OPSTR_READ_CONTACTS)
+                        assertThat(message.uid).isEqualTo(appUid)
+                        assertThat(message.featureId).isEqualTo(TEST_FEATURE_ID)
+                        assertThat(message.message).isEqualTo(MESSAGE)
+                        assertThat(message.samplingStrategy)
+                                .isEqualTo(RUNTIME_APP_OP_ACCESS__SAMPLING_STRATEGY__RARELY_USED)
+                        return
+                    }
+                }
+            }
+        }
+        fail("App Op use message was not collected")
+    }
+}
diff --git a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
index 7437e90..cee0944 100644
--- a/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
+++ b/tests/tests/binder_ndk/libbinder_ndk_test/test_native_aidl_client.cpp
@@ -831,7 +831,7 @@
   //
   // Warning: for testing purposes only. This parcels things within the same process for testing
   // purposes. In normal usage, this should just return SharedRefBase::make<MyTest> directly.
-  return (new BpTest(binder))->ref<ITest>();
+  return SharedRefBase::make<BpTest>(binder);
 }
 
 std::shared_ptr<ITest> getNdkBinderTestJavaService(const std::string& method) {
diff --git a/tests/tests/car/Android.bp b/tests/tests/car/Android.bp
index 6d71db9..28b6431 100644
--- a/tests/tests/car/Android.bp
+++ b/tests/tests/car/Android.bp
@@ -21,6 +21,9 @@
         "truth-prebuilt",
         "ctstestrunner-axt",
         "android.test.base.stubs",
+        // TODO: remove once Android migrates to JUnit 4.12,
+        // which provides assertThrows
+        "testng",
     ],
     libs: [
         "android.car-test-stubs",
diff --git a/tests/tests/car/AndroidManifest.xml b/tests/tests/car/AndroidManifest.xml
index 1ec8475..d146b32 100644
--- a/tests/tests/car/AndroidManifest.xml
+++ b/tests/tests/car/AndroidManifest.xml
@@ -27,6 +27,9 @@
     <uses-permission android:name="android.car.permission.CAR_ENERGY_PORTS" />
     <uses-permission android:name="android.permission.BLUETOOTH" />
     <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name=".drivingstate.DistractionOptimizedActivity">
diff --git a/tests/tests/car/src/android/car/cts/CarApiTestBase.java b/tests/tests/car/src/android/car/cts/CarApiTestBase.java
index 71db227..445593b 100644
--- a/tests/tests/car/src/android/car/cts/CarApiTestBase.java
+++ b/tests/tests/car/src/android/car/cts/CarApiTestBase.java
@@ -26,7 +26,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 
-import androidx.test.InstrumentationRegistry;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.compatibility.common.util.FeatureUtil;
 
@@ -43,6 +43,9 @@
     private final DefaultServiceConnectionListener mConnectionListener =
             new DefaultServiceConnectionListener();
 
+    protected static final Context sContext = InstrumentationRegistry.getInstrumentation()
+            .getContext();
+
     protected void assertMainThread() {
         assertTrue(Looper.getMainLooper().isCurrentThread());
     }
@@ -50,9 +53,7 @@
     protected void setUp() throws Exception {
         assumeTrue(FeatureUtil.isAutomotive());
 
-        Context context =
-                InstrumentationRegistry.getInstrumentation().getTargetContext();
-        mCar = Car.createCar(context, mConnectionListener, null);
+        mCar = Car.createCar(sContext, mConnectionListener, null);
         mCar.connect();
         mConnectionListener.waitForConnection(DEFAULT_WAIT_TIMEOUT_MS);
     }
diff --git a/tests/tests/car/src/android/car/cts/CarUserManagerTest.java b/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
new file mode 100644
index 0000000..622fa28
--- /dev/null
+++ b/tests/tests/car/src/android/car/cts/CarUserManagerTest.java
@@ -0,0 +1,291 @@
+/*
+ * Copyright (C) 2020 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.car.cts;
+
+import static android.os.Process.myUid;
+
+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeMethodWithShellPermissions;
+import static com.android.compatibility.common.util.ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn;
+import static com.android.compatibility.common.util.ShellUtils.runShellCommand;
+
+import static com.google.common.truth.Truth.assertWithMessage;
+
+import static org.junit.Assert.fail;
+
+import static org.testng.Assert.assertThrows;
+
+import android.app.ActivityManager;
+import android.app.UiAutomation;
+import android.car.Car;
+import android.car.user.CarUserManager;
+import android.car.user.CarUserManager.UserLifecycleListener;
+import android.content.pm.PackageManager;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.util.Log;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.After;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.Executor;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicReference;
+
+public final class CarUserManagerTest extends CarApiTestBase {
+
+    private static final String TAG = CarUserManagerTest.class.getSimpleName();
+
+    /**
+     * Constant used to wait for a condition that is triggered by checking a condition.
+     */
+    private static final int SWITCH_TIMEOUT_USING_CHECK_MS = 30_000;
+
+    /**
+     * Constant used to wait blindly, when there is no condition that can be checked.
+     */
+    private static final int SWITCH_TIMEOUT_WITHOUT_CHECK_MS = 10_000;
+
+    /**
+     * How long to sleep (multiple times) while waiting for a condition.
+     */
+    private static final int SMALL_NAP_MS = 500;
+
+    private static CarUserManager sCarUserManager;
+
+    private static int sInitialUserId = UserHandle.myUserId();
+    private static int sNewUserId = UserHandle.USER_NULL;
+
+    private final Executor mNoOpExecutor = (r) -> {};
+    private final UserLifecycleListener mNoOpListener = (e) -> {};
+
+    @Override
+    @Before
+    public void setUp() throws Exception {
+        super.setUp();
+
+        // TODO: ideally it should be created on @BeforeClass, but it relies on getCar()
+        if (sNewUserId != UserHandle.USER_NULL) {
+            Log.d(TAG, "setUp(): already set static stuff");
+            return;
+        }
+
+        sCarUserManager = (CarUserManager) getCar().getCarManager(Car.CAR_USER_SERVICE);
+        sNewUserId = createNewUser("CarUserManagerTest");
+        Log.i(TAG, "setUp(): myUid=" + myUid() + ", currentUser=" + sInitialUserId
+                + ", newUser=" + sNewUserId);
+    }
+
+    @AfterClass
+    public static void resetUsers() {
+        switchUser(sInitialUserId);
+        if (sNewUserId != UserHandle.USER_NULL) {
+            removeUser(sNewUserId);
+        }
+    }
+
+    @Test
+    public void testAddListener_noPermission() throws Exception {
+        toggleInteractAcrossUsersPermission(false);
+        try {
+            assertThrows(SecurityException.class,
+                    () -> sCarUserManager.addListener(mNoOpExecutor, mNoOpListener));
+        } finally {
+            toggleInteractAcrossUsersPermission(true);
+        }
+    }
+
+    @Test
+    public void testRemoveListener_noPermission() throws Exception {
+        toggleInteractAcrossUsersPermission(false);
+        try {
+            assertThrows(SecurityException.class,
+                    ()-> sCarUserManager.removeListener(mNoOpListener));
+        } finally {
+            toggleInteractAcrossUsersPermission(true);
+        }
+    }
+
+    // TODO(b/144120654): tag with @CddTest
+    @Test
+    public void testLifecycleListener() throws Exception {
+        // TODO(b/144120654): listen to other event types
+
+        int oldUserId = sInitialUserId;
+        int newUserId = sNewUserId;
+
+        // TODO: move listener to its own class (if it becomes too hard to read)
+        CountDownLatch latch = new CountDownLatch(1);
+        AtomicReference<Exception> bgExceptionRef = new AtomicReference<>();
+        AtomicBoolean expectingEventRef = new AtomicBoolean(true);
+
+        UserLifecycleListener listener = (event) -> {
+            boolean expectingEvent = expectingEventRef.get();
+            Log.d(TAG, "received event (expecting=" + expectingEvent + "): "  + event);
+            latch.countDown();
+            if (!expectingEvent) {
+                bgExceptionRef.set(new IllegalStateException("Received event when it shouldn't: "
+                        + event));
+                return;
+            }
+            // Verify event
+            List<String> errors = new ArrayList<>();
+            int actualType = event.getEventType();
+            if (actualType != CarUserManager.USER_LIFECYCLE_EVENT_TYPE_SWITCHING) {
+                errors.add("wrong event; expected SWITCHING, got "
+                        + CarUserManager.lifecycleEventTypeToString(actualType));
+            }
+            UserHandle actualUserHandle = event.getUserHandle();
+            if (actualUserHandle == null) {
+                errors.add("no user handle");
+            } else if (actualUserHandle.getIdentifier() != newUserId) {
+                errors.add("wrong user: expected " + newUserId + ", got " + actualUserHandle);
+            }
+
+            // TODO(b/144120654): check for previous handle (not set yet)
+            if (false) {
+                UserHandle previousUserHandle = event.getPreviousUserHandle();
+                if (previousUserHandle == null) {
+                    errors.add("no previous user handle");
+                } else if (previousUserHandle.getIdentifier() != oldUserId) {
+                    errors.add("wrong previous user: expected " + oldUserId + ", got "
+                            + previousUserHandle);
+                }
+            }
+
+            if (!errors.isEmpty()) {
+                bgExceptionRef.set(new IllegalArgumentException(
+                        "Received wrong event (" + event + "): " + errors));
+            }
+        };
+        Log.d(TAG, "registering listener: " + listener);
+
+
+        AtomicBoolean executedRef = new AtomicBoolean();
+        sCarUserManager.addListener((r) -> {
+            executedRef.set(true);
+            r.run();
+        }, listener);
+
+        // Switch while listener is registered
+        switchUser(newUserId);
+        if (!latch.await(SWITCH_TIMEOUT_USING_CHECK_MS, TimeUnit.MILLISECONDS)) {
+            fail("listener not called in " + SWITCH_TIMEOUT_USING_CHECK_MS + "ms");
+        }
+
+        // Make sure it was executed in the proper threaqd
+        assertWithMessage("not executed on executor").that(executedRef.get()).isTrue();
+
+         // Then switch back when it isn't
+        // TODO(b/144120654): the current mechanism is not thread safe because if an event is
+        // received before this line, it wouldn't be detected. But that's fine for now, as this test
+        // will be refactored once it's expecting more events (like STARTING before SWITCHING)
+        expectingEventRef.set(false);
+
+        Log.d(TAG, "unregistering listener: " + listener);
+        sCarUserManager.removeListener(listener);
+        switchUser(oldUserId);
+        // Wait until it's switched...
+        waitForCurrentUser(oldUserId, SWITCH_TIMEOUT_USING_CHECK_MS);
+        // .. then a little bit longer to make sure the callback was not called
+        SystemClock.sleep(SWITCH_TIMEOUT_WITHOUT_CHECK_MS);
+
+        Exception bgException = bgExceptionRef.get();
+        if (bgException != null) {
+            throw bgException;
+        }
+    }
+
+    /**
+     * Used to temporarily revoke the permission.
+     */
+    private void toggleInteractAcrossUsersPermission(boolean enabled) {
+        String permission = "android.permission.INTERACT_ACROSS_USERS";
+        String pkgName = sContext.getPackageName();
+        UiAutomation automan = InstrumentationRegistry.getInstrumentation().getUiAutomation();
+        if (enabled) {
+            Log.d(TAG,"re-enabling " + permission + " to " + pkgName);
+            invokeMethodWithShellPermissionsNoReturn(automan, (a) -> a
+                    .grantRuntimePermission(pkgName, permission));
+        } else {
+            Log.d(TAG,"temporarily disabing " + permission + " for " + pkgName);
+            invokeMethodWithShellPermissionsNoReturn(automan, (a) -> a
+                    .revokeRuntimePermission(pkgName, permission));
+        }
+    }
+
+    /**
+     * Creates a new Android user.
+     */
+    private int createNewUser(String name) {
+        Log.i(TAG, "Creating new user " + name);
+        int newUserId = invokeMethodWithShellPermissions(sCarUserManager,
+                (um) -> um.createUser(name));
+        Log.i(TAG, "New user created with id " + newUserId);
+        return newUserId;
+    }
+
+    /**
+     * Removes an Android user.
+     */
+    private static void removeUser(int userId) {
+        Log.i(TAG, "Removing user " + userId);
+        invokeMethodWithShellPermissionsNoReturn(sCarUserManager, (um) -> um.removeUser(userId));
+    }
+
+    /**
+     * Switches to the given Android user.
+     */
+    private static void switchUser(int userId) {
+        Log.i(TAG, "Switching to user " + userId);
+        ActivityManager activityManager = sContext.getSystemService(ActivityManager.class);
+        boolean success = invokeMethodWithShellPermissions(activityManager,
+                (am) -> am.switchUser(UserHandle.of(userId)));
+        if (!success) {
+            fail("Could not switch to user " + userId + " using ActivityManager");
+        }
+    }
+
+    /**
+     * Waits until the current Android user is {@code userId}, or fail if it times out.
+     */
+    private static void waitForCurrentUser(int userId, long timeoutMs) {
+        Log.i(TAG, "Waiting until current user is " + userId);
+        long deadline = System.currentTimeMillis() + timeoutMs;
+        do {
+            int actualUserId = getCurrentUser();
+            if (actualUserId == userId) {
+                Log.d(TAG, "the wait is over!");
+                return;
+            }
+            Log.d(TAG, "still on " + actualUserId + "; sleeping " + SMALL_NAP_MS + "ms");
+            SystemClock.sleep(SMALL_NAP_MS);
+        } while (System.currentTimeMillis() < deadline);
+        fail("didn't switch to user " + userId + " in " + timeoutMs + " ms");
+    }
+
+    private static int getCurrentUser() {
+        // TODO: should use Activity.getCurrentUser(), but that's a @SystemApi (not @TestApi)
+        return Integer.parseInt(runShellCommand("am get-current-user"));
+    }
+}
diff --git a/tests/tests/content/Android.bp b/tests/tests/content/Android.bp
index a83c62a..fa04cba 100644
--- a/tests/tests/content/Android.bp
+++ b/tests/tests/content/Android.bp
@@ -64,6 +64,12 @@
         "src/**/*.java",
         "BinderPermissionTestService/**/I*.aidl",
     ],
+    data: [
+        // v4 signed version of android.appsecurity.cts.tinyapp
+        // TODO(b/149354175): use built APKs instead - after soong gets v4 support
+        "data/v4-only-original.apk",
+        "data/v4-only-original.apk.idsig",
+    ],
     platform_apis: true,
     // Tag this module as a cts test artifact
     test_suites: [
diff --git a/tests/tests/content/AndroidTest.xml b/tests/tests/content/AndroidTest.xml
index 0aba510..67cf9c2 100644
--- a/tests/tests/content/AndroidTest.xml
+++ b/tests/tests/content/AndroidTest.xml
@@ -51,6 +51,8 @@
         <option name="push-file" key="HelloWorld7_xhdpi-v4.apk" value="/data/local/tmp/cts/content/HelloWorld7_xhdpi-v4.apk" />
         <option name="push-file" key="HelloWorld7_xxhdpi-v4.apk" value="/data/local/tmp/cts/content/HelloWorld7_xxhdpi-v4.apk" />
         <option name="push-file" key="HelloWorld7_xxxhdpi-v4.apk" value="/data/local/tmp/cts/content/HelloWorld7_xxxhdpi-v4.apk" />
+        <option name="push-file" key="v4-only-original.apk" value="/data/local/tmp/cts/content/v4-only-original.apk" />
+        <option name="push-file" key="v4-only-original.apk.idsig" value="/data/local/tmp/cts/content/v4-only-original.apk.idsig" />
     </target_preparer>
 
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
diff --git a/tests/tests/content/HelloWorldApp/Android.bp b/tests/tests/content/HelloWorldApp/Android.bp
index d2f0a34..9ee96f5 100644
--- a/tests/tests/content/HelloWorldApp/Android.bp
+++ b/tests/tests/content/HelloWorldApp/Android.bp
@@ -31,30 +31,28 @@
     ],
 }
 
-// TODO(b/140795853): once fixed, uncomment the below targets.
+//-----------------------------------------------------------
+android_test {
+    name: "HelloWorld5",
+    defaults: ["hello_world_defaults"],
+    srcs: ["src5/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
 
 //-----------------------------------------------------------
-//android_test {
-//    name: "HelloWorld5",
-//    defaults: ["hello_world_defaults"],
-//    srcs: ["src5/**/*.java"],
-//    // tag this module as a cts test artifact
-//    test_suites: [
-//        "cts",
-//        "vts",
-//        "general-tests",
-//    ],
-//}
-
-//-----------------------------------------------------------
-//android_test {
-//    name: "HelloWorld7",
-//    defaults: ["hello_world_defaults"],
-//    srcs: ["src7/**/*.java"],
-//    // tag this module as a cts test artifact
-//    test_suites: [
-//        "cts",
-//        "vts",
-//        "general-tests",
-//    ],
-//}
+android_test {
+    name: "HelloWorld7",
+    defaults: ["hello_world_defaults"],
+    srcs: ["src7/**/*.java"],
+    // tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+}
diff --git a/tests/tests/content/HelloWorldApp/Android.mk b/tests/tests/content/HelloWorldApp/Android.mk
deleted file mode 100644
index ed7739b..0000000
--- a/tests/tests/content/HelloWorldApp/Android.mk
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) 2019 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-# TODO(b/140795853): Once fixed, remove make files.
-
-LOCAL_PATH := $(call my-dir)
-
-#################################################
-# HelloWorld5
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src5)
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-LOCAL_PACKAGE_NAME := HelloWorld5
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 24
-LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 xxxhdpi-v4
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_ASSET_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs androidx.appcompat_appcompat androidx-constraintlayout_constraintlayout com.google.android.material_material
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
-
-#################################################
-# HelloWorld7
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src7)
-LOCAL_MANIFEST_FILE := AndroidManifest.xml
-
-LOCAL_PACKAGE_NAME := HelloWorld7
-LOCAL_SDK_VERSION := current
-LOCAL_MIN_SDK_VERSION := 24
-LOCAL_PACKAGE_SPLITS := mdpi-v4 hdpi-v4 xhdpi-v4 xxhdpi-v4 xxxhdpi-v4
-
-LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
-
-LOCAL_ASSET_DIR := $(LOCAL_PATH)/res
-
-LOCAL_JAVA_LIBRARIES := android.test.runner.stubs android.test.base.stubs androidx.appcompat_appcompat androidx-constraintlayout_constraintlayout com.google.android.material_material
-
-include $(BUILD_CTS_SUPPORT_PACKAGE)
diff --git a/tests/tests/content/OWNERS b/tests/tests/content/OWNERS
new file mode 100644
index 0000000..12c955a
--- /dev/null
+++ b/tests/tests/content/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 36137
+toddke@google.com
+patb@google.com
+schfan@google.com
+alexbuy@google.com
diff --git a/tests/tests/content/data/v4-only-original.apk b/tests/tests/content/data/v4-only-original.apk
new file mode 100644
index 0000000..50b5ea2
--- /dev/null
+++ b/tests/tests/content/data/v4-only-original.apk
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10488.avi b/tests/tests/content/data/v4-only-original.apk.idsig
similarity index 66%
rename from tests/tests/security/res/raw/cve_2019_10488.avi
rename to tests/tests/content/data/v4-only-original.apk.idsig
index 9230fe4..aa2d5d5 100644
--- a/tests/tests/security/res/raw/cve_2019_10488.avi
+++ b/tests/tests/content/data/v4-only-original.apk.idsig
Binary files differ
diff --git a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
index 1198ef8..dea3192 100644
--- a/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
+++ b/tests/tests/content/src/android/content/cts/AvailableIntentsTest.java
@@ -379,6 +379,10 @@
         }
     }
 
+    public void testInteractAcrossProfilesSettings() {
+        assertCanBeHandled(new Intent(Settings.ACTION_MANAGE_CROSS_PROFILE_ACCESS));
+    }
+
     public void testChangeDefaultSmsApplication() {
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
new file mode 100644
index 0000000..ce37d05
--- /dev/null
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandIncrementalTest.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm.cts;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import android.os.ParcelFileDescriptor;
+import android.os.incremental.IncrementalManager;
+import android.platform.test.annotations.AppModeFull;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.Optional;
+
+@RunWith(AndroidJUnit4.class)
+@AppModeFull
+public class PackageManagerShellCommandIncrementalTest {
+    private static final String TEST_APP_PACKAGE = "com.android.incremental.sampletestapp";
+
+    private static final String TEST_APK_PATH = "/data/local/tmp/cts/content/";
+    private static final String TEST_APK = "v4-only-original.apk";
+
+    private static String executeShellCommand(String command) throws IOException {
+        final ParcelFileDescriptor stdout =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(
+                        command);
+        try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
+            return readFullStream(inputStream);
+        }
+    }
+
+    private static String executeShellCommand(String command, File input)
+            throws IOException {
+        return executeShellCommand(command, new File[]{input});
+    }
+
+    private static String executeShellCommand(String command, File[] inputs)
+            throws IOException {
+        final ParcelFileDescriptor[] pfds =
+                InstrumentationRegistry.getInstrumentation().getUiAutomation()
+                        .executeShellCommandRw(command);
+        ParcelFileDescriptor stdout = pfds[0];
+        ParcelFileDescriptor stdin = pfds[1];
+        try (FileOutputStream outputStream = new ParcelFileDescriptor.AutoCloseOutputStream(
+                stdin)) {
+            for (File input : inputs) {
+                try (FileInputStream inputStream = new FileInputStream(input)) {
+                    writeFullStream(inputStream, outputStream, input.length());
+                }
+            }
+        }
+        try (InputStream inputStream = new ParcelFileDescriptor.AutoCloseInputStream(stdout)) {
+            return readFullStream(inputStream);
+        }
+    }
+
+    private static String readFullStream(InputStream inputStream) throws IOException {
+        ByteArrayOutputStream result = new ByteArrayOutputStream();
+        writeFullStream(inputStream, result, -1);
+        return result.toString("UTF-8");
+    }
+
+    private static void writeFullStream(InputStream inputStream, OutputStream outputStream,
+            long expected)
+            throws IOException {
+        byte[] buffer = new byte[1024];
+        long total = 0;
+        int length;
+        while ((length = inputStream.read(buffer)) != -1) {
+            outputStream.write(buffer, 0, length);
+            total += length;
+        }
+        if (expected > 0) {
+            assertEquals(expected, total);
+        }
+    }
+
+    @Before
+    public void onBefore() throws Exception {
+        uninstallPackageSilently(TEST_APP_PACKAGE);
+        assertFalse(isAppInstalled(TEST_APP_PACKAGE));
+    }
+
+    @After
+    public void onAfter() throws Exception {
+        uninstallPackageSilently(TEST_APP_PACKAGE);
+        assertFalse(isAppInstalled(TEST_APP_PACKAGE));
+        assertEquals(null, getSplits(TEST_APP_PACKAGE));
+    }
+
+    @Test
+    public void testInstallWithIdSig() throws Exception {
+        if (!IncrementalManager.isAllowed()) {
+            return;
+        }
+        installPackage(TEST_APK);
+        assertTrue(isAppInstalled(TEST_APP_PACKAGE));
+    }
+
+    @Test
+    public void testProperty() {
+        if (!IncrementalManager.isAllowed()) {
+            return;
+        }
+
+        android.os.SystemProperties.set("incremental.allowed", "0");
+        assertFalse(IncrementalManager.isAllowed());
+        android.os.SystemProperties.set("incremental.allowed", null);
+        assertTrue(IncrementalManager.isAllowed());
+    }
+
+    private boolean isAppInstalled(String packageName) throws IOException {
+        final String commandResult = executeShellCommand("pm list packages");
+        final int prefixLength = "package:".length();
+        return Arrays.stream(commandResult.split("\\r?\\n"))
+                .anyMatch(line -> line.substring(prefixLength).equals(packageName));
+    }
+
+    private String getSplits(String packageName) throws IOException {
+        final String commandResult = executeShellCommand("pm dump " + packageName);
+        final String prefix = "    splits=[";
+        final int prefixLength = prefix.length();
+        Optional<String> maybeSplits = Arrays.stream(commandResult.split("\\r?\\n"))
+                .filter(line -> line.startsWith(prefix)).findFirst();
+        if (!maybeSplits.isPresent()) {
+            return null;
+        }
+        String splits = maybeSplits.get();
+        return splits.substring(prefixLength, splits.length() - 1);
+    }
+
+    private static String createApkPath(String baseName) {
+        return TEST_APK_PATH + baseName;
+    }
+
+    private void installPackage(String baseName) throws IOException {
+        File file = new File(createApkPath(baseName));
+        assertEquals("Success\n",
+                executeShellCommand("pm install-incremental -t -g " + file.getPath()));
+    }
+
+    private String uninstallPackageSilently(String packageName) throws IOException {
+        return executeShellCommand("pm uninstall " + packageName);
+    }
+}
+
diff --git a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
index 1b51264..36ba232 100644
--- a/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
+++ b/tests/tests/content/src/android/content/pm/cts/PackageManagerShellCommandTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.os.ParcelFileDescriptor;
+import android.os.incremental.IncrementalManager;
 import android.platform.test.annotations.AppModeFull;
 
 import androidx.test.InstrumentationRegistry;
@@ -73,8 +74,7 @@
 
     @Parameters
     public static Iterable<Object> initParameters() {
-        return Arrays.asList(DATA_LOADER_TYPE_NONE, DATA_LOADER_TYPE_STREAMING/*,
-                DATA_LOADER_TYPE_INCREMENTAL*/);
+        return Arrays.asList(DATA_LOADER_TYPE_NONE);
     }
 
     private boolean mStreaming = false;
@@ -137,17 +137,24 @@
     }
 
     @Before
-    public void checkNotInstalled() throws Exception {
+    public void onBefore() throws Exception {
+        // Check if Incremental is allowed and revert to non-dataloader installation.
+        if (mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL && !IncrementalManager.isAllowed()) {
+            mDataLoaderType = DATA_LOADER_TYPE_NONE;
+        }
+
         mStreaming = mDataLoaderType != DATA_LOADER_TYPE_NONE;
         mIncremental = mDataLoaderType == DATA_LOADER_TYPE_INCREMENTAL;
         mInstall = mDataLoaderType == DATA_LOADER_TYPE_NONE ? " install " :
                 mDataLoaderType == DATA_LOADER_TYPE_STREAMING ? " install-streaming " :
                         " install-incremental ";
+
+        uninstallPackageSilently(TEST_APP_PACKAGE);
         assertFalse(isAppInstalled(TEST_APP_PACKAGE));
     }
 
     @After
-    public void uninstall() throws Exception {
+    public void onAfter() throws Exception {
         uninstallPackageSilently(TEST_APP_PACKAGE);
         assertFalse(isAppInstalled(TEST_APP_PACKAGE));
         assertEquals(null, getSplits(TEST_APP_PACKAGE));
diff --git a/tests/tests/graphics/jni/android_graphics_cts_ANativeWindowTest.cpp b/tests/tests/graphics/jni/android_graphics_cts_ANativeWindowTest.cpp
index 74f33cd..1b22e62 100644
--- a/tests/tests/graphics/jni/android_graphics_cts_ANativeWindowTest.cpp
+++ b/tests/tests/graphics/jni/android_graphics_cts_ANativeWindowTest.cpp
@@ -58,12 +58,29 @@
     return ANativeWindow_getBuffersDataSpace(window);
 }
 
-const std::array<JNINativeMethod, 3> JNI_METHODS = {{
-    { "nPushBufferWithTransform", "(Landroid/view/Surface;I)V", (void*)pushBufferWithTransform },
-    { "nSetBuffersDataSpace", "(Landroid/view/Surface;I)I", (void*)setBuffersDataSpace },
-    { "nGetBuffersDataSpace", "(Landroid/view/Surface;)I", (void*)getBuffersDataSpace },
-}};
+void tryAllocateBuffers(JNIEnv* env, jclass, jobject jSurface) {
+    ANativeWindow* window = nullptr;
+    if (jSurface) {
+      window = ANativeWindow_fromSurface(env, jSurface);
+    }
 
+    ANativeWindow_tryAllocateBuffers(window);
+
+    if (window) {
+      ANativeWindow_release(window);
+    }
+}
+
+const std::array<JNINativeMethod, 4> JNI_METHODS = {{
+    {"nPushBufferWithTransform", "(Landroid/view/Surface;I)V",
+     (void*)pushBufferWithTransform},
+    {"nSetBuffersDataSpace", "(Landroid/view/Surface;I)I",
+     (void*)setBuffersDataSpace},
+    {"nGetBuffersDataSpace", "(Landroid/view/Surface;)I",
+     (void*)getBuffersDataSpace},
+    {"nTryAllocateBuffers", "(Landroid/view/Surface;)V",
+     (void*)tryAllocateBuffers},
+}};
 }
 
 int register_android_graphics_cts_ANativeWindowTest(JNIEnv* env) {
diff --git a/tests/tests/graphics/src/android/graphics/cts/ANativeWindowTest.java b/tests/tests/graphics/src/android/graphics/cts/ANativeWindowTest.java
index 17ab379..7e95e8c 100644
--- a/tests/tests/graphics/src/android/graphics/cts/ANativeWindowTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/ANativeWindowTest.java
@@ -245,7 +245,21 @@
         System.arraycopy(tmp, 0, result, 0, 16);
     }
 
+    @Test
+    public void testTryAllocateBuffersDoesNotCrash() {
+        int[] texId = new int[1];
+        GLES20.glGenTextures(1, texId, 0);
+
+        SurfaceTexture consumer = new SurfaceTexture(texId[0]);
+        consumer.setDefaultBufferSize(16, 16);
+        Surface surface = new Surface(consumer);
+
+        nTryAllocateBuffers(surface);
+        nTryAllocateBuffers(null);
+    }
+
     private static native void nPushBufferWithTransform(Surface surface, int transform);
     private static native int nSetBuffersDataSpace(Surface surface, int dataSpace);
     private static native int nGetBuffersDataSpace(Surface surface);
+    private static native void nTryAllocateBuffers(Surface surface);
 }
diff --git a/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java
new file mode 100644
index 0000000..3f8c011
--- /dev/null
+++ b/tests/tests/graphics/src/android/graphics/cts/VulkanDeqpLevelTest.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.cts;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.pm.FeatureInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.compatibility.common.util.CddTest;
+
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Test that feature flag android.software.vulkan.deqp.level is present and that it has an
+ * acceptable value.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class VulkanDeqpLevelTest {
+
+    private static final String TAG = VulkanDeqpLevelTest.class.getSimpleName();
+    private static final boolean DEBUG = false;
+
+    private static final int MINIMUM_VULKAN_DEQP_LEVEL = 0x07E30301; // Corresponds to 2019-03-01
+
+    // Require patch version 3 for Vulkan 1.0: It was the first publicly available version,
+    // and there was an important bugfix relative to 1.0.2.
+    private static final int VULKAN_1_0 = 0x00400003; // 1.0.3
+
+    private PackageManager mPm;
+    private FeatureInfo mVulkanHardwareVersion = null;
+
+    @Before
+    public void setup() throws Throwable {
+        mPm = InstrumentationRegistry.getTargetContext().getPackageManager();
+        FeatureInfo[] features = mPm.getSystemAvailableFeatures();
+        if (features != null) {
+            for (FeatureInfo feature : features) {
+                if (PackageManager.FEATURE_VULKAN_HARDWARE_VERSION.equals(feature.name)) {
+                    mVulkanHardwareVersion = feature;
+                    if (DEBUG) {
+                        Log.d(TAG, feature.name + "=0x" + Integer.toHexString(feature.version));
+                    }
+                }
+            }
+        }
+    }
+
+    @CddTest(requirement = "7.1.4.2/C-1-8")
+    @Ignore("b/149464764: Test disabled until certain targets get the new feature flag.")
+    @Test
+    public void testVulkanDeqpLevel() {
+        if (mVulkanHardwareVersion.version >= VULKAN_1_0) {
+            if (DEBUG) {
+                Log.d(TAG, "Checking whether " + PackageManager.FEATURE_VULKAN_DEQP_LEVEL
+                        + " has an acceptable value");
+            }
+            assertTrue("Feature " + PackageManager.FEATURE_VULKAN_DEQP_LEVEL + " must be present "
+                            + "and have at least version " + MINIMUM_VULKAN_DEQP_LEVEL,
+                    mPm.hasSystemFeature(PackageManager.FEATURE_VULKAN_DEQP_LEVEL,
+                            MINIMUM_VULKAN_DEQP_LEVEL));
+        }
+    }
+
+}
diff --git a/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
new file mode 100644
index 0000000..34b0cf2
--- /dev/null
+++ b/tests/tests/identity/src/android/security/identity/cts/AttestationTest.java
@@ -0,0 +1,156 @@
+/*
+ * Copyright 2020 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.security.identity.cts;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+
+import android.security.identity.IdentityCredential;
+import android.security.identity.IdentityCredentialStore;
+import androidx.test.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.Ignore;
+
+import com.google.common.primitives.Bytes;
+
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.X509Certificate;
+import java.util.Collection;
+
+import java.util.Optional;
+
+public class AttestationTest {
+    private static final String TAG = "AttestationTest";
+
+    // The subset of Keymaster tags we care about. See
+    //
+    //   https://source.android.com/security/keystore/tags
+    //
+    // for a list of known tags.
+    //
+    public static final int KM_TAG_ATTESTATION_APPLICATION_ID = 709;
+    public static final int KM_TAG_IDENTITY_CREDENTIAL_KEY = 721;
+
+    @Ignore("Not ready until SW implementation produces correct attestations")
+    @Test
+    public void attestationTest() throws Exception {
+        Context appContext = InstrumentationRegistry.getTargetContext();
+        IdentityCredentialStore store = IdentityCredentialStore.getInstance(appContext);
+
+        // Use a random challenge of length between 16 and 32.
+        SecureRandom random = new SecureRandom();
+        int challengeLength = 16 + random.nextInt(16);
+        byte[] challenge = new byte[challengeLength];
+        random.nextBytes(challenge);
+
+        String credentialName = "test";
+
+        store.deleteCredentialByName(credentialName);
+        Collection<X509Certificate> certChain = ProvisioningTest.createCredentialWithChallenge(
+            store, credentialName, challenge);
+        store.deleteCredentialByName("test");
+
+        // Check that each certificate in the chain isn't expired and also that it's signed by the
+        // next one.
+        assertTrue(verifyCertificateChain(certChain));
+
+        // Parse the attestation record... Identity Credential uses standard KeyMaster-style
+        // attestation with only a few differences:
+        //
+        // - Tag::IDENTITY_CREDENTIAL_KEY (boolean) must be set to identify the key as an Identity
+        //   Credential key.
+        //
+        // - the KeyMaster version and security-level should be set to that of Identity Credential
+        //
+        // In this test we only test for these two things and a) the attestationApplicationId
+        // matches the calling application; and b) the given challenge matches what was sent.
+        //
+        // We could test for all the other expected attestation records but currently we assume
+        // this is already tested by Keymaster/Android Keystore tests since the TA is expected to
+        // re-use the same infrastructure.
+        //
+        X509Certificate cert = certChain.iterator().next();
+        ParsedAttestationRecord record = new ParsedAttestationRecord(cert);
+
+        // Need at least attestation version 3 and attestations to be done in either the TEE
+        // or in a StrongBox.
+        assertTrue(record.getAttestationVersion() >= 3);
+
+        // Also per the IC HAL, the keymasterSecurityLevel field is used as the securityLevel of
+        // the IC TA and this must be either TEE or in a StrongBox... except we specifically
+        // allow our software implementation to report Software here.
+        //
+        // Since we cannot get the implementation name or author at this layer, we can't test for
+        // it. This can be tested for in the VTS test, however.
+
+        // As per the IC HAL, the keymasterVersion field should be the version of the Identity
+        // Credential HAL - 1.0 - and this is encoded as major*10 + minor. This field is used by
+        // Keymaster which is known to report integers less than or equal to 4 (for KM up to 4.0)
+        // and integers greater or equal than 41 (for KM starting with 4.1).
+        //
+        // Since we won't get to version 4.0 of the IC HAL for a while, let's also check that a KM
+        // version isn't errornously returned.
+        assertTrue(record.getKeymasterVersion() >= 10);
+        assertTrue(record.getKeymasterVersion() < 40);
+
+        // Check that the challenge we passed in, is in fact in the attestation record.
+        assertArrayEquals(challenge, record.getAttestationChallenge());
+
+        // Tag::ATTESTATION_APPLICATION_ID is used to identify the set of possible applications of
+        // which one has initiated a key attestation. This is complicated ASN.1 which we don't want
+        // to parse and we don't need to [1].. we can however easily check that our applicationId
+        // is appearing as a substring somewhere in this blob.
+        //
+        // [1] : and the point of this test isn't to verify that attestations are done correctly,
+        // that's tested elsewhere in e.g. KM and Android Keystore.
+        //
+        Optional<byte[]> attestationApplicationId =
+                record.getSoftwareAuthorizationByteString(KM_TAG_ATTESTATION_APPLICATION_ID);
+        assertTrue(attestationApplicationId.isPresent());
+        String appId = appContext.getPackageName();
+        assertTrue(Bytes.indexOf(attestationApplicationId.get(), appId.getBytes()) != -1);
+
+        // Tag::IDENTITY_CREDENTIAL_KEY is used in attestations produced by the Identity Credential
+        // HAL when that HAL attests to Credential Keys.
+        boolean isIdentityCredentialKey =
+                record.getTeeAuthorizationBoolean(KM_TAG_IDENTITY_CREDENTIAL_KEY);
+        assertTrue(isIdentityCredentialKey);
+    }
+
+    // This only verifies each cert hasn't expired and signed by the next one.
+    private static boolean verifyCertificateChain(Collection<X509Certificate> certChain) {
+        X509Certificate[] certs = new X509Certificate[certChain.size()];
+        certs = certChain.toArray(certs);
+        X509Certificate parent = certs[certs.length - 1];
+        for (int i = certs.length - 1; i >= 0; i--) {
+            X509Certificate cert = certs[i];
+            try {
+                cert.checkValidity();
+                cert.verify(parent.getPublicKey());
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
+            parent = cert;
+        }
+        return true;
+    }
+}
diff --git a/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java b/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
index 791be12..a474729 100644
--- a/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/EphemeralKeyTest.java
@@ -135,8 +135,8 @@
                 PublicKey holderEphemeralPublicKey) throws IdentityCredentialException {
             mCipherSuite = cipherSuite;
             mHolderEphemeralPublicKey = holderEphemeralPublicKey;
-            mCounter = 0;
-            mMdlExpectedCounter = 0;
+            mCounter = 1;
+            mMdlExpectedCounter = 1;
 
             try {
                 KeyPairGenerator kpg = KeyPairGenerator.getInstance(KeyProperties.KEY_ALGORITHM_EC);
diff --git a/tests/tests/identity/src/android/security/identity/cts/ParsedAttestationRecord.java b/tests/tests/identity/src/android/security/identity/cts/ParsedAttestationRecord.java
new file mode 100644
index 0000000..e4297d7
--- /dev/null
+++ b/tests/tests/identity/src/android/security/identity/cts/ParsedAttestationRecord.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2020 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.security.identity.cts;
+
+import java.io.IOException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Set;
+import java.util.Optional;
+
+import org.bouncycastle.asn1.ASN1InputStream;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Sequence;
+import org.bouncycastle.asn1.ASN1Boolean;
+import org.bouncycastle.asn1.ASN1Encodable;
+import org.bouncycastle.asn1.ASN1Enumerated;
+import org.bouncycastle.asn1.ASN1Integer;
+import org.bouncycastle.asn1.ASN1OctetString;
+import org.bouncycastle.asn1.ASN1Primitive;
+import org.bouncycastle.asn1.ASN1Set;
+import org.bouncycastle.asn1.ASN1TaggedObject;
+import org.bouncycastle.asn1.DEROctetString;
+
+// This code is loosely based on https://github.com/google/android-key-attestation
+
+class ParsedAttestationRecord {
+    private static final String KEY_DESCRIPTION_OID = "1.3.6.1.4.1.11129.2.1.17";
+
+    enum SecurityLevel {
+        SOFTWARE,
+        TRUSTED_ENVIRONMENT,
+        STRONG_BOX
+    }
+
+    private static final int ATTESTATION_VERSION_INDEX = 0;
+    private static final int ATTESTATION_SECURITY_LEVEL_INDEX = 1;
+    private static final int KEYMASTER_VERSION_INDEX = 2;
+    private static final int KEYMASTER_SECURITY_LEVEL_INDEX = 3;
+    private static final int ATTESTATION_CHALLENGE_INDEX = 4;
+    private static final int UNIQUE_ID_INDEX = 5;
+    private static final int SW_ENFORCED_INDEX = 6;
+    private static final int TEE_ENFORCED_INDEX = 7;
+
+    // Some security values. The complete list is in this AOSP file:
+    // hardware/libhardware/include/hardware/keymaster_defs.h
+    private static final int KM_SECURITY_LEVEL_SOFTWARE = 0;
+    private static final int KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT = 1;
+    private static final int KM_SECURITY_LEVEL_STRONG_BOX = 2;
+
+    private int attestationVersion;
+    private SecurityLevel attestationSecurityLevel;
+    private int keymasterVersion;
+    private SecurityLevel keymasterSecurityLevel;
+    private byte[] attestationChallenge;
+    private byte[] uniqueId;
+
+    private Map<Integer, ASN1Primitive> softwareEnforcedAuthorizations;
+    private Map<Integer, ASN1Primitive> teeEnforcedAuthorizations;
+
+    public int getAttestationVersion() {
+        return attestationVersion;
+    }
+
+    public SecurityLevel getAttestationSecurityLevel() {
+        return attestationSecurityLevel;
+    }
+
+    public int getKeymasterVersion() {
+        return keymasterVersion;
+    }
+
+    public SecurityLevel getKeymasterSecurityLevel() {
+        return attestationSecurityLevel;
+    }
+
+    public byte[] getAttestationChallenge() {
+        return attestationChallenge;
+    }
+
+    public byte[] getUniqueId() {
+        return uniqueId;
+    }
+
+    public Set<Integer> getSoftwareEnforcedAuthorizationTags() {
+        return softwareEnforcedAuthorizations.keySet();
+    }
+
+    public Set<Integer> getTeeEnforcedAuthorizationTags() {
+        return teeEnforcedAuthorizations.keySet();
+    }
+
+    private static ASN1Primitive findAuthorizationListEntry(
+        Map<Integer, ASN1Primitive> authorizationMap, int tag) {
+        return authorizationMap.getOrDefault(tag, null);
+    }
+
+    public Optional<Integer> getSoftwareAuthorizationInteger(int tag) {
+        ASN1Primitive entry = findAuthorizationListEntry(softwareEnforcedAuthorizations, tag);
+        return Optional.ofNullable(entry).map(ParsedAttestationRecord::getIntegerFromAsn1);
+    }
+
+    public Optional<Integer> getTeeAuthorizationInteger(int tag) {
+        ASN1Primitive entry = findAuthorizationListEntry(teeEnforcedAuthorizations, tag);
+        return Optional.ofNullable(entry).map(ParsedAttestationRecord::getIntegerFromAsn1);
+    }
+    public boolean getSoftwareAuthorizationBoolean(int tag) {
+        ASN1Primitive entry = findAuthorizationListEntry(softwareEnforcedAuthorizations, tag);
+        return entry != null;
+    }
+
+    public boolean getTeeAuthorizationBoolean(int tag) {
+        ASN1Primitive entry = findAuthorizationListEntry(teeEnforcedAuthorizations, tag);
+        return entry != null;
+    }
+
+    public Optional<byte[]> getSoftwareAuthorizationByteString(int tag) {
+        ASN1OctetString entry = (ASN1OctetString) findAuthorizationListEntry(softwareEnforcedAuthorizations, tag);
+        return Optional.ofNullable(entry).map(ASN1OctetString::getOctets);
+    }
+
+    public Optional<byte[]> getTeeAuthorizationByteString(int tag) {
+        ASN1OctetString entry = (ASN1OctetString) findAuthorizationListEntry(teeEnforcedAuthorizations, tag);
+        return Optional.ofNullable(entry).map(ASN1OctetString::getOctets);
+    }
+
+    private static boolean getBooleanFromAsn1(ASN1Encodable asn1Value) {
+        if (asn1Value instanceof ASN1Boolean) {
+            return ((ASN1Boolean) asn1Value).isTrue();
+        } else {
+            throw new RuntimeException(
+                "Boolean value expected; found " + asn1Value.getClass().getName() + " instead.");
+        }
+    }
+
+    private static int getIntegerFromAsn1(ASN1Encodable asn1Value) {
+        if (asn1Value instanceof ASN1Integer) {
+            return ((ASN1Integer) asn1Value).getValue().intValue();
+        } else if (asn1Value instanceof ASN1Enumerated) {
+            return ((ASN1Enumerated) asn1Value).getValue().intValue();
+        } else {
+            throw new IllegalArgumentException(
+                "Integer value expected; found " + asn1Value.getClass().getName() + " instead.");
+        }
+    }
+
+    private static Map<Integer, ASN1Primitive> getAuthorizationMap(
+        ASN1Encodable[] authorizationList) {
+        Map<Integer, ASN1Primitive> authorizationMap = new HashMap<>();
+        for (ASN1Encodable entry : authorizationList) {
+            ASN1TaggedObject taggedEntry = (ASN1TaggedObject) entry;
+            authorizationMap.put(taggedEntry.getTagNo(), taggedEntry.getObject());
+        }
+        return authorizationMap;
+    }
+
+    public ParsedAttestationRecord(X509Certificate cert) throws IOException {
+        byte[] attestationExtensionBytes = cert.getExtensionValue(KEY_DESCRIPTION_OID);
+        if (attestationExtensionBytes == null || attestationExtensionBytes.length == 0) {
+            throw new IllegalArgumentException("Couldn't find keystore attestation extension.");
+        }
+
+        ASN1Sequence seq;
+        try (ASN1InputStream asn1InputStream = new ASN1InputStream(attestationExtensionBytes)) {
+            // The extension contains one object, a sequence, in the
+            // Distinguished Encoding Rules (DER)-encoded form. Get the DER
+            // bytes.
+            byte[] derSequenceBytes = ((ASN1OctetString) asn1InputStream.readObject()).getOctets();
+            // Decode the bytes as an ASN1 sequence object.
+            try (ASN1InputStream seqInputStream = new ASN1InputStream(derSequenceBytes)) {
+                seq = (ASN1Sequence) seqInputStream.readObject();
+            }
+        }
+
+        this.attestationVersion = getIntegerFromAsn1(seq.getObjectAt(ATTESTATION_VERSION_INDEX));
+        this.attestationSecurityLevel =
+                securityLevelToEnum(getIntegerFromAsn1(
+                    seq.getObjectAt(ATTESTATION_SECURITY_LEVEL_INDEX)));
+        this.keymasterVersion = getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_VERSION_INDEX));
+        this.keymasterSecurityLevel = securityLevelToEnum(
+            getIntegerFromAsn1(seq.getObjectAt(KEYMASTER_SECURITY_LEVEL_INDEX)));
+        this.attestationChallenge =
+                ((ASN1OctetString) seq.getObjectAt(ATTESTATION_CHALLENGE_INDEX)).getOctets();
+        this.uniqueId = ((ASN1OctetString) seq.getObjectAt(UNIQUE_ID_INDEX)).getOctets();
+
+        this.softwareEnforcedAuthorizations = getAuthorizationMap(
+            ((ASN1Sequence) seq.getObjectAt(SW_ENFORCED_INDEX)).toArray());
+
+        this.teeEnforcedAuthorizations = getAuthorizationMap(
+            ((ASN1Sequence) seq.getObjectAt(TEE_ENFORCED_INDEX)).toArray());
+    }
+
+    private static SecurityLevel securityLevelToEnum(int securityLevel) {
+        switch (securityLevel) {
+            case KM_SECURITY_LEVEL_SOFTWARE:
+                return SecurityLevel.SOFTWARE;
+            case KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT:
+                return SecurityLevel.TRUSTED_ENVIRONMENT;
+            case KM_SECURITY_LEVEL_STRONG_BOX:
+                return SecurityLevel.STRONG_BOX;
+            default:
+                throw new IllegalArgumentException("Invalid security level.");
+        }
+    }
+}
diff --git a/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java b/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
index 8269234..48cc405 100644
--- a/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
+++ b/tests/tests/identity/src/android/security/identity/cts/ProvisioningTest.java
@@ -107,11 +107,17 @@
 
     static Collection<X509Certificate> createCredential(IdentityCredentialStore store,
             String credentialName) throws IdentityCredentialException {
+        return createCredentialWithChallenge(store, credentialName, "SomeChallenge".getBytes());
+    }
+
+    static Collection<X509Certificate> createCredentialWithChallenge(IdentityCredentialStore store,
+            String credentialName,
+            byte[] challenge) throws IdentityCredentialException {
         WritableIdentityCredential wc = null;
         wc = store.createCredential(credentialName, "org.iso.18013-5.2019.mdl");
 
         Collection<X509Certificate> certificateChain =
-                wc.getCredentialKeyCertificateChain("SomeChallenge".getBytes());
+                wc.getCredentialKeyCertificateChain(challenge);
         // TODO: inspect cert-chain
 
         // Profile 0 (no authentication)
diff --git a/tests/tests/media/libaudiojni/Android.bp b/tests/tests/media/libaudiojni/Android.bp
index 6e1805c..44dab86 100644
--- a/tests/tests/media/libaudiojni/Android.bp
+++ b/tests/tests/media/libaudiojni/Android.bp
@@ -33,6 +33,7 @@
     cflags: [
         "-Werror",
         "-Wall",
+        "-Wno-deprecated-declarations",
     ],
     gtest: false,
 }
diff --git a/tests/tests/media/libndkaudio/Android.bp b/tests/tests/media/libndkaudio/Android.bp
index 2746f0d..13f907c 100644
--- a/tests/tests/media/libndkaudio/Android.bp
+++ b/tests/tests/media/libndkaudio/Android.bp
@@ -39,6 +39,7 @@
     cflags: [
         "-Werror",
         "-Wall",
+        "-Wno-deprecated-declarations",
     ],
     gtest: false,
 }
diff --git a/tests/tests/media/res/raw/a_4_haptic.ogg b/tests/tests/media/res/raw/a_4_haptic.ogg
index e8287a8..3c94c8d 100644
--- a/tests/tests/media/res/raw/a_4_haptic.ogg
+++ b/tests/tests/media/res/raw/a_4_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/b_5_haptic.ogg b/tests/tests/media/res/raw/b_5_haptic.ogg
index cb4df5a..90ab939 100644
--- a/tests/tests/media/res/raw/b_5_haptic.ogg
+++ b/tests/tests/media/res/raw/b_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/c_sharp_5_haptic.ogg b/tests/tests/media/res/raw/c_sharp_5_haptic.ogg
index 7950552..57c46ea 100644
--- a/tests/tests/media/res/raw/c_sharp_5_haptic.ogg
+++ b/tests/tests/media/res/raw/c_sharp_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/e_5_haptic.ogg b/tests/tests/media/res/raw/e_5_haptic.ogg
index 7c7f4cd..98289dc 100644
--- a/tests/tests/media/res/raw/e_5_haptic.ogg
+++ b/tests/tests/media/res/raw/e_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/res/raw/g_sharp_5_haptic.ogg b/tests/tests/media/res/raw/g_sharp_5_haptic.ogg
index ecf9439..6fb7388 100644
--- a/tests/tests/media/res/raw/g_sharp_5_haptic.ogg
+++ b/tests/tests/media/res/raw/g_sharp_5_haptic.ogg
Binary files differ
diff --git a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
index 84a8ccb..7b00c9a 100644
--- a/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioPlaybackCaptureTest.java
@@ -42,7 +42,6 @@
 import android.media.projection.MediaProjection;
 import android.os.Handler;
 import android.os.Looper;
-import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 
 import androidx.test.rule.ActivityTestRule;
@@ -78,7 +77,6 @@
     private AudioManager mAudioManager;
     private boolean mPlaybackBeforeCapture;
     private int mUid; //< UID of this test
-    private int mUserId; // userId of this test
     private AudioPlaybackCaptureActivity mActivity;
     private MediaProjection mMediaProjection;
     @Rule
@@ -90,8 +88,6 @@
         public @AttributeUsage int[] excludeUsages;
         public int[] matchingUids;
         public int[] excludeUids;
-        public int[] matchingUserIds;
-        public int[] excludeUserIds;
         private AudioPlaybackCaptureConfiguration build(MediaProjection projection)
                 throws Exception {
             AudioPlaybackCaptureConfiguration.Builder apccBuilder =
@@ -117,16 +113,6 @@
                     apccBuilder.excludeUid(uid);
                 }
             }
-            if (matchingUserIds != null) {
-                for (int userId : matchingUserIds) {
-                    apccBuilder.addMatchingUserId(userId);
-                }
-            }
-            if (excludeUserIds != null) {
-                for (int userId : excludeUserIds) {
-                    apccBuilder.excludeUserId(userId);
-                }
-            }
             AudioPlaybackCaptureConfiguration config = apccBuilder.build();
             assertCorreclyBuilt(config);
             return config;
@@ -137,8 +123,6 @@
             assertEqualNullIsEmpty("excludeUsages", excludeUsages, config.getExcludeUsages());
             assertEqualNullIsEmpty("matchingUids", matchingUids, config.getMatchingUids());
             assertEqualNullIsEmpty("excludeUids", excludeUids, config.getExcludeUids());
-            assertEqualNullIsEmpty("matchingUserIds", matchingUserIds, config.getMatchingUserIds());
-            assertEqualNullIsEmpty("excludeUserIds", excludeUserIds, config.getExcludeUserIds());
         }
 
         private void assertEqualNullIsEmpty(String msg, int[] expected, int[] found) {
@@ -158,8 +142,6 @@
         mActivity = mActivityRule.getActivity();
         mAudioManager = mActivity.getSystemService(AudioManager.class);
         mUid = mActivity.getApplicationInfo().uid;
-        mUserId = UserHandle.getUserHandleForUid(mActivity.getApplicationInfo().uid)
-                .getIdentifier();
         mMediaProjection = mActivity.waitForMediaProjection();
     }
 
@@ -301,7 +283,8 @@
             AudioAttributes.USAGE_ASSISTANCE_NAVIGATION_GUIDANCE,
             AudioAttributes.USAGE_ASSISTANCE_SONIFICATION,
             AudioAttributes.USAGE_ASSISTANT,
-            AudioAttributes.USAGE_NOTIFICATION
+            AudioAttributes.USAGE_NOTIFICATION,
+            AudioAttributes.USAGE_VOICE_COMMUNICATION
     };
 
     @Presubmit
@@ -338,13 +321,6 @@
         testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_UNKNOWN, EXPECT_SILENCE);
     }
 
-    @Test(expected = IllegalStateException.class)
-    public void testCombineUserId() throws Exception {
-        mAPCTestConfig.matchingUserIds = new int[]{ mUserId };
-        mAPCTestConfig.excludeUserIds = new int[]{ mUserId + 1 };
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_UNKNOWN, EXPECT_SILENCE);
-    }
-
     @Test
     public void testCaptureMatchingAllowedUsage() throws Exception {
         for (int usage : ALLOWED_USAGES) {
@@ -388,45 +364,23 @@
         mAPCTestConfig.matchingUids = new int[]{ mUid };
         testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_DATA);
         testPlaybackCapture(OPT_OUT, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_ALARM, EXPECT_SILENCE);
+        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_VOICE_COMMUNICATION, EXPECT_SILENCE);
 
         mAPCTestConfig.matchingUids = new int[]{ 0 };
         testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
     }
 
     @Test
-    public void testCaptureMatchingUserId() throws Exception {
-        mAPCTestConfig.matchingUserIds = new int[]{ mUserId };
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_DATA);
-        testPlaybackCapture(OPT_OUT, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_ALARM, EXPECT_SILENCE);
-
-        mAPCTestConfig.matchingUserIds = new int[]{ mUserId + 1 };
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
-    }
-
-    @Test
     public void testCaptureExcludeUid() throws Exception {
         mAPCTestConfig.excludeUids = new int[]{ 0 };
         testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_DATA);
         testPlaybackCapture(OPT_OUT, AudioAttributes.USAGE_UNKNOWN, EXPECT_SILENCE);
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_ALARM, EXPECT_SILENCE);
+        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_VOICE_COMMUNICATION, EXPECT_SILENCE);
 
         mAPCTestConfig.excludeUids = new int[]{ mUid };
         testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
     }
 
-    @Test
-    public void testCaptureExcludeUserId() throws Exception {
-        mAPCTestConfig.excludeUserIds = new int[]{ mUserId + 1 };
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_DATA);
-        testPlaybackCapture(OPT_OUT, AudioAttributes.USAGE_UNKNOWN, EXPECT_SILENCE);
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_ALARM, EXPECT_SILENCE);
-
-        mAPCTestConfig.excludeUserIds = new int[]{ mUserId };
-        testPlaybackCapture(OPT_IN, AudioAttributes.USAGE_GAME, EXPECT_SILENCE);
-    }
-
     @Test(expected = UnsupportedOperationException.class)
     public void testStoppedMediaProjection() throws Exception {
         mMediaProjection.stop();
diff --git a/tests/tests/media/src/android/media/cts/CodecState.java b/tests/tests/media/src/android/media/cts/CodecState.java
index 5f1d322..2384704 100644
--- a/tests/tests/media/src/android/media/cts/CodecState.java
+++ b/tests/tests/media/src/android/media/cts/CodecState.java
@@ -19,6 +19,7 @@
 import android.media.MediaCodec;
 import android.media.MediaExtractor;
 import android.media.MediaFormat;
+import android.os.Handler;
 import android.util.Log;
 import android.view.Surface;
 import java.nio.ByteBuffer;
@@ -50,6 +51,7 @@
     private MediaFormat mFormat;
     private MediaFormat mOutputFormat;
     private NonBlockingAudioTrack mAudioTrack;
+    private OnFrameRenderedListener mOnFrameRenderedListener;
 
     /**
      * Manages audio and video playback using MediaCodec and AudioTrack.
@@ -84,6 +86,11 @@
         String mime = mFormat.getString(MediaFormat.KEY_MIME);
         Log.d(TAG, "CodecState::CodecState " + mime);
         mIsAudio = mime.startsWith("audio/");
+
+        if (mTunneled && !mIsAudio) {
+            mOnFrameRenderedListener = new OnFrameRenderedListener();
+            codec.setOnFrameRenderedListener(mOnFrameRenderedListener, new Handler());
+        }
     }
 
     public void release() {
@@ -100,6 +107,11 @@
         mAvailableOutputBufferIndices = null;
         mAvailableOutputBufferInfos = null;
 
+        if (mOnFrameRenderedListener != null) {
+            mCodec.setOnFrameRenderedListener(null, null);
+            mOnFrameRenderedListener = null;
+        }
+
         mCodec.release();
         mCodec = null;
 
@@ -218,11 +230,6 @@
                 Log.d(TAG, "sampleSize: " + sampleSize + " trackIndex:" + trackIndex +
                         " sampleTime:" + sampleTime + " sampleFlags:" + sampleFlags);
                 mSawInputEOS = true;
-                // FIX-ME: in tunneled mode we currently use input EOS as output EOS indicator
-                // we should use stream duration
-                if (mTunneled && !mIsAudio) {
-                    mSawOutputEOS = true;
-                }
                 return false;
             }
 
@@ -231,9 +238,6 @@
                     mSampleBaseTimeUs = sampleTime;
                 }
                 sampleTime -= mSampleBaseTimeUs;
-                // FIX-ME: in tunneled mode we currently use input buffer time
-                // as video presentation time. This is not accurate and should be fixed
-                mPresentationTimeUs = sampleTime;
             }
 
             if ((sampleFlags & MediaExtractor.SAMPLE_FLAG_ENCRYPTED) != 0) {
@@ -255,11 +259,6 @@
             Log.d(TAG, "saw input EOS on track " + mTrackIndex);
 
             mSawInputEOS = true;
-            // FIX-ME: in tunneled mode we currently use input EOS as output EOS indicator
-            // we should use stream duration
-            if (mTunneled && !mIsAudio) {
-                mSawOutputEOS = true;
-            }
 
             mCodec.queueInputBuffer(
                     index, 0 /* offset */, 0 /* sampleSize */,
@@ -375,6 +374,23 @@
         }
     }
 
+    /** Callback called by the renderer in tunneling mode. */
+    private class OnFrameRenderedListener implements MediaCodec.OnFrameRenderedListener {
+        private static final long TUNNELING_EOS_PRESENTATION_TIME_US = Long.MAX_VALUE;
+
+        @Override
+        public void onFrameRendered(MediaCodec codec, long presentationTimeUs, long nanoTime) {
+            if (this != mOnFrameRenderedListener) {
+                return; // stale event
+            }
+            if (presentationTimeUs == TUNNELING_EOS_PRESENTATION_TIME_US) {
+                 mSawOutputEOS = true;
+            } else {
+                 mPresentationTimeUs = presentationTimeUs;
+            }
+        }
+    }
+
     public long getAudioTimeUs() {
         if (mAudioTrack == null) {
             return 0;
diff --git a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
index 2e62650..b9d4873 100644
--- a/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaPlayerTest.java
@@ -1260,49 +1260,6 @@
         mMediaPlayer.stop();
     }
 
-    public void testMkvWithoutCueSeek() throws Exception {
-        if (!checkLoadResource(
-                R.raw.video_1280x720_mkv_h265_500kbps_25fps_aac_stereo_128kbps_44100hz_withoutcues)) {
-            return; // skip
-        }
-
-        mMediaPlayer.setOnSeekCompleteListener(new MediaPlayer.OnSeekCompleteListener() {
-            @Override
-            public void onSeekComplete(MediaPlayer mp) {
-                mOnSeekCompleteCalled.signal();
-            }
-        });
-        mMediaPlayer.setDisplay(mActivity.getSurfaceHolder());
-        mMediaPlayer.prepare();
-        mOnSeekCompleteCalled.reset();
-        mMediaPlayer.start();
-
-        final int seekPosMs = 3000;
-        final int syncTime2Ms = 5960;
-
-        int cp = runSeekMode(MediaPlayer.SEEK_CLOSEST, seekPosMs);
-        Log.d(LOG_TAG, "runSeekMode SEEK_CLOSEST cp: " + cp);
-        assertTrue("MediaPlayer seek fail with SEEK_CLOSEST mode.",
-                  cp > seekPosMs && cp < syncTime2Ms);
-
-        cp = runSeekMode(MediaPlayer.SEEK_PREVIOUS_SYNC, seekPosMs);
-        Log.d(LOG_TAG, "runSeekMode SEEK_PREVIOUS_SYNC cp: " + cp);
-        assertTrue("MediaPlayer seek fail with SEEK_PREVIOUS_SYNC mode.",
-                cp >= syncTime2Ms);
-
-        cp = runSeekMode(MediaPlayer.SEEK_NEXT_SYNC, seekPosMs);
-        Log.d(LOG_TAG, "runSeekMode SEEK_NEXT_SYNC cp: " + cp);
-        assertTrue("MediaPlayer seek fail with SEEK_NEXT_SYNC mode.",
-                cp >= syncTime2Ms);
-
-        cp = runSeekMode(MediaPlayer.SEEK_CLOSEST_SYNC, seekPosMs);
-        Log.d(LOG_TAG, "runSeekMode SEEK_CLOSEST_SYNC cp: " + cp);
-        assertTrue("MediaPlayer seek fail with SEEK_CLOSEST_SYNC mode.",
-                cp >= syncTime2Ms);
-
-        mMediaPlayer.stop();
-    }
-
     @Presubmit
     public void testSeekModes() throws Exception {
         // This clip has 2 I frames at 66687us and 4299687us.
diff --git a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java b/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
index 72de394..ec9e8b4 100644
--- a/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
+++ b/tests/tests/media/src/android/media/cts/MediaRoute2ProviderServiceTest.java
@@ -16,15 +16,34 @@
 
 package android.media.cts;
 
+import static android.media.cts.MediaRouter2Test.releaseControllers;
 import static android.media.cts.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
 import static android.media.cts.SampleMediaRoute2ProviderService.FEATURE_SPECIAL;
+import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID1;
+import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID2;
+import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
+import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
 
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import android.content.Context;
+import android.media.MediaRoute2Info;
+import android.media.MediaRoute2ProviderService;
 import android.media.MediaRouter2;
+import android.media.MediaRouter2.ControllerCallback;
+import android.media.MediaRouter2.RouteCallback;
+import android.media.MediaRouter2.RoutingController;
+import android.media.MediaRouter2.TransferCallback;
 import android.media.RouteDiscoveryPreference;
+import android.media.RoutingSessionInfo;
 import android.media.cts.SampleMediaRoute2ProviderService.Proxy;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.LargeTest;
 
 import androidx.test.InstrumentationRegistry;
 import androidx.test.runner.AndroidJUnit4;
@@ -34,41 +53,479 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
 
 @RunWith(AndroidJUnit4.class)
+@AppModeFull(reason = "The system should be able to bind to SampleMediaRoute2ProviderService")
+@LargeTest
 public class MediaRoute2ProviderServiceTest {
     private static final String TAG = "MR2ProviderServiceTest";
     Context mContext;
     private MediaRouter2 mRouter2;
     private Executor mExecutor;
+    private SampleMediaRoute2ProviderService mServiceInstance;
 
     private static final int TIMEOUT_MS = 5000;
 
+    private static final String SESSION_ID_1 = "SESSION_ID_1";
+    private static final String SESSION_ID_2 = "SESSION_ID_2";
+
+    // TODO: Merge these TEST_KEY / TEST_VALUE in all files
+    public static final String TEST_KEY = "test_key";
+    public static final String TEST_VALUE = "test_value";
+
     @Before
     public void setUp() throws Exception {
         mContext = InstrumentationRegistry.getTargetContext();
         mRouter2 = MediaRouter2.getInstance(mContext);
         mExecutor = Executors.newSingleThreadExecutor();
+        mServiceInstance = SampleMediaRoute2ProviderService.getInstance();
     }
 
     @After
     public void tearDown() throws Exception {
-        setProxy(null);
+        if (mServiceInstance != null) {
+            mServiceInstance.clear();
+            mServiceInstance = null;
+        }
     }
 
     @Test
+    public void testGetSessionInfoAndGetAllSessionInfo() {
+        SampleMediaRoute2ProviderService service = mServiceInstance;
+        assertNotNull(service);
+        assertEquals(0, service.getAllSessionInfo().size());
+
+        // Add a session
+        RoutingSessionInfo sessionInfo1 = new RoutingSessionInfo.Builder(
+                SESSION_ID_1, "" /* clientPackageName */)
+                .addSelectedRoute(ROUTE_ID1)
+                .build();
+        service.notifySessionCreated(sessionInfo1, MediaRoute2ProviderService.REQUEST_ID_UNKNOWN);
+        assertEquals(1, service.getAllSessionInfo().size());
+        assertEquals(sessionInfo1, service.getAllSessionInfo().get(0));
+        assertEquals(sessionInfo1, service.getSessionInfo(SESSION_ID_1));
+
+        // Add another session
+        RoutingSessionInfo sessionInfo2 = new RoutingSessionInfo.Builder(
+                SESSION_ID_2, "" /* clientPackageName */)
+                .addSelectedRoute(ROUTE_ID2)
+                .build();
+        service.notifySessionCreated(
+                sessionInfo2, MediaRoute2ProviderService.REQUEST_ID_UNKNOWN);
+        assertEquals(2, service.getAllSessionInfo().size());
+        assertEquals(sessionInfo2, service.getSessionInfo(SESSION_ID_2));
+
+        // Remove the first session
+        service.notifySessionReleased(SESSION_ID_1);
+        assertNull(service.getSessionInfo(SESSION_ID_1));
+        assertEquals(1, service.getAllSessionInfo().size());
+        assertEquals(sessionInfo2, service.getAllSessionInfo().get(0));
+        assertEquals(sessionInfo2, service.getSessionInfo(SESSION_ID_2));
+
+        // Remove the remaining session
+        service.notifySessionReleased(SESSION_ID_2);
+        assertEquals(0, service.getAllSessionInfo().size());
+        assertNull(service.getSessionInfo(SESSION_ID_2));
+    }
+
+    @Test
+    public void testNotifyRoutesInvokesMediaRouter2RouteCallback() throws Exception {
+        SampleMediaRoute2ProviderService service = mServiceInstance;
+        assertNotNull(service);
+
+        final String routeId0 = "routeId0";
+        final String routeName0 = "routeName0";
+        final String routeId1 = "routeId1";
+        final String routeName1 = "routeName1";
+        final List<String> features = Collections.singletonList("customFeature");
+
+        final List<MediaRoute2Info> routes = new ArrayList<>();
+        routes.add(new MediaRoute2Info.Builder(routeId0, routeName0)
+                .addFeatures(features)
+                .build());
+        routes.add(new MediaRoute2Info.Builder(routeId1, routeName1)
+                .addFeatures(features)
+                .build());
+
+        final int newConnectionState = MediaRoute2Info.CONNECTION_STATE_CONNECTED;
+        CountDownLatch onRoutesAddedLatch = new CountDownLatch(1);
+        CountDownLatch onRoutesChangedLatch = new CountDownLatch(1);
+        CountDownLatch onRoutesRemovedLatch = new CountDownLatch(1);
+        RouteCallback routeCallback = new RouteCallback() {
+            @Override
+            public void onRoutesAdded(List<MediaRoute2Info> routes) {
+                if (!features.equals(routes.get(0).getFeatures())) {
+                    return;
+                }
+                assertEquals(2, routes.size());
+
+                MediaRoute2Info route0;
+                MediaRoute2Info route1;
+                if (routeId0.equals(routes.get(0).getOriginalId())) {
+                    route0 = routes.get(0);
+                    route1 = routes.get(1);
+                } else {
+                    route0 = routes.get(1);
+                    route1 = routes.get(0);
+                }
+
+                assertNotNull(route0);
+                assertEquals(routeId0, route0.getOriginalId());
+                assertEquals(routeName0, route0.getName());
+                assertEquals(features, route0.getFeatures());
+
+                assertNotNull(route1);
+                assertEquals(routeId1, route1.getOriginalId());
+                assertEquals(routeName1, route1.getName());
+                assertEquals(features, route1.getFeatures());
+
+                onRoutesAddedLatch.countDown();
+            }
+
+            @Override
+            public void onRoutesChanged(List<MediaRoute2Info> routes) {
+                if (!features.equals(routes.get(0).getFeatures())) {
+                    return;
+                }
+                assertEquals(1, routes.size());
+                assertEquals(routeId1, routes.get(0).getOriginalId());
+                assertEquals(newConnectionState, routes.get(0).getConnectionState());
+                onRoutesChangedLatch.countDown();
+            }
+
+            @Override
+            public void onRoutesRemoved(List<MediaRoute2Info> routes) {
+                if (!features.equals(routes.get(0).getFeatures())) {
+                    return;
+                }
+                assertEquals(2, routes.size());
+
+                MediaRoute2Info route0;
+                MediaRoute2Info route1;
+                if (routeId0.equals(routes.get(0).getOriginalId())) {
+                    route0 = routes.get(0);
+                    route1 = routes.get(1);
+                } else {
+                    route0 = routes.get(1);
+                    route1 = routes.get(0);
+                }
+
+                assertNotNull(route0);
+                assertEquals(routeId0, route0.getOriginalId());
+                assertEquals(routeName0, route0.getName());
+                assertEquals(features, route0.getFeatures());
+
+                assertNotNull(route1);
+                assertEquals(routeId1, route1.getOriginalId());
+                assertEquals(routeName1, route1.getName());
+                assertEquals(features, route1.getFeatures());
+
+                onRoutesRemovedLatch.countDown();
+            }
+        };
+
+        mRouter2.registerRouteCallback(mExecutor, routeCallback,
+                new RouteDiscoveryPreference.Builder(features, true).build());
+        try {
+            service.notifyRoutes(routes);
+            assertTrue(onRoutesAddedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            // Change the connection state of route2 in order to invoke onRoutesChanged()
+            MediaRoute2Info newRoute2 = new MediaRoute2Info.Builder(routes.get(1))
+                    .setConnectionState(newConnectionState)
+                    .build();
+            routes.set(1, newRoute2);
+            service.notifyRoutes(routes);
+            assertTrue(onRoutesChangedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            // Now remove all the routes
+            routes.clear();
+            service.notifyRoutes(routes);
+            assertTrue(onRoutesRemovedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterRouteCallback(routeCallback);
+        }
+    }
+
+    @Test
+    public void testSessionRelatedCallbacks() throws Exception {
+        SampleMediaRoute2ProviderService service = mServiceInstance;
+        assertNotNull(service);
+        service.initializeRoutes();
+        service.publishRoutes();
+
+        List<String> featuresSample = Collections.singletonList(FEATURE_SAMPLE);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(featuresSample);
+        MediaRoute2Info routeToCreateSession = routes.get(ROUTE_ID1);
+        assertNotNull(routeToCreateSession);
+
+        Bundle sessionHints = new Bundle();
+        sessionHints.putString(TEST_KEY, TEST_VALUE);
+        mRouter2.setOnGetControllerHintsListener(route -> sessionHints);
+
+        CountDownLatch onCreateSessionLatch = new CountDownLatch(1);
+        CountDownLatch onReleaseSessionLatch = new CountDownLatch(1);
+        CountDownLatch onSelectRouteLatch = new CountDownLatch(1);
+        CountDownLatch onDeselectRouteLatch = new CountDownLatch(1);
+        CountDownLatch onTransferToRouteLatch = new CountDownLatch(1);
+
+        // Now test all session-related callbacks.
+        setProxy(new Proxy() {
+            @Override
+            public void onCreateSession(String packageName, String routeId, long requestId,
+                    Bundle sessionHints) {
+                assertEquals(mContext.getPackageName(), packageName);
+                assertEquals(ROUTE_ID1, routeId);
+                assertNotNull(sessionHints);
+                assertTrue(sessionHints.containsKey(TEST_KEY));
+                assertEquals(TEST_VALUE, sessionHints.getString(TEST_KEY));
+
+                RoutingSessionInfo info = new RoutingSessionInfo.Builder(
+                        SESSION_ID_1, mContext.getPackageName())
+                        .addSelectedRoute(ROUTE_ID1)
+                        .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .addTransferableRoute(ROUTE_ID5_TO_TRANSFER_TO)
+                        .build();
+                service.notifySessionCreated(info, requestId);
+                onCreateSessionLatch.countDown();
+            }
+
+            @Override
+            public void onSelectRoute(String sessionId, String routeId) {
+                assertEquals(SESSION_ID_1, sessionId);
+                assertEquals(ROUTE_ID4_TO_SELECT_AND_DESELECT, routeId);
+
+                RoutingSessionInfo oldInfo = service.getSessionInfo(SESSION_ID_1);
+                RoutingSessionInfo newInfo = new RoutingSessionInfo.Builder(oldInfo)
+                        .addSelectedRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .removeSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .addDeselectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .build();
+                service.notifySessionUpdated(newInfo);
+                onSelectRouteLatch.countDown();
+            }
+
+            @Override
+            public void onDeselectRoute(String sessionId, String routeId) {
+                assertEquals(SESSION_ID_1, sessionId);
+                assertEquals(ROUTE_ID4_TO_SELECT_AND_DESELECT, routeId);
+
+                RoutingSessionInfo oldInfo = service.getSessionInfo(SESSION_ID_1);
+                RoutingSessionInfo newInfo = new RoutingSessionInfo.Builder(oldInfo)
+                        .removeSelectedRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .removeDeselectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .build();
+                service.notifySessionUpdated(newInfo);
+                onDeselectRouteLatch.countDown();
+            }
+
+            @Override
+            public void onTransferToRoute(String sessionId, String routeId) {
+                assertEquals(SESSION_ID_1, sessionId);
+                assertEquals(ROUTE_ID5_TO_TRANSFER_TO, routeId);
+
+                RoutingSessionInfo oldInfo = service.getSessionInfo(SESSION_ID_1);
+                RoutingSessionInfo newInfo = new RoutingSessionInfo.Builder(oldInfo)
+                        .clearDeselectableRoutes()
+                        .clearSelectedRoutes()
+                        .clearDeselectableRoutes()
+                        .addSelectedRoute(ROUTE_ID5_TO_TRANSFER_TO)
+                        .build();
+                service.notifySessionUpdated(newInfo);
+                onTransferToRouteLatch.countDown();
+            }
+
+            @Override
+            public void onReleaseSession(String sessionId) {
+                assertEquals(SESSION_ID_1, sessionId);
+                service.notifySessionReleased(sessionId);
+                onReleaseSessionLatch.countDown();
+            }
+        });
+
+
+        CountDownLatch onControllerCreatedLatch = new CountDownLatch(1);
+        CountDownLatch onControllerUpdatedForSelectLatch = new CountDownLatch(1);
+        CountDownLatch onControllerUpdatedForDeselectLatch = new CountDownLatch(1);
+        CountDownLatch onControllerUpdatedForTransferLatch = new CountDownLatch(1);
+        List<RoutingController> controllers = new ArrayList<>();
+
+        TransferCallback transferCallback = new TransferCallback() {
+            @Override
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                // TODO: Make RoutingController#getOriginalId() as @TestApi and use it.
+                if (newController != null
+                        && ROUTE_ID1.equals(newController
+                        .getSelectedRoutes().get(0).getOriginalId())) {
+                    controllers.add(newController);
+                    onControllerCreatedLatch.countDown();
+                }
+            }
+        };
+
+        ControllerCallback controllerCallback = new ControllerCallback() {
+            @Override
+            public void onControllerUpdated(RoutingController controller) {
+                List<MediaRoute2Info> selectedRoutes = controller.getSelectedRoutes();
+                if (onControllerUpdatedForSelectLatch.getCount() > 0) {
+                    if (selectedRoutes.size() == 2
+                            && ROUTE_ID4_TO_SELECT_AND_DESELECT.equals(
+                            selectedRoutes.get(1).getOriginalId())) {
+                        onControllerUpdatedForSelectLatch.countDown();
+                    }
+                } else if (onControllerUpdatedForDeselectLatch.getCount() > 0) {
+                    if (selectedRoutes.size() == 1
+                            && ROUTE_ID1.equals(selectedRoutes.get(0).getOriginalId())) {
+                        onControllerUpdatedForDeselectLatch.countDown();
+                    }
+                } else if (onControllerUpdatedForTransferLatch.getCount() > 0) {
+                    if (selectedRoutes.size() == 1
+                            && ROUTE_ID5_TO_TRANSFER_TO.equals(
+                            selectedRoutes.get(0).getOriginalId())) {
+                        onControllerUpdatedForTransferLatch.countDown();
+                    }
+                }
+            }
+        };
+
+        // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
+        RouteCallback dummyCallback = new RouteCallback();
+        try {
+            mRouter2.registerRouteCallback(mExecutor, dummyCallback,
+                    new RouteDiscoveryPreference.Builder(new ArrayList<>(), true).build());
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
+
+            mRouter2.transferTo(routeToCreateSession);
+            assertTrue(onCreateSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertFalse(controllers.isEmpty());
+
+            RoutingController controller = controllers.get(0);
+
+            controller.selectRoute(routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
+            assertTrue(onSelectRouteLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(onControllerUpdatedForSelectLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            controller.deselectRoute(routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT));
+            assertTrue(onDeselectRouteLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(onControllerUpdatedForDeselectLatch.await(
+                    TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            mRouter2.transferTo(routes.get(ROUTE_ID5_TO_TRANSFER_TO));
+            assertTrue(onTransferToRouteLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(onControllerUpdatedForTransferLatch.await(
+                    TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            controller.release();
+            assertTrue(onReleaseSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterRouteCallback(dummyCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
+            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.setOnGetControllerHintsListener(null);
+            releaseControllers(mRouter2.getControllers());
+        }
+    }
+
+    @Test
+    public void testNotifySessionReleased() throws Exception {
+        SampleMediaRoute2ProviderService service = mServiceInstance;
+        assertNotNull(service);
+        service.initializeRoutes();
+        service.publishRoutes();
+
+        List<String> featuresSample = Collections.singletonList(FEATURE_SAMPLE);
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(featuresSample);
+        MediaRoute2Info routeToCreateSession = routes.get(ROUTE_ID1);
+        assertNotNull(routeToCreateSession);
+
+        CountDownLatch onCreateSessionLatch = new CountDownLatch(1);
+        setProxy(new Proxy() {
+            @Override
+            public void onCreateSession(String packageName, String routeId, long requestId,
+                    Bundle sessionHints) {
+                assertEquals(mContext.getPackageName(), packageName);
+                assertEquals(ROUTE_ID1, routeId);
+                assertNull(sessionHints);
+
+                RoutingSessionInfo info = new RoutingSessionInfo.Builder(
+                        SESSION_ID_1, mContext.getPackageName())
+                        .addSelectedRoute(ROUTE_ID1)
+                        .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
+                        .addTransferableRoute(ROUTE_ID5_TO_TRANSFER_TO)
+                        .build();
+                service.notifySessionCreated(info, requestId);
+                onCreateSessionLatch.countDown();
+            }
+        });
+
+
+        CountDownLatch onControllerCreatedLatch = new CountDownLatch(1);
+        CountDownLatch onControllerReleasedLatch = new CountDownLatch(1);
+        List<RoutingController> controllers = new ArrayList<>();
+
+        TransferCallback transferCallback = new TransferCallback() {
+            @Override
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                // TODO: Make RoutingController#getOriginalId() as @TestApi and use it.
+                if (newController != null) {
+                    if (ROUTE_ID1.equals(newController
+                            .getSelectedRoutes().get(0).getOriginalId())) {
+                        controllers.add(newController);
+                        onControllerCreatedLatch.countDown();
+                    }
+                } else {
+                    if (ROUTE_ID1.equals(oldController
+                            .getSelectedRoutes().get(0).getOriginalId())) {
+                        assertTrue(oldController.isReleased());
+                        onControllerReleasedLatch.countDown();
+                    }
+                }
+            }
+        };
+
+        // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
+        RouteCallback dummyCallback = new RouteCallback();
+        try {
+            mRouter2.registerRouteCallback(mExecutor, dummyCallback,
+                    new RouteDiscoveryPreference.Builder(new ArrayList<>(), true).build());
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+
+            mRouter2.transferTo(routeToCreateSession);
+            assertTrue(onCreateSessionLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            assertFalse(controllers.isEmpty());
+
+            service.notifySessionReleased(SESSION_ID_1);
+            assertTrue(onControllerReleasedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterRouteCallback(dummyCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
+            releaseControllers(mRouter2.getControllers());
+        }
+    }
+
+
+    @Test
     public void testOnDiscoveryPreferenceChanged() throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
         CountDownLatch latch2 = new CountDownLatch(1);
 
-        MediaRouter2.RouteCallback routeCallback = new MediaRouter2.RouteCallback();
-        MediaRouter2.RouteCallback routeCallback2 = new MediaRouter2.RouteCallback();
+        RouteCallback routeCallback = new RouteCallback();
+        RouteCallback routeCallback2 = new RouteCallback();
 
         List<String> featuresSample = Collections.singletonList(FEATURE_SAMPLE);
         List<String> featuresSpecial = Collections.singletonList(FEATURE_SPECIAL);
@@ -78,7 +535,7 @@
             public void onDiscoveryPreferenceChanged(RouteDiscoveryPreference preference) {
                 List<String> features = preference.getPreferredFeatures();
                 if (features.contains(FEATURE_SAMPLE) && features.contains(FEATURE_SPECIAL)
-                        && preference.isActiveScan()) {
+                        && preference.shouldPerformActiveScan()) {
                     latch.countDown();
                 }
                 if (latch.getCount() == 0 && !features.contains(FEATURE_SAMPLE)
@@ -107,4 +564,39 @@
             instance.setProxy(proxy);
         }
     }
+
+    Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> features)
+            throws Exception {
+        CountDownLatch latch = new CountDownLatch(1);
+
+        RouteCallback routeCallback = new RouteCallback() {
+            @Override
+            public void onRoutesAdded(List<MediaRoute2Info> routes) {
+                for (MediaRoute2Info route : routes) {
+                    if (!route.isSystemRoute()) {
+                        latch.countDown();
+                    }
+                }
+            }
+        };
+
+        mRouter2.registerRouteCallback(mExecutor, routeCallback,
+                new RouteDiscoveryPreference.Builder(features, true).build());
+        try {
+            latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            return createRouteMap(mRouter2.getRoutes());
+        } finally {
+            mRouter2.unregisterRouteCallback(routeCallback);
+        }
+    }
+
+    // Helper for getting routes easily. Uses original ID as a key
+    static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
+        Map<String, MediaRoute2Info> routeMap = new HashMap<>();
+        for (MediaRoute2Info route : routes) {
+            routeMap.put(route.getOriginalId(), route);
+        }
+        return routeMap;
+    }
+
 }
diff --git a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
index 5189649..c73a447 100644
--- a/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
+++ b/tests/tests/media/src/android/media/cts/MediaRouter2Test.java
@@ -17,6 +17,7 @@
 package android.media.cts;
 
 import static android.content.Context.AUDIO_SERVICE;
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
 import static android.media.cts.SampleMediaRoute2ProviderService.FEATURES_SPECIAL;
 import static android.media.cts.SampleMediaRoute2ProviderService.FEATURE_SAMPLE;
 import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID1;
@@ -25,7 +26,6 @@
 import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID4_TO_SELECT_AND_DESELECT;
 import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID5_TO_TRANSFER_TO;
 import static android.media.cts.SampleMediaRoute2ProviderService.ROUTE_ID_SPECIAL_FEATURE;
-import static android.media.cts.SampleMediaRoute2ProviderService.SYSTEM_PROVIDER_ID;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -40,15 +40,20 @@
 import android.media.AudioManager;
 import android.media.MediaRoute2Info;
 import android.media.MediaRouter2;
+import android.media.MediaRouter2.ControllerCallback;
 import android.media.MediaRouter2.OnGetControllerHintsListener;
 import android.media.MediaRouter2.RouteCallback;
 import android.media.MediaRouter2.RoutingController;
-import android.media.MediaRouter2.RoutingControllerCallback;
+import android.media.MediaRouter2.TransferCallback;
 import android.media.RouteDiscoveryPreference;
 import android.os.Bundle;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.LargeTest;
 import android.text.TextUtils;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -63,11 +68,6 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
-import java.util.stream.Collectors;
-
-import androidx.test.InstrumentationRegistry;
-import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
 
 @RunWith(AndroidJUnit4.class)
 @AppModeFull(reason = "The system should be able to bind to SampleMediaRoute2ProviderService")
@@ -78,12 +78,15 @@
     private MediaRouter2 mRouter2;
     private Executor mExecutor;
     private AudioManager mAudioManager;
+    private SampleMediaRoute2ProviderService mServiceInstance;
 
     private static final int TIMEOUT_MS = 5000;
     private static final int WAIT_MS = 2000;
 
     private static final String TEST_KEY = "test_key";
     private static final String TEST_VALUE = "test_value";
+    private static final RouteDiscoveryPreference EMPTY_DISCOVERY_PREFERENCE =
+            new RouteDiscoveryPreference.Builder(Collections.emptyList(), false).build();
 
     @Before
     public void setUp() throws Exception {
@@ -91,10 +94,20 @@
         mRouter2 = MediaRouter2.getInstance(mContext);
         mExecutor = Executors.newSingleThreadExecutor();
         mAudioManager = (AudioManager) mContext.getSystemService(AUDIO_SERVICE);
+
+        mServiceInstance = SampleMediaRoute2ProviderService.getInstance();
+        if (mServiceInstance != null) {
+            mServiceInstance.initializeRoutes();
+            mServiceInstance.publishRoutes();
+        }
     }
 
     @After
     public void tearDown() throws Exception {
+        if (mServiceInstance != null) {
+            mServiceInstance.clear();
+            mServiceInstance = null;
+        }
     }
 
     /**
@@ -121,45 +134,28 @@
     }
 
     @Test
-    public void testRegisterControllerCallbackWithInvalidArguments() {
+    public void testRegisterTransferCallbackWithInvalidArguments() {
         Executor executor = mExecutor;
-        RoutingControllerCallback callback = new RoutingControllerCallback();
+        TransferCallback callback = new TransferCallback();
 
         // Tests null executor
         assertThrows(NullPointerException.class,
-                () -> mRouter2.registerControllerCallback(null, callback));
+                () -> mRouter2.registerTransferCallback(null, callback));
 
         // Tests null callback
         assertThrows(NullPointerException.class,
-                () -> mRouter2.registerControllerCallback(executor, null));
+                () -> mRouter2.registerTransferCallback(executor, null));
     }
 
     @Test
-    public void testUnregisterControllerCallbackWithNullCallback() {
+    public void testUnregisterTransferCallbackWithNullCallback() {
         // Tests null callback
         assertThrows(NullPointerException.class,
-                () -> mRouter2.unregisterControllerCallback(null));
+                () -> mRouter2.unregisterTransferCallback(null));
     }
 
     @Test
-    public void testRequestCreateControllerWithNullRoute() {
-        assertThrows(NullPointerException.class,
-                () -> mRouter2.requestCreateController(null));
-    }
-
-    @Test
-    public void testRequestCreateControllerWithSystemRoute() {
-        List<MediaRoute2Info> systemRoutes =
-            mRouter2.getRoutes().stream().filter(r -> r.isSystemRoute())
-                    .collect(Collectors.toList());
-
-        assertFalse(systemRoutes.isEmpty());
-        assertThrows(IllegalArgumentException.class,
-                () -> mRouter2.requestCreateController(systemRoutes.get(0)));
-    }
-
-    @Test
-    public void testRequestCreateControllerSuccess() throws Exception {
+    public void testTransferToSuccess() throws Exception {
         final List<String> sampleRouteFeature = new ArrayList<>();
         sampleRouteFeature.add(FEATURE_SAMPLE);
 
@@ -172,29 +168,31 @@
         final List<RoutingController> controllers = new ArrayList<>();
 
         // Create session with this route
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback controllerCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                assertNotNull(controller);
-                assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(
-                        ROUTE_ID1));
-                controllers.add(controller);
-                successLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(createRouteMap(newController.getSelectedRoutes()).containsKey(
+                            ROUTE_ID1));
+                    controllers.add(newController);
+                    successLatch.countDown();
+                }
             }
 
             @Override
-            public void onControllerCreationFailed(MediaRoute2Info requestedRoute) {
+            public void onTransferFailed(MediaRoute2Info requestedRoute) {
                 failureLatch.countDown();
             }
         };
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
-            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(route);
+            mRouter2.registerTransferCallback(mExecutor, controllerCallback);
+            mRouter2.transferTo(route);
             assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
             // onSessionCreationFailed should not be called.
@@ -202,12 +200,12 @@
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
-            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(controllerCallback);
         }
     }
 
     @Test
-    public void testRequestCreateControllerFailure() throws Exception {
+    public void testTransferToFailure() throws Exception {
         final List<String> sampleRouteType = new ArrayList<>();
         sampleRouteType.add(FEATURE_SAMPLE);
 
@@ -220,15 +218,18 @@
         final List<RoutingController> controllers = new ArrayList<>();
 
         // Create session with this route
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                controllers.add(controller);
-                successLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    controllers.add(newController);
+                    successLatch.countDown();
+                }
             }
 
             @Override
-            public void onControllerCreationFailed(MediaRoute2Info requestedRoute) {
+            public void onTransferFailed(MediaRoute2Info requestedRoute) {
                 assertEquals(route, requestedRoute);
                 failureLatch.countDown();
             }
@@ -236,41 +237,49 @@
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
-            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(route);
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.transferTo(route);
             assertTrue(failureLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-            // onSessionCreated should not be called.
+            // onTransferred should not be called.
             assertFalse(successLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
-            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
         }
     }
 
     @Test
-    public void testRequestCreateControllerMultipleSessions() throws Exception {
+    public void testTransferToTwice() throws Exception {
         final List<String> sampleRouteType = new ArrayList<>();
         sampleRouteType.add(FEATURE_SAMPLE);
 
-        final CountDownLatch successLatch = new CountDownLatch(2);
+        final CountDownLatch successLatch1 = new CountDownLatch(1);
+        final CountDownLatch successLatch2 = new CountDownLatch(1);
         final CountDownLatch failureLatch = new CountDownLatch(1);
         final List<RoutingController> createdControllers = new ArrayList<>();
 
         // Create session with this route
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                createdControllers.add(controller);
-                successLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    createdControllers.add(newController);
+                    if (successLatch1.getCount() > 0) {
+                        successLatch1.countDown();
+                    } else {
+                        successLatch2.countDown();
+                    }
+                }
             }
 
             @Override
-            public void onControllerCreationFailed(MediaRoute2Info requestedRoute) {
+            public void onTransferFailed(MediaRoute2Info requestedRoute) {
                 failureLatch.countDown();
             }
         };
@@ -283,15 +292,16 @@
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
-            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(route1);
-            mRouter2.requestCreateController(route2);
-            assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.transferTo(route1);
+            assertTrue(successLatch1.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            mRouter2.transferTo(route2);
+            assertTrue(successLatch2.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
-            // onSessionCreationFailed should not be called.
+            // onTransferFailed should not be called.
             assertFalse(failureLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
 
             // Created controllers should have proper info
@@ -299,6 +309,9 @@
             RoutingController controller1 = createdControllers.get(0);
             RoutingController controller2 = createdControllers.get(1);
 
+            // The first controller is expected to be released.
+            assertTrue(controller1.isReleased());
+
             assertNotEquals(controller1.getId(), controller2.getId());
             assertTrue(createRouteMap(controller1.getSelectedRoutes()).containsKey(
                     ROUTE_ID1));
@@ -308,7 +321,7 @@
         } finally {
             releaseControllers(createdControllers);
             mRouter2.unregisterRouteCallback(routeCallback);
-            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
         }
     }
 
@@ -321,55 +334,52 @@
         MediaRoute2Info route = routes.get(ROUTE_ID1);
         assertNotNull(route);
 
-        final Bundle createSessionHints = new Bundle();
-        createSessionHints.putString(TEST_KEY, TEST_VALUE);
-        final OnGetControllerHintsListener listener = new OnGetControllerHintsListener() {
-            @Override
-            public Bundle onGetControllerHints(MediaRoute2Info route) {
-                return createSessionHints;
-            }
-        };
+        final Bundle controllerHints = new Bundle();
+        controllerHints.putString(TEST_KEY, TEST_VALUE);
+        final OnGetControllerHintsListener listener = route1 -> controllerHints;
 
         final CountDownLatch successLatch = new CountDownLatch(1);
         final CountDownLatch failureLatch = new CountDownLatch(1);
         final List<RoutingController> controllers = new ArrayList<>();
 
         // Create session with this route
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                assertNotNull(controller);
-                assertTrue(createRouteMap(controller.getSelectedRoutes()).containsKey(
-                        ROUTE_ID1));
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(createRouteMap(newController.getSelectedRoutes()).containsKey(
+                            ROUTE_ID1));
 
-                // The SampleMediaRoute2ProviderService supposed to set control hints
-                // with the given creationSessionHints.
-                Bundle controlHints = controller.getControlHints();
-                assertNotNull(controlHints);
-                assertTrue(controlHints.containsKey(TEST_KEY));
-                assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY));
+                    // The SampleMediaRoute2ProviderService is supposed to set control hints
+                    // with the given controllerHints.
+                    Bundle controlHints = newController.getControlHints();
+                    assertNotNull(controlHints);
+                    assertTrue(controlHints.containsKey(TEST_KEY));
+                    assertEquals(TEST_VALUE, controlHints.getString(TEST_KEY));
 
-                controllers.add(controller);
-                successLatch.countDown();
+                    controllers.add(newController);
+                    successLatch.countDown();
+                }
             }
 
             @Override
-            public void onControllerCreationFailed(MediaRoute2Info requestedRoute) {
+            public void onTransferFailed(MediaRoute2Info requestedRoute) {
                 failureLatch.countDown();
             }
         };
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
-            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
 
             // The SampleMediaRoute2ProviderService supposed to set control hints
             // with the given creationSessionHints.
             mRouter2.setOnGetControllerHintsListener(listener);
-            mRouter2.requestCreateController(route);
+            mRouter2.transferTo(route);
             assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
             // onSessionCreationFailed should not be called.
@@ -377,12 +387,85 @@
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
+        }
+    }
+
+    @Test
+    public void testSetSessionVolume() throws Exception {
+        List<String> sampleRouteFeature = new ArrayList<>();
+        sampleRouteFeature.add(FEATURE_SAMPLE);
+
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteFeature);
+        MediaRoute2Info route = routes.get(ROUTE_ID1);
+        assertNotNull(route);
+
+        CountDownLatch successLatch = new CountDownLatch(1);
+        CountDownLatch volumeChangedLatch = new CountDownLatch(1);
+
+        List<RoutingController> controllers = new ArrayList<>();
+
+        // Create session with this route
+        TransferCallback transferCallback = new TransferCallback() {
+            @Override
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    controllers.add(newController);
+                    successLatch.countDown();
+                }
+            }
+        };
+
+        // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
+        RouteCallback routeCallback = new RouteCallback();
+
+        try {
+            mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.transferTo(route);
+
+            assertTrue(successLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            mRouter2.unregisterTransferCallback(transferCallback);
+            mRouter2.unregisterRouteCallback(routeCallback);
+        }
+
+        assertEquals(1, controllers.size());
+        // test requestSetSessionVolume
+
+        RoutingController targetController = controllers.get(0);
+        assertEquals(PLAYBACK_VOLUME_VARIABLE, targetController.getVolumeHandling());
+        int currentVolume = targetController.getVolume();
+        int maxVolume = targetController.getVolumeMax();
+        int targetVolume = (currentVolume == maxVolume) ? currentVolume - 1 : (currentVolume + 1);
+
+        ControllerCallback controllerCallback = new ControllerCallback() {
+            @Override
+            public void onControllerUpdated(MediaRouter2.RoutingController controller) {
+                if (!TextUtils.equals(targetController.getId(), controller.getId())) {
+                    return;
+                }
+                if (controller.getVolume() == targetVolume) {
+                    volumeChangedLatch.countDown();
+                }
+            }
+        };
+
+        try {
+            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
+            mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
+            targetController.setVolume(targetVolume);
+            assertTrue(volumeChangedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            releaseControllers(controllers);
+            mRouter2.unregisterRouteCallback(routeCallback);
             mRouter2.unregisterControllerCallback(controllerCallback);
         }
     }
 
     @Test
-    public void testRoutingControllerCallbackIsNotCalledAfterUnregistered() throws Exception {
+    public void testTransferCallbackIsNotCalledAfterUnregistered() throws Exception {
         final List<String> sampleRouteType = new ArrayList<>();
         sampleRouteType.add(FEATURE_SAMPLE);
 
@@ -395,37 +478,40 @@
         final List<RoutingController> controllers = new ArrayList<>();
 
         // Create session with this route
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                controllers.add(controller);
-                successLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    controllers.add(newController);
+                    successLatch.countDown();
+                }
             }
 
             @Override
-            public void onControllerCreationFailed(MediaRoute2Info requestedRoute) {
+            public void onTransferFailed(MediaRoute2Info requestedRoute) {
                 failureLatch.countDown();
             }
         };
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
-            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(route);
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.transferTo(route);
 
-            // Unregisters session callback
-            mRouter2.unregisterControllerCallback(controllerCallback);
+            // Unregisters transfer callback
+            mRouter2.unregisterTransferCallback(transferCallback);
 
-            // No session callback methods should be called.
+            // No transfer callback methods should be called.
             assertFalse(successLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
             assertFalse(failureLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
-            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
         }
     }
 
@@ -436,30 +522,34 @@
         sampleRouteType.add(FEATURE_SAMPLE);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
-        MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
-        assertNotNull(routeToCreateSessionWith);
+        MediaRoute2Info routeToBegin = routes.get(ROUTE_ID1);
+        assertNotNull(routeToBegin);
 
-        final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1);
+        final CountDownLatch onTransferredLatch = new CountDownLatch(1);
         final CountDownLatch onControllerUpdatedLatchForSelect = new CountDownLatch(1);
         final CountDownLatch onControllerUpdatedLatchForDeselect = new CountDownLatch(1);
         final List<RoutingController> controllers = new ArrayList<>();
 
-        // Create session with ROUTE_ID1
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
-            @Override
-            public void onControllerCreated(RoutingController controller) {
-                assertNotNull(controller);
-                assertTrue(getOriginalRouteIds(controller.getSelectedRoutes()).contains(
-                        ROUTE_ID1));
-                controllers.add(controller);
-                onControllerCreatedLatch.countDown();
-            }
 
+        // Create session with ROUTE_ID1
+        TransferCallback transferCallback = new TransferCallback() {
+            @Override
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(getOriginalRouteIds(newController.getSelectedRoutes()).contains(
+                            ROUTE_ID1));
+                    controllers.add(newController);
+                    onTransferredLatch.countDown();
+                }
+            }
+        };
+
+        ControllerCallback controllerCallback = new ControllerCallback() {
             @Override
             public void onControllerUpdated(RoutingController controller) {
-                if (onControllerCreatedLatch.getCount() != 0
-                        || !TextUtils.equals(
-                                controllers.get(0).getId(), controller.getId())) {
+                if (onTransferredLatch.getCount() != 0
+                        || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) {
                     return;
                 }
 
@@ -491,14 +581,16 @@
             }
         };
 
+
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
             mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(routeToCreateSessionWith);
-            assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            mRouter2.transferTo(routeToBegin);
+            assertTrue(onTransferredLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
             assertEquals(1, controllers.size());
             RoutingController controller = controllers.get(0);
@@ -519,6 +611,7 @@
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
             mRouter2.unregisterControllerCallback(controllerCallback);
         }
     }
@@ -529,29 +622,32 @@
         sampleRouteType.add(FEATURE_SAMPLE);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
-        MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
-        assertNotNull(routeToCreateSessionWith);
+        MediaRoute2Info routeToBegin = routes.get(ROUTE_ID1);
+        assertNotNull(routeToBegin);
 
-        final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1);
+        final CountDownLatch onTransferredLatch = new CountDownLatch(1);
         final CountDownLatch onControllerUpdatedLatch = new CountDownLatch(1);
         final List<RoutingController> controllers = new ArrayList<>();
 
         // Create session with ROUTE_ID1
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                assertNotNull(controller);
-                assertTrue(getOriginalRouteIds(controller.getSelectedRoutes()).contains(
-                        ROUTE_ID1));
-                controllers.add(controller);
-                onControllerCreatedLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(getOriginalRouteIds(newController.getSelectedRoutes()).contains(
+                            ROUTE_ID1));
+                    controllers.add(newController);
+                    onTransferredLatch.countDown();
+                }
             }
+        };
 
+        ControllerCallback controllerCallback = new ControllerCallback() {
             @Override
             public void onControllerUpdated(RoutingController controller) {
-                if (onControllerCreatedLatch.getCount() != 0
-                        || !TextUtils.equals(
-                                controllers.get(0).getId(), controller.getId())) {
+                if (onTransferredLatch.getCount() != 0
+                        || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) {
                     return;
                 }
                 assertEquals(1, controller.getSelectedRoutes().size());
@@ -559,37 +655,103 @@
                         ROUTE_ID1));
                 assertTrue(getOriginalRouteIds(controller.getSelectedRoutes())
                         .contains(ROUTE_ID5_TO_TRANSFER_TO));
-                assertFalse(getOriginalRouteIds(controller.getTransferrableRoutes())
-                        .contains(ROUTE_ID5_TO_TRANSFER_TO));
-
                 onControllerUpdatedLatch.countDown();
             }
         };
 
         // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
             mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(routeToCreateSessionWith);
-            assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            mRouter2.transferTo(routeToBegin);
+            assertTrue(onTransferredLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
             assertEquals(1, controllers.size());
             RoutingController controller = controllers.get(0);
-            assertTrue(getOriginalRouteIds(controller.getTransferrableRoutes())
-                    .contains(ROUTE_ID5_TO_TRANSFER_TO));
 
             // Transfer to ROUTE_ID5_TO_TRANSFER_TO
             MediaRoute2Info routeToTransferTo = routes.get(ROUTE_ID5_TO_TRANSFER_TO);
             assertNotNull(routeToTransferTo);
 
-            controller.transferToRoute(routeToTransferTo);
+            mRouter2.transferTo(routeToTransferTo);
             assertTrue(onControllerUpdatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
         } finally {
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
             mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
+        }
+    }
+
+    @Test
+    public void testControllerCallbackUnregister() throws Exception {
+        final List<String> sampleRouteType = new ArrayList<>();
+        sampleRouteType.add(FEATURE_SAMPLE);
+
+        Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
+        MediaRoute2Info routeToBegin = routes.get(ROUTE_ID1);
+        assertNotNull(routeToBegin);
+
+        final CountDownLatch onTransferredLatch = new CountDownLatch(1);
+        final CountDownLatch onControllerUpdatedLatch = new CountDownLatch(1);
+        final List<RoutingController> controllers = new ArrayList<>();
+
+        // Create session with ROUTE_ID1
+        TransferCallback transferCallback = new TransferCallback() {
+            @Override
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(getOriginalRouteIds(newController.getSelectedRoutes()).contains(
+                            ROUTE_ID1));
+                    controllers.add(newController);
+                    onTransferredLatch.countDown();
+                }
+            }
+        };
+        ControllerCallback controllerCallback = new ControllerCallback() {
+            @Override
+            public void onControllerUpdated(RoutingController controller) {
+                if (onTransferredLatch.getCount() != 0
+                        || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) {
+                    return;
+                }
+                assertEquals(1, controller.getSelectedRoutes().size());
+                assertFalse(getOriginalRouteIds(controller.getSelectedRoutes()).contains(
+                        ROUTE_ID1));
+                assertTrue(getOriginalRouteIds(controller.getSelectedRoutes())
+                        .contains(ROUTE_ID5_TO_TRANSFER_TO));
+                onControllerUpdatedLatch.countDown();
+            }
+        };
+
+        // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
+        RouteCallback routeCallback = new RouteCallback();
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
+
+        try {
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
+            mRouter2.registerControllerCallback(mExecutor, controllerCallback);
+            mRouter2.transferTo(routeToBegin);
+            assertTrue(onTransferredLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+
+            assertEquals(1, controllers.size());
+
+            // Transfer to ROUTE_ID5_TO_TRANSFER_TO
+            MediaRoute2Info routeToTransferTo = routes.get(ROUTE_ID5_TO_TRANSFER_TO);
+            assertNotNull(routeToTransferTo);
+
+            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.transferTo(routeToTransferTo);
+            assertFalse(onControllerUpdatedLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
+        } finally {
+            releaseControllers(controllers);
+            mRouter2.unregisterRouteCallback(routeCallback);
+            mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
         }
     }
 
@@ -601,68 +763,68 @@
         sampleRouteType.add(FEATURE_SAMPLE);
 
         Map<String, MediaRoute2Info> routes = waitAndGetRoutes(sampleRouteType);
-        MediaRoute2Info routeToCreateSessionWith = routes.get(ROUTE_ID1);
-        assertNotNull(routeToCreateSessionWith);
+        MediaRoute2Info routeTransferFrom = routes.get(ROUTE_ID1);
+        assertNotNull(routeTransferFrom);
 
-        final CountDownLatch onControllerCreatedLatch = new CountDownLatch(1);
+        final CountDownLatch onTransferredLatch = new CountDownLatch(1);
         final CountDownLatch onControllerUpdatedLatch = new CountDownLatch(1);
         final CountDownLatch onControllerReleasedLatch = new CountDownLatch(1);
         final List<RoutingController> controllers = new ArrayList<>();
 
-        // Create session with ROUTE_ID1
-        RoutingControllerCallback controllerCallback = new RoutingControllerCallback() {
+        TransferCallback transferCallback = new TransferCallback() {
             @Override
-            public void onControllerCreated(RoutingController controller) {
-                assertNotNull(controller);
-                assertTrue(getOriginalRouteIds(controller.getSelectedRoutes()).contains(
-                        ROUTE_ID1));
-                controllers.add(controller);
-                onControllerCreatedLatch.countDown();
+            public void onTransferred(RoutingController oldController,
+                    RoutingController newController) {
+                if (newController != null) {
+                    assertTrue(getOriginalRouteIds(newController.getSelectedRoutes()).contains(
+                            ROUTE_ID1));
+                    controllers.add(newController);
+                    onTransferredLatch.countDown();
+                } else {
+                    if (onTransferredLatch.getCount() != 0
+                            || !TextUtils.equals(
+                                    controllers.get(0).getId(), oldController.getId())) {
+                        return;
+                    }
+                    onControllerReleasedLatch.countDown();
+                }
             }
+        };
 
+        ControllerCallback controllerCallback = new ControllerCallback() {
             @Override
             public void onControllerUpdated(RoutingController controller) {
-                if (onControllerCreatedLatch.getCount() != 0
+                if (onTransferredLatch.getCount() != 0
                         || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) {
                     return;
                 }
                 onControllerUpdatedLatch.countDown();
             }
-
-            @Override
-            public void onControllerReleased(RoutingController controller) {
-                if (onControllerCreatedLatch.getCount() != 0
-                        || !TextUtils.equals(controllers.get(0).getId(), controller.getId())) {
-                    return;
-                }
-                onControllerReleasedLatch.countDown();
-            }
         };
 
-        // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
+       // TODO: Remove this once the MediaRouter2 becomes always connected to the service.
         RouteCallback routeCallback = new RouteCallback();
-        mRouter2.registerRouteCallback(mExecutor, routeCallback, RouteDiscoveryPreference.EMPTY);
+        mRouter2.registerRouteCallback(mExecutor, routeCallback, EMPTY_DISCOVERY_PREFERENCE);
 
         try {
+            mRouter2.registerTransferCallback(mExecutor, transferCallback);
             mRouter2.registerControllerCallback(mExecutor, controllerCallback);
-            mRouter2.requestCreateController(routeToCreateSessionWith);
-            assertTrue(onControllerCreatedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
+            mRouter2.transferTo(routeTransferFrom);
+            assertTrue(onTransferredLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS));
 
             assertEquals(1, controllers.size());
             RoutingController controller = controllers.get(0);
-            assertTrue(getOriginalRouteIds(controller.getTransferrableRoutes())
-                    .contains(ROUTE_ID5_TO_TRANSFER_TO));
 
             // Release controller. Future calls should be ignored.
             controller.release();
 
-            // Transfer to ROUTE_ID5_TO_TRANSFER_TO
-            MediaRoute2Info routeToTransferTo = routes.get(ROUTE_ID5_TO_TRANSFER_TO);
-            assertNotNull(routeToTransferTo);
+            // Select ROUTE_ID5_TO_TRANSFER_TO
+            MediaRoute2Info routeToSelect = routes.get(ROUTE_ID4_TO_SELECT_AND_DESELECT);
+            assertNotNull(routeToSelect);
 
             // This call should be ignored.
             // The onSessionInfoChanged() shouldn't be called.
-            controller.transferToRoute(routeToTransferTo);
+            controller.selectRoute(routeToSelect);
             assertFalse(onControllerUpdatedLatch.await(WAIT_MS, TimeUnit.MILLISECONDS));
 
             // onControllerReleased should be called.
@@ -671,6 +833,7 @@
             releaseControllers(controllers);
             mRouter2.unregisterRouteCallback(routeCallback);
             mRouter2.unregisterControllerCallback(controllerCallback);
+            mRouter2.unregisterTransferCallback(transferCallback);
         }
     }
 
@@ -720,7 +883,7 @@
 
         assertEquals(maxVolume, selectedSystemRoute.getVolumeMax());
         assertEquals(originalVolume, selectedSystemRoute.getVolume());
-        assertEquals(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE,
+        assertEquals(PLAYBACK_VOLUME_VARIABLE,
                 selectedSystemRoute.getVolumeHandling());
 
         final int targetVolume = originalVolume == minVolume
@@ -757,25 +920,22 @@
         // we have tests for them. This method just directly calls those methods so that the tool
         // can recognize the callback methods as tested.
 
-        // TODO: Uncomment this when the RouteCallback is properly tested.
-        // MediaRouter2.RouteCallback routeCallback = new MediaRouter2.RouteCallback();
-        // routeCallback.onRoutesAdded(null);
-        // routeCallback.onRoutesChanged(null);
-        // routeCallback.onRoutesRemoved(null);
+        MediaRouter2.RouteCallback routeCallback = new MediaRouter2.RouteCallback();
+        routeCallback.onRoutesAdded(null);
+        routeCallback.onRoutesChanged(null);
+        routeCallback.onRoutesRemoved(null);
 
-        MediaRouter2.RoutingControllerCallback controllerCallback =
-                new MediaRouter2.RoutingControllerCallback();
-        controllerCallback.onControllerCreated(null);
-        controllerCallback.onControllerCreationFailed(null);
-        controllerCallback.onControllerUpdated(null);
-        controllerCallback.onControllerReleased(null);
+        MediaRouter2.TransferCallback transferCallback =
+                new MediaRouter2.TransferCallback();
+        transferCallback.onTransferred(null, null);
+        transferCallback.onTransferFailed(null);
 
         OnGetControllerHintsListener listener = route -> null;
         listener.onGetControllerHints(null);
     }
 
     // Helper for getting routes easily. Uses original ID as a key
-    static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
+    private static Map<String, MediaRoute2Info> createRouteMap(List<MediaRoute2Info> routes) {
         Map<String, MediaRoute2Info> routeMap = new HashMap<>();
         for (MediaRoute2Info route : routes) {
             routeMap.put(route.getOriginalId(), route);
@@ -783,16 +943,15 @@
         return routeMap;
     }
 
-    Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes)
+    private Map<String, MediaRoute2Info> waitAndGetRoutes(List<String> routeTypes)
             throws Exception {
         CountDownLatch latch = new CountDownLatch(1);
 
         RouteCallback routeCallback = new RouteCallback() {
             @Override
             public void onRoutesAdded(List<MediaRoute2Info> routes) {
-                for (int i = 0; i < routes.size(); i++) {
-                    //TODO: use isSystem() or similar method when it's ready
-                    if (!TextUtils.equals(routes.get(i).getProviderId(), SYSTEM_PROVIDER_ID)) {
+                for (MediaRoute2Info route : routes) {
+                    if (!route.isSystemRoute()) {
                         latch.countDown();
                     }
                 }
@@ -818,7 +977,7 @@
     /**
      * Returns a list of original route IDs of the given route list.
      */
-    List<String> getOriginalRouteIds(@NonNull List<MediaRoute2Info> routes) {
+    private List<String> getOriginalRouteIds(@NonNull List<MediaRoute2Info> routes) {
         List<String> result = new ArrayList<>();
         for (MediaRoute2Info route : routes) {
             result.add(route.getOriginalId());
diff --git a/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java b/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java
index 4eda8b8..6f36cb9 100644
--- a/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java
+++ b/tests/tests/media/src/android/media/cts/MediaSessionTestActivity.java
@@ -24,6 +24,7 @@
 import android.media.session.MediaController;
 import android.media.session.MediaSession;
 import android.os.Bundle;
+import android.util.Log;
 import android.view.WindowManager;
 
 /**
@@ -32,28 +33,40 @@
  */
 public class MediaSessionTestActivity extends Activity {
     public static final String KEY_SESSION_TOKEN = "KEY_SESSION_TOKEN";
+    private static final String TAG = "MediaSessionTestActivity";
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
+        // Wake up device.
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
         setTurnScreenOn(true);
+
+        // Unlock device which is previously locked by power button press.
+        // This is required even when the screen lock is set to 'None'.
         setShowWhenLocked(true);
 
         KeyguardManager keyguardManager =
                 (KeyguardManager) getSystemService(Context.KEYGUARD_SERVICE);
-        if (keyguardManager.isKeyguardLocked()) {
+        // KeyguardManager can be null for the instant mode.
+        if (keyguardManager == null) {
+            Log.i(TAG, "Unable to get KeyguardManager. Probably in the instant mode.");
+        } else if (keyguardManager.isKeyguardLocked()) {
+            // Note: CTS requires 'no lock pattern or password is set on the device'.
+            // However, try to dismiss keyguard for convenience.
             keyguardManager.requestDismissKeyguard(this,
                     new KeyguardManager.KeyguardDismissCallback() {
                         @Override
                         public void onDismissError() {
-                            fail("Failed to dismiss keyguard.");
+                            fail("Running CTS needs device unlock. Manually unlock device because"
+                                    + " failed to dismiss keyguard.");
                         }
 
                         @Override
                         public void onDismissCancelled() {
-                            fail("Dismissing keyguard is canceled");
+                            fail("Running CTS needs device unlock. Manually unlock device because"
+                                    + " failed to dismiss keyguard.");
                         }
                     });
         }
diff --git a/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java b/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java
index 2f3a090..1632ab6 100644
--- a/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java
+++ b/tests/tests/media/src/android/media/cts/RouteDiscoveryPreferenceTest.java
@@ -69,7 +69,8 @@
         RouteDiscoveryPreference preference =
                 new RouteDiscoveryPreference.Builder(features, true /* isActiveScan */).build();
         assertEquals(features, preference.getPreferredFeatures());
-        assertTrue(preference.isActiveScan());
+        assertTrue(preference.shouldPerformActiveScan());
+        assertEquals(0, preference.describeContents());
     }
 
     @Test
@@ -90,7 +91,7 @@
                 .build();
 
         assertEquals(newFeatures, newPreference.getPreferredFeatures());
-        assertTrue(newPreference.isActiveScan());
+        assertTrue(newPreference.shouldPerformActiveScan());
     }
 
     @Test
@@ -104,11 +105,11 @@
 
         // Using copy constructor, we only change the activeScan to 'false'.
         RouteDiscoveryPreference newPreference = new RouteDiscoveryPreference.Builder(preference)
-                .setActiveScan(false)
+                .setShouldPerformActiveScan(false)
                 .build();
 
         assertEquals(features, newPreference.getPreferredFeatures());
-        assertFalse(newPreference.isActiveScan());
+        assertFalse(newPreference.shouldPerformActiveScan());
     }
 
     @Test
@@ -180,7 +181,7 @@
 
         RouteDiscoveryPreference preferenceWithDifferentActiveScan =
                 new RouteDiscoveryPreference.Builder(preference)
-                        .setActiveScan(false)
+                        .setShouldPerformActiveScan(false)
                         .build();
         assertNotEquals(preference, preferenceWithDifferentActiveScan);
     }
diff --git a/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java b/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java
index 93d9aca..a458a9a 100644
--- a/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java
+++ b/tests/tests/media/src/android/media/cts/RoutingSessionInfoTest.java
@@ -16,6 +16,8 @@
 
 package android.media.cts;
 
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNotNull;
@@ -54,6 +56,9 @@
     public static final String TEST_KEY = "test_key";
     public static final String TEST_VALUE = "test_value";
 
+    public static final int TEST_VOLUME_HANDLING = PLAYBACK_VOLUME_VARIABLE;
+    public static final int TEST_VOLUME_MAX = 100;
+    public static final int TEST_VOLUME = 65;
     @Test
     public void testBuilderConstructorWithInvalidValues() {
         final String nullId = null;
@@ -121,7 +126,7 @@
         assertThrows(IllegalArgumentException.class,
                 () -> builder.addDeselectableRoute(nullRouteId));
         assertThrows(IllegalArgumentException.class,
-                () -> builder.addTransferrableRoute(nullRouteId));
+                () -> builder.addTransferableRoute(nullRouteId));
 
         assertThrows(IllegalArgumentException.class,
                 () -> builder.addSelectedRoute(emptyRouteId));
@@ -130,7 +135,7 @@
         assertThrows(IllegalArgumentException.class,
                 () -> builder.addDeselectableRoute(emptyRouteId));
         assertThrows(IllegalArgumentException.class,
-                () -> builder.addTransferrableRoute(emptyRouteId));
+                () -> builder.addTransferableRoute(emptyRouteId));
     }
 
     @Test
@@ -148,7 +153,7 @@
         assertThrows(IllegalArgumentException.class,
                 () -> builder.removeDeselectableRoute(nullRouteId));
         assertThrows(IllegalArgumentException.class,
-                () -> builder.removeTransferrableRoute(nullRouteId));
+                () -> builder.removeTransferableRoute(nullRouteId));
 
         assertThrows(IllegalArgumentException.class,
                 () -> builder.removeSelectedRoute(emptyRouteId));
@@ -157,7 +162,7 @@
         assertThrows(IllegalArgumentException.class,
                 () -> builder.removeDeselectableRoute(emptyRouteId));
         assertThrows(IllegalArgumentException.class,
-                () -> builder.removeTransferrableRoute(emptyRouteId));
+                () -> builder.removeTransferableRoute(emptyRouteId));
     }
 
     @Test
@@ -173,8 +178,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -193,9 +201,13 @@
         assertEquals(TEST_ROUTE_ID_4, sessionInfo.getDeselectableRoutes().get(0));
         assertEquals(TEST_ROUTE_ID_5, sessionInfo.getDeselectableRoutes().get(1));
 
-        assertEquals(2, sessionInfo.getTransferrableRoutes().size());
-        assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferrableRoutes().get(0));
-        assertEquals(TEST_ROUTE_ID_7, sessionInfo.getTransferrableRoutes().get(1));
+        assertEquals(2, sessionInfo.getTransferableRoutes().size());
+        assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferableRoutes().get(0));
+        assertEquals(TEST_ROUTE_ID_7, sessionInfo.getTransferableRoutes().get(1));
+
+        assertEquals(TEST_VOLUME_HANDLING, sessionInfo.getVolumeHandling());
+        assertEquals(TEST_VOLUME_MAX, sessionInfo.getVolumeMax());
+        assertEquals(TEST_VOLUME, sessionInfo.getVolume());
 
         Bundle controlHintsOut = sessionInfo.getControlHints();
         assertNotNull(controlHintsOut);
@@ -210,14 +222,14 @@
                 .addSelectedRoute(TEST_ROUTE_ID_0)
                 .addSelectableRoute(TEST_ROUTE_ID_2)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
                 .build();
 
         RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
                 .addSelectedRoute(TEST_ROUTE_ID_1)
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
                 .build();
 
         assertEquals(2, newSessionInfo.getSelectedRoutes().size());
@@ -232,9 +244,9 @@
         assertEquals(TEST_ROUTE_ID_4, newSessionInfo.getDeselectableRoutes().get(0));
         assertEquals(TEST_ROUTE_ID_5, newSessionInfo.getDeselectableRoutes().get(1));
 
-        assertEquals(2, newSessionInfo.getTransferrableRoutes().size());
-        assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferrableRoutes().get(0));
-        assertEquals(TEST_ROUTE_ID_7, newSessionInfo.getTransferrableRoutes().get(1));
+        assertEquals(2, newSessionInfo.getTransferableRoutes().size());
+        assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferableRoutes().get(0));
+        assertEquals(TEST_ROUTE_ID_7, newSessionInfo.getTransferableRoutes().get(1));
     }
 
     @Test
@@ -253,9 +265,9 @@
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
                 .removeDeselectableRoute(TEST_ROUTE_ID_5)
 
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
-                .removeTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .removeTransferableRoute(TEST_ROUTE_ID_7)
 
                 .build();
 
@@ -268,8 +280,8 @@
         assertEquals(1, sessionInfo.getDeselectableRoutes().size());
         assertEquals(TEST_ROUTE_ID_4, sessionInfo.getDeselectableRoutes().get(0));
 
-        assertEquals(1, sessionInfo.getTransferrableRoutes().size());
-        assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferrableRoutes().get(0));
+        assertEquals(1, sessionInfo.getTransferableRoutes().size());
+        assertEquals(TEST_ROUTE_ID_6, sessionInfo.getTransferableRoutes().get(0));
     }
 
     @Test
@@ -282,15 +294,15 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
                 .build();
 
         RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
                 .removeSelectedRoute(TEST_ROUTE_ID_1)
                 .removeSelectableRoute(TEST_ROUTE_ID_3)
                 .removeDeselectableRoute(TEST_ROUTE_ID_5)
-                .removeTransferrableRoute(TEST_ROUTE_ID_7)
+                .removeTransferableRoute(TEST_ROUTE_ID_7)
                 .build();
 
         assertEquals(1, newSessionInfo.getSelectedRoutes().size());
@@ -302,8 +314,8 @@
         assertEquals(1, newSessionInfo.getDeselectableRoutes().size());
         assertEquals(TEST_ROUTE_ID_4, newSessionInfo.getDeselectableRoutes().get(0));
 
-        assertEquals(1, newSessionInfo.getTransferrableRoutes().size());
-        assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferrableRoutes().get(0));
+        assertEquals(1, newSessionInfo.getTransferableRoutes().size());
+        assertEquals(TEST_ROUTE_ID_6, newSessionInfo.getTransferableRoutes().get(0));
     }
 
     @Test
@@ -322,9 +334,9 @@
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
                 .clearDeselectableRoutes()
 
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
-                .clearTransferrableRoutes()
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .clearTransferableRoutes()
 
                 // SelectedRoutes must not be empty
                 .addSelectedRoute(TEST_ROUTE_ID_0)
@@ -335,7 +347,7 @@
 
         assertTrue(sessionInfo.getSelectableRoutes().isEmpty());
         assertTrue(sessionInfo.getDeselectableRoutes().isEmpty());
-        assertTrue(sessionInfo.getTransferrableRoutes().isEmpty());
+        assertTrue(sessionInfo.getTransferableRoutes().isEmpty());
     }
 
     @Test
@@ -348,15 +360,15 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
                 .build();
 
         RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
                 .clearSelectedRoutes()
                 .clearSelectableRoutes()
                 .clearDeselectableRoutes()
-                .clearTransferrableRoutes()
+                .clearTransferableRoutes()
                 // SelectedRoutes must not be empty
                 .addSelectedRoute(TEST_ROUTE_ID_0)
                 .build();
@@ -366,7 +378,7 @@
 
         assertTrue(newSessionInfo.getSelectableRoutes().isEmpty());
         assertTrue(newSessionInfo.getDeselectableRoutes().isEmpty());
-        assertTrue(newSessionInfo.getTransferrableRoutes().isEmpty());
+        assertTrue(newSessionInfo.getTransferableRoutes().isEmpty());
     }
 
     @Test
@@ -382,8 +394,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -395,8 +410,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -417,8 +435,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -441,8 +462,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -457,7 +481,7 @@
                 .addDeselectableRoute("randomRoute")
                 .build());
         assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
-                .addTransferrableRoute("randomRoute")
+                .addTransferableRoute("randomRoute")
                 .build());
 
         assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
@@ -470,7 +494,7 @@
                 .removeDeselectableRoute(TEST_ROUTE_ID_5)
                 .build());
         assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
-                .removeTransferrableRoute(TEST_ROUTE_ID_7)
+                .removeTransferableRoute(TEST_ROUTE_ID_7)
                 .build());
 
         assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
@@ -485,9 +509,16 @@
                 .clearDeselectableRoutes()
                 .build());
         assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
-                .clearTransferrableRoutes()
+                .clearTransferableRoutes()
                 .build());
 
+        assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
+                .setVolumeHandling(TEST_VOLUME_HANDLING + 1).build());
+        assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
+                .setVolumeMax(TEST_VOLUME_MAX + 1).build());
+        assertNotEquals(sessionInfo, new RoutingSessionInfo.Builder(sessionInfo)
+                .setVolume(TEST_VOLUME + 1).build());
+
         // Note: ControlHints will not affect the equals.
     }
 
@@ -504,8 +535,11 @@
                 .addSelectableRoute(TEST_ROUTE_ID_3)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
                 .addDeselectableRoute(TEST_ROUTE_ID_5)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
-                .addTransferrableRoute(TEST_ROUTE_ID_7)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_7)
+                .setVolumeHandling(TEST_VOLUME_HANDLING)
+                .setVolumeMax(TEST_VOLUME_MAX)
+                .setVolume(TEST_VOLUME)
                 .setControlHints(controlHints)
                 .build();
 
@@ -537,7 +571,7 @@
                 .addSelectedRoute(TEST_ROUTE_ID_0)
                 .addSelectableRoute(TEST_ROUTE_ID_2)
                 .addDeselectableRoute(TEST_ROUTE_ID_4)
-                .addTransferrableRoute(TEST_ROUTE_ID_6)
+                .addTransferableRoute(TEST_ROUTE_ID_6)
                 .build();
         assertEquals(0, sessionInfo.describeContents());
     }
diff --git a/tests/tests/media/src/android/media/cts/SampleMediaRoute2ProviderService.java b/tests/tests/media/src/android/media/cts/SampleMediaRoute2ProviderService.java
index fda5444..4b51731 100644
--- a/tests/tests/media/src/android/media/cts/SampleMediaRoute2ProviderService.java
+++ b/tests/tests/media/src/android/media/cts/SampleMediaRoute2ProviderService.java
@@ -19,7 +19,9 @@
 import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_SPEAKER;
 import static android.media.MediaRoute2Info.DEVICE_TYPE_REMOTE_TV;
 import static android.media.MediaRoute2Info.FEATURE_LIVE_AUDIO;
+import static android.media.MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Intent;
 import android.media.MediaRoute2Info;
@@ -29,7 +31,9 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.text.TextUtils;
+import android.util.Log;
 
+import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -58,23 +62,16 @@
     public static final String ROUTE_NAME_SPECIAL_FEATURE = "Special Feature Route";
 
     public static final int VOLUME_MAX = 100;
+    public static final int SESSION_VOLUME_MAX = 50;
+    public static final int SESSION_VOLUME_INITIAL = 20;
+
     public static final String ROUTE_ID_FIXED_VOLUME = "route_fixed_volume";
     public static final String ROUTE_NAME_FIXED_VOLUME = "Fixed Volume Route";
     public static final String ROUTE_ID_VARIABLE_VOLUME = "route_variable_volume";
     public static final String ROUTE_NAME_VARIABLE_VOLUME = "Variable Volume Route";
 
-    public static final String ACTION_REMOVE_ROUTE =
-            "com.android.mediarouteprovider.action_remove_route";
-
-    public static final String FEATURE_SAMPLE =
-            "com.android.mediarouteprovider.FEATURE_SAMPLE";
-    public static final String FEATURE_SPECIAL =
-            "com.android.mediarouteprovider.FEATURE_SPECIAL";
-
-    // TODO: We shouldn't depend on this constant.
-    //       Remove this when MediaRoute2Info#isSystem() is introduced.
-    public static final String SYSTEM_PROVIDER_ID =
-            "com.android.server.media/.SystemMediaRoute2Provider";
+    public static final String FEATURE_SAMPLE = "android.media.cts.FEATURE_SAMPLE";
+    public static final String FEATURE_SPECIAL = "android.media.cts.FEATURE_SPECIAL";
 
     public static final List<String> FEATURES_ALL = new ArrayList();
     public static final List<String> FEATURES_SPECIAL = new ArrayList();
@@ -95,7 +92,7 @@
     private static SampleMediaRoute2ProviderService sInstance;
     private Proxy mProxy;
 
-    private void initializeRoutes() {
+    public void initializeRoutes() {
         MediaRoute2Info route1 = new MediaRoute2Info.Builder(ROUTE_ID1, ROUTE_NAME1)
                 .addFeature(FEATURE_SAMPLE)
                 .setDeviceType(DEVICE_TYPE_REMOTE_TV)
@@ -129,7 +126,7 @@
         MediaRoute2Info variableVolumeRoute =
                 new MediaRoute2Info.Builder(ROUTE_ID_VARIABLE_VOLUME, ROUTE_NAME_VARIABLE_VOLUME)
                         .addFeature(FEATURE_SAMPLE)
-                        .setVolumeHandling(MediaRoute2Info.PLAYBACK_VOLUME_VARIABLE)
+                        .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
                         .setVolumeMax(VOLUME_MAX)
                         .build();
 
@@ -149,6 +146,15 @@
         }
     }
 
+    public void clear() {
+        mProxy = null;
+        mRoutes.clear();
+        mRouteIdToSessionId.clear();
+        for (RoutingSessionInfo sessionInfo : getAllSessionInfo()) {
+            notifySessionReleased(sessionInfo.getId());
+        }
+    }
+
     public void setProxy(@Nullable Proxy proxy) {
         mProxy = proxy;
     }
@@ -159,7 +165,6 @@
         synchronized (sLock) {
             sInstance = this;
         }
-        initializeRoutes();
     }
 
     @Override
@@ -174,30 +179,16 @@
 
     @Override
     public IBinder onBind(Intent intent) {
-        publishRoutes();
         return super.onBind(intent);
     }
 
     @Override
-    public void onControlRequest(String routeId, Intent request) {
-        String action = request.getAction();
-        if (ACTION_REMOVE_ROUTE.equals(action)) {
-            MediaRoute2Info route = mRoutes.get(routeId);
-            if (route != null) {
-                mRoutes.remove(routeId);
-                publishRoutes();
-                mRoutes.put(routeId, route);
-            }
-        }
-    }
-
-    @Override
-    public void onSetVolume(String routeId, int volume) {
+    public void onSetRouteVolume(String routeId, int volume) {
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null) {
             return;
         }
-        volume = Math.min(volume, Math.max(0, route.getVolumeMax()));
+        volume = Math.max(0, Math.min(volume, route.getVolumeMax()));
         mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
                 .setVolume(volume)
                 .build());
@@ -205,8 +196,27 @@
     }
 
     @Override
+    public void onSetSessionVolume(String sessionId, int volume) {
+        RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
+        if (sessionInfo == null) {
+            return;
+        }
+        volume = Math.max(0, Math.min(volume, sessionInfo.getVolumeMax()));
+        RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
+                .setVolume(volume)
+                .build();
+        notifySessionUpdated(newSessionInfo);
+    }
+
+    @Override
     public void onCreateSession(String packageName, String routeId, long requestId,
             @Nullable Bundle sessionHints) {
+        Proxy proxy = mProxy;
+        if (doesProxyOverridesMethod(proxy, "onCreateSession")) {
+            proxy.onCreateSession(packageName, routeId, requestId, sessionHints);
+            return;
+        }
+
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || TextUtils.equals(ROUTE_ID3_SESSION_CREATION_FAILED, routeId)) {
             // Tell the router that session cannot be created by passing null as sessionInfo.
@@ -226,7 +236,10 @@
         RoutingSessionInfo sessionInfo = new RoutingSessionInfo.Builder(sessionId, packageName)
                 .addSelectedRoute(routeId)
                 .addSelectableRoute(ROUTE_ID4_TO_SELECT_AND_DESELECT)
-                .addTransferrableRoute(ROUTE_ID5_TO_TRANSFER_TO)
+                .addTransferableRoute(ROUTE_ID5_TO_TRANSFER_TO)
+                .setVolumeHandling(PLAYBACK_VOLUME_VARIABLE)
+                .setVolumeMax(SESSION_VOLUME_MAX)
+                .setVolume(SESSION_VOLUME_INITIAL)
                 // Set control hints with given sessionHints
                 .setControlHints(sessionHints)
                 .build();
@@ -236,6 +249,12 @@
 
     @Override
     public void onReleaseSession(String sessionId) {
+        Proxy proxy = mProxy;
+        if (doesProxyOverridesMethod(proxy, "onReleaseSession")) {
+            proxy.onReleaseSession(sessionId);
+            return;
+        }
+
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         if (sessionInfo == null) {
             return;
@@ -257,13 +276,23 @@
     @Override
     public void onDiscoveryPreferenceChanged(RouteDiscoveryPreference preference) {
         Proxy proxy = mProxy;
-        if (proxy != null) {
+        if (doesProxyOverridesMethod(proxy, "onDiscoveryPreferenceChanged")) {
             proxy.onDiscoveryPreferenceChanged(preference);
+            return;
         }
+
+        // Just call the empty super method in order to mark the callback as tested.
+        super.onDiscoveryPreferenceChanged(preference);
     }
 
     @Override
     public void onSelectRoute(String sessionId, String routeId) {
+        Proxy proxy = mProxy;
+        if (doesProxyOverridesMethod(proxy, "onSelectRoute")) {
+            proxy.onSelectRoute(sessionId, routeId);
+            return;
+        }
+
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
         if (route == null || sessionInfo == null) {
@@ -275,6 +304,7 @@
                 .setClientPackageName(sessionInfo.getClientPackageName())
                 .build());
         mRouteIdToSessionId.put(routeId, sessionId);
+        publishRoutes();
 
         RoutingSessionInfo newSessionInfo = new RoutingSessionInfo.Builder(sessionInfo)
                 .addSelectedRoute(routeId)
@@ -286,6 +316,12 @@
 
     @Override
     public void onDeselectRoute(String sessionId, String routeId) {
+        Proxy proxy = mProxy;
+        if (doesProxyOverridesMethod(proxy, "onDeselectRoute")) {
+            proxy.onDeselectRoute(sessionId, routeId);
+            return;
+        }
+
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
 
@@ -298,6 +334,7 @@
         mRoutes.put(routeId, new MediaRoute2Info.Builder(route)
                 .setClientPackageName(null)
                 .build());
+        publishRoutes();
 
         if (sessionInfo.getSelectedRoutes().size() == 1) {
             notifySessionReleased(sessionId);
@@ -314,6 +351,12 @@
 
     @Override
     public void onTransferToRoute(String sessionId, String routeId) {
+        Proxy proxy = mProxy;
+        if (doesProxyOverridesMethod(proxy, "onTransferToRoute")) {
+            proxy.onTransferToRoute(sessionId, routeId);
+            return;
+        }
+
         RoutingSessionInfo sessionInfo = getSessionInfo(sessionId);
         MediaRoute2Info route = mRoutes.get(routeId);
 
@@ -340,7 +383,7 @@
                 .clearSelectedRoutes()
                 .addSelectedRoute(routeId)
                 .removeDeselectableRoute(routeId)
-                .removeTransferrableRoute(routeId)
+                .removeTransferableRoute(routeId)
                 .build();
         notifySessionUpdated(newSessionInfo);
         publishRoutes();
@@ -356,10 +399,34 @@
     }
 
     void publishRoutes() {
-        notifyRoutes(mRoutes.values());
+        notifyRoutes(new ArrayList<>(mRoutes.values()));
     }
 
     public static class Proxy {
+        public void onCreateSession(@NonNull String packageName, @NonNull String routeId,
+                long requestId, @Nullable Bundle sessionHints) {}
+        public void onReleaseSession(@NonNull String sessionId) {}
+        public void onSelectRoute(@NonNull String sessionId, @NonNull String routeId) {}
+        public void onDeselectRoute(@NonNull String sessionId, @NonNull String routeId) {}
+        public void onTransferToRoute(@NonNull String sessionId, @NonNull String routeId) {}
         public void onDiscoveryPreferenceChanged(RouteDiscoveryPreference preference) {}
+        // TODO: Handle onSetRouteVolume() && onSetSessionVolume()
+    }
+
+    private static boolean doesProxyOverridesMethod(Proxy proxy, String methodName) {
+        if (proxy == null) {
+            return false;
+        }
+        Method[] methods = proxy.getClass().getMethods();
+        if (methods == null) {
+            return false;
+        }
+        for (int i = 0; i < methods.length; i++) {
+            if (methods[i].getName().equals(methodName)) {
+                // Found method. Check if it overrides
+                return methods[i].getDeclaringClass() != Proxy.class;
+            }
+        }
+        return false;
     }
 }
diff --git a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
index 727db77..73fc811 100644
--- a/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
+++ b/tests/tests/media/src/android/media/cts/VideoEncoderTest.java
@@ -35,6 +35,7 @@
 import android.net.Uri;
 import android.platform.test.annotations.AppModeFull;
 import android.platform.test.annotations.Presubmit;
+import android.platform.test.annotations.RequiresDevice;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Range;
@@ -1631,10 +1632,12 @@
     @NonMediaMainlineTest
     public void testOtherH265SurfQCIF()  { specific(otherH265(),  176, 144, false /* flex */); }
     @NonMediaMainlineTest
+    @RequiresDevice
     @Presubmit
     @SmallTest
     public void testOtherH264FlexQCIF()  { specific(otherH264(),  176, 144, true /* flex */); }
     @NonMediaMainlineTest
+    @RequiresDevice
     @Presubmit
     @SmallTest
     public void testOtherH264SurfQCIF()  { specific(otherH264(),  176, 144, false /* flex */); }
diff --git a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
index 1bef85e..c3eafe7 100644
--- a/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
+++ b/tests/tests/mediaparser/src/android/media/mediaparser/cts/MockMediaParserOutputConsumer.java
@@ -17,15 +17,20 @@
 package android.media.mediaparser.cts;
 
 import android.media.MediaCodec;
+import android.media.MediaFormat;
 import android.media.MediaParser;
 import android.util.Pair;
 
 import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.Format;
+import com.google.android.exoplayer2.drm.DrmInitData;
 import com.google.android.exoplayer2.extractor.ExtractorInput;
 import com.google.android.exoplayer2.extractor.SeekMap;
 import com.google.android.exoplayer2.extractor.SeekPoint;
 import com.google.android.exoplayer2.extractor.TrackOutput;
 import com.google.android.exoplayer2.testutil.FakeExtractorOutput;
+import com.google.android.exoplayer2.util.MimeTypes;
+import com.google.android.exoplayer2.video.ColorInfo;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -61,16 +66,6 @@
                 });
     }
 
-    private static SeekMap.SeekPoints toExoPlayerSeekPoints(
-            Pair<MediaParser.SeekPoint, MediaParser.SeekPoint> seekPoints) {
-        return new SeekMap.SeekPoints(
-                toExoPlayerSeekPoint(seekPoints.first), toExoPlayerSeekPoint(seekPoints.second));
-    }
-
-    private static SeekPoint toExoPlayerSeekPoint(MediaParser.SeekPoint seekPoint) {
-        return new SeekPoint(seekPoint.timeUs, seekPoint.position);
-    }
-
     @Override
     public void onTracksFound(int numberOfTracks) {
         // Do nothing.
@@ -78,9 +73,10 @@
 
     @Override
     public void onTrackData(int trackIndex, MediaParser.TrackData trackData) {
-        while (mTrackOutputs.size() < trackIndex) {
+        while (mTrackOutputs.size() <= trackIndex) {
             mTrackOutputs.add(mFakeExtractorOutput.track(trackIndex, C.TRACK_TYPE_UNKNOWN));
         }
+        mTrackOutputs.get(trackIndex).format(toExoPlayerFormat(trackData));
     }
 
     @Override
@@ -103,6 +99,208 @@
             int offset,
             MediaCodec.CryptoInfo cryptoData) {}
 
+    // Internal methods.
+
+    private static SeekMap.SeekPoints toExoPlayerSeekPoints(
+            Pair<MediaParser.SeekPoint, MediaParser.SeekPoint> seekPoints) {
+        return new SeekMap.SeekPoints(
+                toExoPlayerSeekPoint(seekPoints.first), toExoPlayerSeekPoint(seekPoints.second));
+    }
+
+    private static SeekPoint toExoPlayerSeekPoint(MediaParser.SeekPoint seekPoint) {
+        return new SeekPoint(seekPoint.timeUs, seekPoint.position);
+    }
+
+    private static Format toExoPlayerFormat(MediaParser.TrackData trackData) {
+        MediaFormat mediaFormat = trackData.mediaFormat;
+        String sampleMimeType =
+                mediaFormat.getString(MediaFormat.KEY_MIME, /* defaultValue= */ null);
+        String id =
+                mediaFormat.containsKey(MediaFormat.KEY_TRACK_ID)
+                        ? String.valueOf(mediaFormat.getInteger(MediaFormat.KEY_TRACK_ID))
+                        : null;
+        String codecs =
+                mediaFormat.getString(MediaFormat.KEY_CODECS_STRING, /* defaultValue= */ null);
+        int bitrate =
+                mediaFormat.getInteger(
+                        MediaFormat.KEY_BIT_RATE, /* defaultValue= */ Format.NO_VALUE);
+        int maxInputSize =
+                mediaFormat.getInteger(
+                        MediaFormat.KEY_MAX_INPUT_SIZE, /* defaultValue= */ Format.NO_VALUE);
+        int width =
+                mediaFormat.getInteger(MediaFormat.KEY_WIDTH, /* defaultValue= */ Format.NO_VALUE);
+        int height =
+                mediaFormat.getInteger(MediaFormat.KEY_HEIGHT, /* defaultValue= */ Format.NO_VALUE);
+        float frameRate =
+                mediaFormat.getFloat(
+                        MediaFormat.KEY_FRAME_RATE, /* defaultValue= */ Format.NO_VALUE);
+        int rotationDegrees =
+                mediaFormat.getInteger(
+                        MediaFormat.KEY_ROTATION, /* defaultValue= */ Format.NO_VALUE);
+        ArrayList<byte[]> initData = null;
+        if (mediaFormat.containsKey("csd-0")) {
+            initData = new ArrayList<>();
+            int index = 0;
+            while (mediaFormat.containsKey("csd-" + index)) {
+                initData.add(mediaFormat.getByteBuffer("csd-" + index++).array());
+            }
+        }
+        float pixelAspectWidth =
+                (float)
+                        mediaFormat.getInteger(
+                                MediaFormat.KEY_PIXEL_ASPECT_RATIO_WIDTH, /* defaultValue= */ 0);
+        float pixelAspectHeight =
+                (float)
+                        mediaFormat.getInteger(
+                                MediaFormat.KEY_PIXEL_ASPECT_RATIO_HEIGHT, /* defaultValue= */ 0);
+        float pixelAspectRatio =
+                pixelAspectHeight == 0 || pixelAspectWidth == 0
+                        ? Format.NO_VALUE
+                        : pixelAspectWidth / pixelAspectHeight;
+        ColorInfo colorInfo = getExoPlayerColorInfo(mediaFormat);
+        DrmInitData drmInitData = getExoPlayerDrmInitData(trackData.drmInitData);
+
+        int selectionFlags =
+                mediaFormat.getInteger(MediaFormat.KEY_IS_AUTOSELECT, /* defaultValue= */ 0) != 0
+                        ? C.SELECTION_FLAG_AUTOSELECT
+                        : 0;
+        selectionFlags |=
+                mediaFormat.getInteger(MediaFormat.KEY_IS_FORCED_SUBTITLE, /* defaultValue= */ 0)
+                                != 0
+                        ? C.SELECTION_FLAG_FORCED
+                        : 0;
+        selectionFlags |=
+                mediaFormat.getInteger(MediaFormat.KEY_IS_DEFAULT, /* defaultValue= */ 0) != 0
+                        ? C.SELECTION_FLAG_DEFAULT
+                        : 0;
+
+        String language = mediaFormat.getString(MediaFormat.KEY_LANGUAGE, /* defaultValue= */ null);
+
+        // TODO: Replace this with Format.Builder once available.
+        if (MimeTypes.isVideo(sampleMimeType)) {
+            return Format.createVideoSampleFormat(
+                    id,
+                    sampleMimeType,
+                    codecs,
+                    bitrate,
+                    maxInputSize,
+                    width,
+                    height,
+                    frameRate,
+                    initData,
+                    rotationDegrees,
+                    pixelAspectRatio,
+                    /* projectionData= */ null,
+                    /* stereoMode= */ Format.NO_VALUE,
+                    colorInfo,
+                    drmInitData);
+        } else if (MimeTypes.isAudio(sampleMimeType)) {
+            int channels = mediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
+            int sampleRate = mediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
+            return Format.createAudioContainerFormat(
+                    id,
+                    /* label= */ null,
+                    /* containerMimeType= */ null,
+                    sampleMimeType,
+                    codecs,
+                    /* metadata= */ null,
+                    bitrate,
+                    channels,
+                    sampleRate,
+                    initData,
+                    selectionFlags,
+                    /* roleFlags= */ 0,
+                    language);
+        } else { // Application or Text.
+            return Format.createTextSampleFormat(
+                    id,
+                    sampleMimeType,
+                    codecs,
+                    bitrate,
+                    selectionFlags,
+                    language,
+                    /* accessibilityChannel= */ 0, // TODO: Add once ag/9864463 is submitted.
+                    /* drmInitData= */ drmInitData,
+                    /* subsampleOffsetUs= */ Format.OFFSET_SAMPLE_RELATIVE,
+                    initData);
+        }
+    }
+
+    private static DrmInitData getExoPlayerDrmInitData(android.media.DrmInitData drmInitData) {
+        // TODO: Implement once ag/10253368 is resolved.
+        return null;
+    }
+
+    private static ColorInfo getExoPlayerColorInfo(MediaFormat mediaFormat) {
+        int colorSpace = Format.NO_VALUE;
+        if (mediaFormat.containsKey(MediaFormat.KEY_COLOR_FORMAT)) {
+            switch (mediaFormat.getInteger(MediaFormat.KEY_COLOR_FORMAT)) {
+                case MediaFormat.COLOR_STANDARD_BT601_NTSC:
+                case MediaFormat.COLOR_STANDARD_BT601_PAL:
+                    colorSpace = C.COLOR_SPACE_BT601;
+                    break;
+                case MediaFormat.COLOR_STANDARD_BT709:
+                    colorSpace = C.COLOR_SPACE_BT709;
+                    break;
+                case MediaFormat.COLOR_STANDARD_BT2020:
+                    colorSpace = C.COLOR_SPACE_BT2020;
+                    break;
+                default:
+                    colorSpace = Format.NO_VALUE;
+            }
+        }
+
+        int colorRange = Format.NO_VALUE;
+        if (mediaFormat.containsKey(MediaFormat.KEY_COLOR_RANGE)) {
+            switch (mediaFormat.getInteger(MediaFormat.KEY_COLOR_RANGE)) {
+                case MediaFormat.COLOR_RANGE_FULL:
+                    colorRange = C.COLOR_RANGE_FULL;
+                    break;
+                case MediaFormat.COLOR_RANGE_LIMITED:
+                    colorRange = C.COLOR_RANGE_LIMITED;
+                    break;
+                default:
+                    colorRange = Format.NO_VALUE;
+            }
+        }
+
+        int colorTransfer = Format.NO_VALUE;
+        if (mediaFormat.containsKey(MediaFormat.KEY_COLOR_TRANSFER)) {
+            switch (mediaFormat.getInteger(MediaFormat.KEY_COLOR_TRANSFER)) {
+                case MediaFormat.COLOR_TRANSFER_HLG:
+                    colorTransfer = C.COLOR_TRANSFER_HLG;
+                    break;
+                case MediaFormat.COLOR_TRANSFER_SDR_VIDEO:
+                    colorTransfer = C.COLOR_TRANSFER_SDR;
+                    break;
+                case MediaFormat.COLOR_TRANSFER_ST2084:
+                    colorTransfer = C.COLOR_TRANSFER_ST2084;
+                    break;
+                case MediaFormat.COLOR_TRANSFER_LINEAR:
+                    // Fall through, there's no mapping.
+                default:
+                    colorTransfer = Format.NO_VALUE;
+            }
+        }
+        boolean hasHdrInfo = mediaFormat.containsKey(MediaFormat.KEY_HDR_STATIC_INFO);
+        if (colorSpace == Format.NO_VALUE
+                && colorRange == Format.NO_VALUE
+                && colorTransfer == Format.NO_VALUE
+                && !hasHdrInfo) {
+            return null;
+        } else {
+            return new ColorInfo(
+                    colorSpace,
+                    colorRange,
+                    colorTransfer,
+                    hasHdrInfo
+                            ? mediaFormat.getByteBuffer(MediaFormat.KEY_HDR_STATIC_INFO).array()
+                            : null);
+        }
+    }
+
+    // Internal classes.
+
     private class ExtractorInputAdapter implements ExtractorInput {
 
         private final MediaParser.InputReader mInputReader;
diff --git a/tests/tests/nativemedia/sl/Android.mk b/tests/tests/nativemedia/sl/Android.mk
index 7d0edeb..3e76c88 100644
--- a/tests/tests/nativemedia/sl/Android.mk
+++ b/tests/tests/nativemedia/sl/Android.mk
@@ -44,6 +44,6 @@
 # Tag this module as a cts test artifact
 LOCAL_COMPATIBILITY_SUITE := cts vts general-tests
 
-LOCAL_CFLAGS := -Werror -Wall
+LOCAL_CFLAGS := -Werror -Wall -Wno-deprecated-declarations
 
 include $(BUILD_CTS_EXECUTABLE)
diff --git a/tests/tests/nativemedia/sl/OWNERS b/tests/tests/nativemedia/sl/OWNERS
index 38b4a35..7d77765 100644
--- a/tests/tests/nativemedia/sl/OWNERS
+++ b/tests/tests/nativemedia/sl/OWNERS
@@ -1,2 +1,3 @@
 # Bug component: 1344
 jmtrivi@google.com
+gkasten@google.com
diff --git a/tests/tests/net/Android.bp b/tests/tests/net/Android.bp
index b00455d..624d149 100644
--- a/tests/tests/net/Android.bp
+++ b/tests/tests/net/Android.bp
@@ -12,8 +12,8 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-android_test {
-    name: "CtsNetTestCases",
+java_defaults {
+    name: "CtsNetTestCasesDefaults",
     defaults: ["cts_defaults"],
 
     // Include both the 32 and 64 bit versions
@@ -32,7 +32,6 @@
         "libnativehelper_compat_libc++",
     ],
 
-    // include CtsTestServer as a temporary hack to free net.cts from cts.stub.
     srcs: [
         "src/**/*.java",
         "src/**/*.kt",
@@ -54,13 +53,33 @@
     // uncomment when b/13249961 is fixed
     // sdk_version: "current",
     platform_apis: true,
+}
 
-    // Tag this module as a cts test artifact
+// Networking CTS tests for development and release. These tests always target the platform SDK
+// version, and are subject to all the restrictions appropriate to that version. Before SDK
+// finalization, these tests have a min_sdk_version of 10000, and cannot be installed on release
+// devices.
+android_test {
+    name: "CtsNetTestCases",
+    defaults: ["CtsNetTestCasesDefaults"],
     test_suites: [
         "cts",
         "vts",
         "general-tests",
+    ],
+    test_config_template: "AndroidTestTemplate.xml",
+}
+
+// Networking CTS tests that have a min_sdk_version of the latest released SDK. These tests can
+// be installed on release devices at any point in the release cycle and are useful for qualifying
+// mainline modules on release devices.
+android_test {
+    name: "CtsNetTestCasesLatestSdk",
+    defaults: ["CtsNetTestCasesDefaults"],
+    min_sdk_version: "29",
+    target_sdk_version: "29",
+    test_suites: [
         "mts",
     ],
-
+    test_config_template: "AndroidTestTemplate.xml",
 }
diff --git a/tests/tests/net/AndroidTest.xml b/tests/tests/net/AndroidTestTemplate.xml
similarity index 92%
rename from tests/tests/net/AndroidTest.xml
rename to tests/tests/net/AndroidTestTemplate.xml
index 3ff019e..1f75da1 100644
--- a/tests/tests/net/AndroidTest.xml
+++ b/tests/tests/net/AndroidTestTemplate.xml
@@ -12,7 +12,7 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Net test cases">
+<configuration description="Test config for {MODULE}">
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="networking" />
     <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
@@ -22,7 +22,7 @@
     <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsNetTestCases.apk" />
+        <option name="test-file-name" value="{MODULE}.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="android.net.cts" />
diff --git a/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java b/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
new file mode 100644
index 0000000..0a80047
--- /dev/null
+++ b/tests/tests/net/src/android/net/cts/ConnectivityDiagnosticsManagerTest.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.cts;
+
+import static android.net.ConnectivityDiagnosticsManager.ConnectivityDiagnosticsCallback;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import android.content.Context;
+import android.net.ConnectivityDiagnosticsManager;
+import android.net.NetworkRequest;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.concurrent.Executor;
+
+@RunWith(AndroidJUnit4.class)
+public class ConnectivityDiagnosticsManagerTest {
+    private static final Executor INLINE_EXECUTOR = x -> x.run();
+    private static final NetworkRequest DEFAULT_REQUEST = new NetworkRequest.Builder().build();
+
+    private Context mContext;
+    private ConnectivityDiagnosticsManager mCdm;
+    private ConnectivityDiagnosticsCallback mCallback;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+        mCdm = mContext.getSystemService(ConnectivityDiagnosticsManager.class);
+
+        mCallback = new ConnectivityDiagnosticsCallback() {};
+    }
+
+    @Test
+    public void testRegisterConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+    }
+
+    @Test
+    public void testRegisterDuplicateConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+
+        try {
+            mCdm.registerConnectivityDiagnosticsCallback(
+                    DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+            fail("Registering the same callback twice should throw an IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    @Test
+    public void testUnregisterConnectivityDiagnosticsCallback() {
+        mCdm.registerConnectivityDiagnosticsCallback(DEFAULT_REQUEST, INLINE_EXECUTOR, mCallback);
+        mCdm.unregisterConnectivityDiagnosticsCallback(mCallback);
+    }
+
+    @Test
+    public void testUnregisterUnknownConnectivityDiagnosticsCallback() {
+        // Expected to silently ignore the unregister() call
+        mCdm.unregisterConnectivityDiagnosticsCallback(mCallback);
+    }
+}
diff --git a/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java b/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
index c557338..ba0832f 100644
--- a/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
+++ b/tests/tests/net/src/android/net/wifi/cts/ConcurrencyTest.java
@@ -299,7 +299,6 @@
         assertTrue(waitForBroadcasts(MySync.NETWORK_INFO));
         // wait for changing to EnabledState
         assertNotNull(mMySync.expectedNetworkInfo);
-        assertTrue(mMySync.expectedNetworkInfo.isAvailable());
 
         return true;
     }
diff --git a/tests/tests/neuralnetworks/tflite_delegate/Android.mk b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
index e9ea001..1b6e7b3 100644
--- a/tests/tests/neuralnetworks/tflite_delegate/Android.mk
+++ b/tests/tests/neuralnetworks/tflite_delegate/Android.mk
@@ -20,7 +20,11 @@
 LOCAL_SRC_FILES := \
     tensorflow/lite/delegates/nnapi/nnapi_delegate_test.cc \
     tensorflow/lite/kernels/test_util.cc \
-    tensorflow/core/platform/default/logging.cc
+    tensorflow/core/platform/default/logging.cc \
+    tensorflow/lite/kernels/acceleration_test_util.cc \
+    tensorflow/lite/kernels/acceleration_test_util_internal.cc \
+    tensorflow/lite/delegates/nnapi/acceleration_test_list.cc \
+    tensorflow/lite/delegates/nnapi/acceleration_test_util.cc
 LOCAL_CPP_EXTENSION := .cc
 
 LOCAL_C_INCLUDES += external/flatbuffers/include
@@ -38,6 +42,7 @@
 
 LOCAL_SHARED_LIBRARIES := libandroid liblog libneuralnetworks
 LOCAL_STATIC_LIBRARIES := libgtest_ndk_c++ libgmock_ndk libtflite_static
+LOCAL_HEADER_LIBRARIES := libeigen gemmlowp_headers
 LOCAL_SDK_VERSION := current
 LOCAL_NDK_STL_VARIANT := c++_static
 include $(BUILD_STATIC_LIBRARY)
diff --git a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
index e125158..b999cfe 100644
--- a/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
+++ b/tests/tests/notificationlegacy/notificationlegacy27/src/android/app/notification/legacy/cts/ConditionProviderServiceTest.java
@@ -176,6 +176,7 @@
         // trigger a change in the bound service's condition
         ((LegacyConditionProviderService) LegacyConditionProviderService.getInstance())
                 .toggleDND(false);
+        sleep(500);
 
         // verify that the unbound service maintains it's DND vote
         assertEquals(INTERRUPTION_FILTER_ALARMS, mNm.getCurrentInterruptionFilter());
diff --git a/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
index 9643aef..60ede8b 100644
--- a/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
+++ b/tests/tests/os/src/android/os/storage/cts/StorageStatsManagerTest.java
@@ -20,12 +20,15 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assume.assumeTrue;
+
 import android.Manifest;
 import android.app.UiAutomation;
 import android.app.usage.StorageStatsManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Process;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.CrateInfo;
 import android.os.storage.StorageManager;
@@ -37,6 +40,7 @@
 import com.google.common.truth.Correspondence;
 
 import org.junit.After;
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -55,6 +59,8 @@
 @RunWith(AndroidJUnit4.class)
 public class StorageStatsManagerTest {
     private static final String CRATES_ROOT = "crates";
+    private final static boolean ENABLE_STORAGE_CRATES =
+            SystemProperties.getBoolean("fw.storage_crates", false);
 
     private Context mContext;
     private StorageManager mStorageManager;
@@ -120,6 +126,7 @@
 
     @Test
     public void queryCratesForUid_noCratedFolder_shouldBeEmpty() throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForUid(mUuid,
                 Process.myUid());
 
@@ -143,6 +150,7 @@
     }
     @Test
     public void queryCratesForUser_noCratedFolder_shouldBeEmpty() throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> collection = queryCratesForUser(true, mUuid,
                 Process.myUserHandle());
 
@@ -151,6 +159,7 @@
 
     @Test
     public void queryCratesForPackage_noCratedFolder_shouldBeEmpty() throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> collection = mStorageStatsManager.queryCratesForPackage(mUuid,
                 mContext.getOpPackageName(), Process.myUserHandle());
 
@@ -159,6 +168,7 @@
 
     @Test
     public void queryCratesForUid_withOtherUid_shouldRiseSecurityIssueException() throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         int fakeUid = UserHandle.getUid(MIN_SECONDARY_USER_ID,
                 UserHandle.getAppId(Process.myUid()));
         SecurityException securityException = null;
@@ -175,6 +185,7 @@
     @Test
     public void queryCratesForUser_withOtherUid_shouldRiseSecurityIssueException()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
         SecurityException securityException = null;
 
@@ -190,6 +201,7 @@
     @Test
     public void queryCratesForPackage_withOtherUid_shouldRiseSecurityIssueException()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         UserHandle fakeUserHandle = UserHandle.of(MIN_SECONDARY_USER_ID);
         SecurityException securityException = null;
 
@@ -206,6 +218,7 @@
     @Test
     public void queryCratesForUid_addOneDirectory_shouldIncreasingOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForUid(
                 mUuid, Process.myUid());
 
@@ -219,6 +232,7 @@
     @Test
     public void queryCratesForUser_addOneDirectory_shouldIncreasingOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> originalCollection = queryCratesForUser(true, mUuid,
                 Process.myUserHandle());
 
@@ -232,6 +246,7 @@
     @Test
     public void queryCratesForPackage_addOneDirectory_shouldIncreasingOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         Collection<CrateInfo> originalCollection = mStorageStatsManager.queryCratesForPackage(
                 mUuid, mContext.getOpPackageName(), Process.myUserHandle());
 
@@ -245,6 +260,7 @@
     @Test
     public void queryCratesForUid_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
@@ -256,6 +272,7 @@
     @Test
     public void queryCratesForUser_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos =  queryCratesForUser(true, mUuid,
@@ -267,6 +284,7 @@
     @Test
     public void queryCratesForPackage_withoutSetCrateInfo_labelShouldTheSameWithFolderName()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
@@ -278,6 +296,7 @@
     @Test
     public void queryCratesForUid_withoutSetCrateInfo_expirationShouldBeZero()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForUid(
@@ -289,6 +308,7 @@
     @Test
     public void queryCratesForUser_withoutSetCrateInfo_expirationShouldBeZero()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos =  queryCratesForUser(true, mUuid,
@@ -300,6 +320,7 @@
     @Test
     public void queryCratesForPackage_withoutSetCrateInfo_expirationShouldBeZero()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         mContext.getCrateDir(mCrateId);
 
         Collection<CrateInfo> crateInfos = mStorageStatsManager.queryCratesForPackage(
@@ -311,6 +332,7 @@
     @Test
     public void queryCratesForUid_removeCratedDir_shouldDecreaseTheNumberOfCrates()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         for (int i = 0; i < 3; i++) {
             mContext.getCrateDir(mCrateId + "_" + i);
         }
@@ -327,6 +349,7 @@
     @Test
     public void queryCratesForPackage_removeCratedDir_shouldDecreaseTheNumberOfCrates()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         for (int i = 0; i < 3; i++) {
             mContext.getCrateDir(mCrateId + "_" + i);
         }
@@ -343,6 +366,7 @@
     @Test
     public void queryCratesForUser_removeCratedDir_shouldDecreaseTheNumberOfCrates()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         for (int i = 0; i < 3; i++) {
             mContext.getCrateDir(mCrateId + "_" + i);
         }
@@ -371,6 +395,7 @@
     @Test
     public void queryCratesForUid_createDeepPath_shouldCreateOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
         Files.createDirectories(threeLevelPath);
 
@@ -384,6 +409,7 @@
     @Test
     public void queryCratesForUser_createDeepPath_shouldCreateOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
         Files.createDirectories(threeLevelPath);
 
@@ -397,6 +423,7 @@
     @Test
     public void queryCratesForPackage_createDeepPath_shouldCreateOneCrate()
             throws Exception {
+        assumeTrue("only test on the device with storage crates feature", ENABLE_STORAGE_CRATES);
         final Path threeLevelPath = mCrateDirPath.resolve("1").resolve("2").resolve("3");
         Files.createDirectories(threeLevelPath);
 
diff --git a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
index 1f8f283..54d4260 100644
--- a/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
+++ b/tests/tests/packageinstaller/atomicinstall/AndroidManifest.xml
@@ -17,6 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
           package="com.android.tests.atomicinstall" >
 
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <receiver android:name="com.android.cts.install.lib.LocalIntentSender"
                   android:exported="true" />
diff --git a/tests/tests/permission/AndroidManifest.xml b/tests/tests/permission/AndroidManifest.xml
index 6028ba5..4169ca2 100644
--- a/tests/tests/permission/AndroidManifest.xml
+++ b/tests/tests/permission/AndroidManifest.xml
@@ -47,6 +47,7 @@
                       android:name="android.permission.cts.groupC" />
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="android.permission.cts.PermissionStubActivity"
diff --git a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
index 2456edf..86e1260 100644
--- a/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
+++ b/tests/tests/permission/permissionTestUtilLib/src/android/permission/cts/PermissionUtils.java
@@ -42,6 +42,7 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PermissionInfo;
+import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
 
@@ -92,7 +93,12 @@
      * @param apkFile The apk to install
      */
     public static void install(@NonNull String apkFile) {
-        runShellCommand("pm install -r --force-sdk " + apkFile);
+        final int sdkVersion = Build.VERSION.SDK_INT
+                + (Build.VERSION.RELEASE_OR_CODENAME.equals("REL") ? 0 : 1);
+        boolean forceQueryable = sdkVersion > Build.VERSION_CODES.Q;
+        runShellCommand("pm install -r --force-sdk "
+                + (forceQueryable ? "--force-queryable " : "")
+                + apkFile);
     }
 
     /**
diff --git a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
index 1708b11..c578c19 100644
--- a/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
+++ b/tests/tests/permission/src/android/permission/cts/LocationAccessCheckTest.java
@@ -56,6 +56,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.platform.test.annotations.AppModeFull;
+import android.platform.test.annotations.SecurityTest;
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.notification.NotificationListenerService;
@@ -512,6 +513,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void notificationIsShownOnlyOnce() throws Throwable {
         accessLocation();
         getNotification(true);
@@ -520,6 +522,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void notificationIsShownAgainAfterClear() throws Throwable {
         accessLocation();
         getNotification(true);
@@ -556,6 +559,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void removeNotificationOnUninstall() throws Throwable {
         accessLocation();
         getNotification(false);
@@ -595,6 +599,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void noNotificationIfFeatureDisabled() throws Throwable {
         disableLocationAccessCheck();
         accessLocation();
@@ -602,6 +607,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void notificationOnlyForAccessesSinceFeatureWasEnabled() throws Throwable {
         // Disable the feature and access location in disabled state
         disableLocationAccessCheck();
@@ -618,6 +624,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void noNotificationIfBlamerNotSystemOrLocationProvider() throws Throwable {
         // Blame the app for access from an untrusted for notification purposes package.
         runWithShellPermissionIdentity(() -> {
@@ -629,6 +636,7 @@
     }
 
     @Test
+    @SecurityTest(minPatchLevel="2019-12-01")
     public void testOpeningLocationSettingsDoesNotTriggerAccess() throws Throwable {
         Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
diff --git a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
index 3dc2c71..bf20718 100644
--- a/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
+++ b/tests/tests/permission/src/android/permission/cts/OneTimePermissionTest.java
@@ -17,6 +17,7 @@
 package android.permission.cts;
 
 import static android.Manifest.permission.ACCESS_FINE_LOCATION;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
 
 import static com.android.compatibility.common.util.SystemUtil.eventually;
@@ -42,6 +43,9 @@
 import org.junit.Before;
 import org.junit.Test;
 
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+
 public class OneTimePermissionTest {
     private static final String APP_PKG_NAME = "android.permission.cts.appthatrequestpermission";
     private static final String APK =
@@ -57,6 +61,8 @@
             InstrumentationRegistry.getInstrumentation().getTargetContext();
     private final UiDevice mUiDevice =
             UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+    private final ActivityManager mActivityManager =
+            mContext.getSystemService(ActivityManager.class);
 
     private String mOldOneTimePermissionTimeoutValue;
 
@@ -98,46 +104,37 @@
     public void testOneTimePermission() throws Throwable {
         startApp();
 
+        CompletableFuture<Long> exitTime = registerAppExitListener();
+
         clickOneTimeButton();
 
-        pressHome();
+        exitApp();
 
         assertGranted(5000);
 
-        long oneTimeStart = System.currentTimeMillis();
-
         assertDenied(ONE_TIME_TIMEOUT_MILLIS + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
 
-        long grantedLength = System.currentTimeMillis() - oneTimeStart;
-        if (grantedLength + ONE_TIME_TIMER_LOWER_GRACE_PERIOD < ONE_TIME_TIMEOUT_MILLIS) {
-            throw new AssertionError(
-                    "The one time permission lived shorter than expected. expected: "
-                            + ONE_TIME_TIMEOUT_MILLIS + "ms but was: " + grantedLength + "ms");
-        }
+        assertExpectedLifespan(exitTime, ONE_TIME_TIMEOUT_MILLIS);
     }
 
     @Test
     public void testForegroundServiceMaintainsPermission() throws Throwable {
         startApp();
 
+        CompletableFuture<Long> exitTime = registerAppExitListener();
+
         clickOneTimeButton();
-        long oneTimeStart = System.currentTimeMillis();
 
-        long lifespanMillis = 2 * ONE_TIME_TIMEOUT_MILLIS;
-        startAppForegroundService(lifespanMillis);
+        long expectedLifespanMillis = 2 * ONE_TIME_TIMEOUT_MILLIS;
+        startAppForegroundService(expectedLifespanMillis);
 
-        pressHome();
+        exitApp();
 
         assertGranted(5000);
 
-        assertDenied(lifespanMillis + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
+        assertDenied(expectedLifespanMillis + ONE_TIME_TIMER_UPPER_GRACE_PERIOD);
 
-        long grantedLength = System.currentTimeMillis() - oneTimeStart;
-        if (grantedLength + ONE_TIME_TIMER_LOWER_GRACE_PERIOD < lifespanMillis) {
-            throw new AssertionError(
-                    "The one time permission lived shorter than expected. expected: "
-                            + lifespanMillis + "ms but was: " + grantedLength + "ms");
-        }
+        assertExpectedLifespan(exitTime, expectedLifespanMillis);
 
     }
 
@@ -147,7 +144,7 @@
 
         clickOneTimeButton();
 
-        pressHome();
+        exitApp();
 
         assertGranted(5000);
 
@@ -160,25 +157,44 @@
         assertDenied(500);
     }
 
-    private void assertGrantedState(String s, int permissionGranted, long timeoutMillis)
-            throws Throwable {
+    private void assertGrantedState(String s, int permissionGranted, long timeoutMillis) {
         eventually(() -> Assert.assertEquals(s,
                 permissionGranted, mContext.getPackageManager()
                         .checkPermission(ACCESS_FINE_LOCATION, APP_PKG_NAME)), timeoutMillis);
     }
 
-    private void assertGranted(long timeoutMillis) throws Throwable {
+    private void assertGranted(long timeoutMillis) {
         assertGrantedState("Permission was never granted", PackageManager.PERMISSION_GRANTED,
                 timeoutMillis);
     }
 
-    private void assertDenied(long timeoutMillis) throws Throwable {
+    private void assertDenied(long timeoutMillis) {
         assertGrantedState("Permission was never revoked", PackageManager.PERMISSION_DENIED,
                 timeoutMillis);
     }
 
-    private void pressHome() {
-        SystemUtil.runShellCommand("input keyevent KEYCODE_HOME");
+    private void assertExpectedLifespan(CompletableFuture<Long> exitTime, long expectedLifespan)
+            throws InterruptedException, java.util.concurrent.ExecutionException,
+            java.util.concurrent.TimeoutException {
+        long grantedLength = System.currentTimeMillis() - exitTime.get(0, TimeUnit.MILLISECONDS);
+        if (grantedLength + ONE_TIME_TIMER_LOWER_GRACE_PERIOD < expectedLifespan) {
+            throw new AssertionError(
+                    "The one time permission lived shorter than expected. expected: "
+                            + expectedLifespan + "ms but was: " + grantedLength + "ms");
+        }
+    }
+
+    private void exitApp() {
+        eventually(() -> {
+            mUiDevice.pressHome();
+            mUiDevice.pressBack();
+            runWithShellPermissionIdentity(() -> {
+                if (mActivityManager.getPackageImportance(APP_PKG_NAME)
+                        <= IMPORTANCE_FOREGROUND) {
+                    throw new AssertionError("Unable to exit application");
+                }
+            });
+        });
     }
 
     private void clickOneTimeButton() throws Throwable {
@@ -205,4 +221,38 @@
         intent.putExtra(EXTRA_FOREGROUND_SERVICE_LIFESPAN, lifespanMillis);
         mContext.startService(intent);
     }
+
+    private CompletableFuture<Long> registerAppExitListener() {
+        CompletableFuture<Long> exitTimeCallback = new CompletableFuture<>();
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(APP_PKG_NAME, 0);
+            runWithShellPermissionIdentity(() ->
+                    mActivityManager.addOnUidImportanceListener(new SingleAppExitListener(
+                            uid, IMPORTANCE_FOREGROUND, exitTimeCallback), IMPORTANCE_FOREGROUND));
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new AssertionError("Package not found.", e);
+        }
+        return exitTimeCallback;
+    }
+
+    private class SingleAppExitListener implements ActivityManager.OnUidImportanceListener {
+
+        private final int mUid;
+        private final int mImportance;
+        private final CompletableFuture<Long> mCallback;
+
+        SingleAppExitListener(int uid, int importance, CompletableFuture<Long> callback) {
+            mUid = uid;
+            mImportance = importance;
+            mCallback = callback;
+        }
+
+        @Override
+        public void onUidImportance(int uid, int importance) {
+            if (uid == mUid && importance > mImportance) {
+                mCallback.complete(System.currentTimeMillis());
+                mActivityManager.removeOnUidImportanceListener(this);
+            }
+        }
+    }
 }
diff --git a/tests/tests/permission/telephony/OWNERS b/tests/tests/permission/telephony/OWNERS
index 423a16b..b19c963 100644
--- a/tests/tests/permission/telephony/OWNERS
+++ b/tests/tests/permission/telephony/OWNERS
@@ -1,4 +1,2 @@
 set noparent
-amitmahajan@google.com
-fionaxu@google.com
-jminjie@google.com
\ No newline at end of file
+include ../../telephony/OWNERS
\ No newline at end of file
diff --git a/tests/tests/permission2/Android.bp b/tests/tests/permission2/Android.bp
index fa9a8ca..cb92e53 100644
--- a/tests/tests/permission2/Android.bp
+++ b/tests/tests/permission2/Android.bp
@@ -49,6 +49,7 @@
         ":CtsStoragePermissionsUserOptInSdk22",
         ":CtsStoragePermissionsUserOptInSdk28",
         ":CtsStoragePermissionsUserOptOutSdk29",
+        ":CtsStoragePermissionsPreservedUserOptOutSdk30",
         ":CtsLegacyStorageNotIsolatedWithSharedUid",
         ":CtsLegacyStorageIsolatedWithSharedUid",
         ":CtsLegacyStorageRestrictedWithSharedUid",
diff --git a/tests/tests/permission2/AndroidManifest.xml b/tests/tests/permission2/AndroidManifest.xml
index 065c0b4..c8b594a 100755
--- a/tests/tests/permission2/AndroidManifest.xml
+++ b/tests/tests/permission2/AndroidManifest.xml
@@ -19,6 +19,7 @@
     package="android.permission2.cts" android:targetSandboxVersion="2">
 
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/tests/permission2/AndroidTest.xml b/tests/tests/permission2/AndroidTest.xml
index 7594f4b..1bf1892 100644
--- a/tests/tests/permission2/AndroidTest.xml
+++ b/tests/tests/permission2/AndroidTest.xml
@@ -44,6 +44,7 @@
         <option name="push" value="CtsLegacyStorageRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedWithSharedUid.apk" />
         <option name="push" value="CtsLegacyStorageRestrictedSdk28WithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsLegacyStorageRestrictedSdk28WithSharedUid.apk" />
         <option name="push" value="CtsStoragePermissionsUserOptOutSdk30.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk30.apk" />
+        <option name="push" value="CtsStoragePermissionsPreservedUserOptOutSdk30.apk->/data/local/tmp/cts/permissions2/CtsStoragePermissionsPreservedUserOptOutSdk30.apk" />
         <option name="push" value="CtsSMSRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSRestrictedWithSharedUid.apk" />
         <option name="push" value="CtsSMSNotRestrictedWithSharedUid.apk->/data/local/tmp/cts/permissions2/CtsSMSNotRestrictedWithSharedUid.apk" />
     </target_preparer>
diff --git a/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp b/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp
new file mode 100644
index 0000000..59e67ab
--- /dev/null
+++ b/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/Android.bp
@@ -0,0 +1,22 @@
+//
+// Copyright (C) 2020 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.
+//
+
+android_test_helper_app {
+    name: "CtsStoragePermissionsPreservedUserOptOutSdk30",
+    defaults: ["cts_defaults"],
+
+    sdk_version: "current",
+}
\ No newline at end of file
diff --git a/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml b/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml
new file mode 100644
index 0000000..6a24150
--- /dev/null
+++ b/tests/tests/permission2/CtsStoragePermissionsPreservedUserOptOutSdk30/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.permission2.cts.restrictedpermissionuser"
+    android:versionCode="1">
+
+    <!-- Storage -->
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
+    <uses-sdk android:targetSdkVersion="30"/>
+
+    <application android:label="CtsStoragePermissionsPreservedUserOptOutSdk30"
+         android:preserveLegacyExternalStorage="true"/>
+
+</manifest>
diff --git a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
index 53086d3..95f725b 100644
--- a/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
+++ b/tests/tests/permission2/CtsStoragePermissionsUserDefaultSdk29/Android.bp
@@ -18,5 +18,5 @@
     name: "CtsStoragePermissionsUserDefaultSdk29",
     defaults: ["cts_defaults"],
 
-    sdk_version: "current",
+    sdk_version: "29",
 }
\ No newline at end of file
diff --git a/tests/tests/permission2/OWNERS b/tests/tests/permission2/OWNERS
index 503ac1e..3e44a8c 100644
--- a/tests/tests/permission2/OWNERS
+++ b/tests/tests/permission2/OWNERS
@@ -2,3 +2,5 @@
 moltmann@google.com
 svetoslavganov@google.com
 per-file NoLocationPermissionTest.java = hallliu@google.com
+per-file RestrictedStoragePermissionSharedUidTest.java = nandana@google.com
+per-file RestrictedStoragePermissionTest.java = nandana@google.com
diff --git a/tests/tests/permission2/res/raw/android_manifest.xml b/tests/tests/permission2/res/raw/android_manifest.xml
index d1ec825..650432f 100644
--- a/tests/tests/permission2/res/raw/android_manifest.xml
+++ b/tests/tests/permission2/res/raw/android_manifest.xml
@@ -43,14 +43,17 @@
     <protected-broadcast android:name="android.intent.action.PACKAGE_FULLY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_CHANGED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_ENABLE_ROLLBACK" />
+    <protected-broadcast android:name="android.intent.action.CANCEL_ENABLE_ROLLBACK" />
     <protected-broadcast android:name="android.intent.action.ROLLBACK_COMMITTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_RESTARTED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_DATA_CLEARED" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_FIRST_LAUNCH" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_INTEGRITY_VERIFICATION" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_NEEDS_VERIFICATION" />
     <protected-broadcast android:name="android.intent.action.PACKAGE_VERIFIED" />
     <protected-broadcast android:name="android.intent.action.PACKAGES_SUSPENDED" />
     <protected-broadcast android:name="android.intent.action.PACKAGES_UNSUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.PACKAGE_UNSUSPENDED_MANUALLY" />
     <protected-broadcast android:name="android.intent.action.DISTRACTING_PACKAGES_CHANGED" />
     <protected-broadcast android:name="android.intent.action.ACTION_PREFERRED_ACTIVITY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.UID_REMOVED" />
@@ -91,9 +94,9 @@
     <protected-broadcast android:name="android.intent.action.OVERLAY_CHANGED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_REMOVED" />
     <protected-broadcast android:name="android.intent.action.OVERLAY_PRIORITY_CHANGED" />
-    <protected-broadcast android:name="android.intent.action.USER_ACTIVITY_NOTIFICATION" />
     <protected-broadcast android:name="android.intent.action.MY_PACKAGE_SUSPENDED" />
     <protected-broadcast android:name="android.intent.action.MY_PACKAGE_UNSUSPENDED" />
+    <protected-broadcast android:name="android.intent.action.LOAD_DATA" />
 
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGING" />
@@ -102,6 +105,9 @@
     <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
 
+    <!-- @deprecated This is rarely used and will be phased out soon. -->
+    <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
+
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
     <protected-broadcast android:name="android.app.action.ENTER_CAR_MODE_PRIORITIZED" />
@@ -126,7 +132,6 @@
 
     <protected-broadcast android:name="android.os.action.SETTING_RESTORED" />
 
-    <protected-broadcast android:name="android.app.backup.intent.RUN" />
     <protected-broadcast android:name="android.app.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.app.backup.intent.INIT" />
 
@@ -140,7 +145,7 @@
     <protected-broadcast android:name="android.bluetooth.adapter.action.CONNECTION_STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.UUID" />
     <protected-broadcast android:name="android.bluetooth.device.action.MAS_INSTANCE" />
-    <protected-broadcast android:name="android.bluetooth.device.action.ALIAS_CHANGED" />
+    <protected-broadcast android:name="android.bluetooth.action.ALIAS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.FOUND" />
     <protected-broadcast android:name="android.bluetooth.device.action.CLASS_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.device.action.ACL_CONNECTED" />
@@ -342,6 +347,12 @@
     <protected-broadcast android:name="com.android.server.am.DELETE_DUMPHEAP" />
     <protected-broadcast android:name="com.android.server.net.action.SNOOZE_WARNING" />
     <protected-broadcast android:name="com.android.server.net.action.SNOOZE_RAPID" />
+    <protected-broadcast android:name="com.android.server.wifi.ACTION_SHOW_SET_RANDOMIZATION_DETAILS" />
+    <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_APP" />
+    <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_APP" />
+    <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISMISSED" />
+    <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_ALLOWED_CARRIER" />
+    <protected-broadcast android:name="com.android.server.wifi.action.NetworkSuggestion.USER_DISALLOWED_CARRIER" />
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.USER_DISMISSED_NOTIFICATION" />
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.CONNECT_TO_NETWORK" />
     <protected-broadcast android:name="com.android.server.wifi.ConnectToNetworkNotification.PICK_WIFI_NETWORK" />
@@ -353,7 +364,6 @@
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_AP_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_CREDENTIAL_CHANGED" />
-    <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.aware.action.WIFI_AWARE_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.rtt.action.WIFI_RTT_STATE_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.SCAN_RESULTS" />
@@ -361,12 +371,14 @@
     <protected-broadcast android:name="android.net.wifi.STATE_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.LINK_CONFIGURATION_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.CONFIGURED_NETWORKS_CHANGE" />
+    <protected-broadcast android:name="android.net.wifi.action.NETWORK_SETTINGS_RESET" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_DEAUTH_IMMINENT" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_ICON" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_OSU_PROVIDERS_LIST" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_SUBSCRIPTION_REMEDIATION" />
     <protected-broadcast android:name="android.net.wifi.action.PASSPOINT_LAUNCH_OSU_VIEW" />
     <protected-broadcast android:name="android.net.wifi.action.WIFI_NETWORK_SUGGESTION_POST_CONNECTION" />
+    <protected-broadcast android:name="android.net.wifi.action.WIFI_SCAN_AVAILABILITY_CHANGED" />
     <protected-broadcast android:name="android.net.wifi.supplicant.CONNECTION_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.supplicant.STATE_CHANGE" />
     <protected-broadcast android:name="android.net.wifi.p2p.STATE_CHANGED" />
@@ -379,7 +391,7 @@
     <protected-broadcast android:name="android.net.conn.INET_CONDITION_ACTION" />
     <protected-broadcast android:name="android.net.conn.NETWORK_CONDITIONS_MEASURED" />
     <protected-broadcast
-        android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
+            android:name="android.net.ConnectivityService.action.PKT_CNT_SAMPLE_INTERVAL_ELAPSED" />
     <protected-broadcast android:name="android.net.scoring.SCORE_NETWORKS" />
     <protected-broadcast android:name="android.net.scoring.SCORER_CHANGED" />
     <protected-broadcast android:name="android.intent.action.EXTERNAL_APPLICATIONS_AVAILABLE" />
@@ -435,6 +447,7 @@
 
     <protected-broadcast android:name="android.internal.policy.action.BURN_IN_PROTECTION" />
     <protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
+    <protected-broadcast android:name="android.app.action.RESET_PROTECTION_POLICY_CHANGED" />
     <protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
     <protected-broadcast android:name="android.app.action.MANAGED_USER_CREATED" />
 
@@ -511,6 +524,7 @@
     <protected-broadcast android:name="ScheduleConditionProvider.EVALUATE" />
     <protected-broadcast android:name="EventConditionProvider.EVALUATE" />
     <protected-broadcast android:name="SnoozeHelper.EVALUATE" />
+    <protected-broadcast android:name="wifi_scan_available" />
 
     <protected-broadcast android:name="action.cne.started" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DEADLINE_EXPIRED" />
@@ -533,6 +547,7 @@
     <protected-broadcast android:name="android.app.action.INTERRUPTION_FILTER_CHANGED_INTERNAL" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED" />
+    <protected-broadcast android:name="android.app.action.AUTOMATIC_ZEN_RULE_STATUS_CHANGED" />
     <protected-broadcast android:name="android.os.action.ACTION_EFFECTS_SUPPRESSOR_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_BLOCK_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.NOTIFICATION_CHANNEL_GROUP_BLOCK_STATE_CHANGED" />
@@ -618,6 +633,7 @@
 
     <!-- Added in Q -->
     <protected-broadcast android:name="android.content.pm.action.SESSION_UPDATED" />
+    <protected-broadcast android:name="android.settings.action.GRAYSCALE_CHANGED" />
 
     <!-- For CarIdlenessTracker -->
     <protected-broadcast android:name="com.android.server.jobscheduler.GARAGE_MODE_ON" />
@@ -640,6 +656,7 @@
     <!-- Grouping for platform runtime permissions is not accessible to apps
          @hide
          @SystemApi
+         @TestApi
     -->
     <permission-group android:name="android.permission-group.UNDEFINED"
         android:priority="100" />
@@ -649,18 +666,12 @@
     <!-- ====================================================================== -->
     <eat-comment />
 
-    <!-- @SystemApi Allows accessing the messages on ICC
-     @hide Used internally. -->
-    <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
-        android:protectionLevel="signature|telephony" />
-
     <!-- Used for runtime permissions related to contacts and profiles on this
         device. -->
     <permission-group android:name="android.permission-group.CONTACTS"
         android:icon="@drawable/perm_group_contacts"
         android:label="@string/permgrouplab_contacts"
         android:description="@string/permgroupdesc_contacts"
-        android:request="@string/permgrouprequest_contacts"
         android:priority="100" />
 
     <!-- Allows an application to read the user's contacts data.
@@ -691,7 +702,6 @@
         android:icon="@drawable/perm_group_calendar"
         android:label="@string/permgrouplab_calendar"
         android:description="@string/permgroupdesc_calendar"
-        android:request="@string/permgrouprequest_calendar"
         android:priority="200" />
 
     <!-- Allows an application to read the user's calendar data.
@@ -717,16 +727,24 @@
     <!-- ====================================================================== -->
     <eat-comment />
 
+    <!-- @SystemApi Allows accessing the messages on ICC
+         @hide Used internally. -->
+    <permission android:name="android.permission.ACCESS_MESSAGES_ON_ICC"
+        android:protectionLevel="signature|telephony" />
+
     <!-- Used for runtime permissions related to user's SMS messages. -->
     <permission-group android:name="android.permission-group.SMS"
         android:icon="@drawable/perm_group_sms"
         android:label="@string/permgrouplab_sms"
         android:description="@string/permgroupdesc_sms"
-        android:request="@string/permgrouprequest_sms"
         android:priority="300" />
 
     <!-- Allows an application to send SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.SEND_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -737,6 +755,10 @@
 
     <!-- Allows an application to receive SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -747,6 +769,10 @@
 
     <!-- Allows an application to read SMS messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_SMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -757,6 +783,10 @@
 
     <!-- Allows an application to receive WAP push messages.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_WAP_PUSH"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -766,7 +796,11 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to monitor incoming MMS messages.
-        <p>Protection level: dangerous
+         <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.RECEIVE_MMS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -775,6 +809,18 @@
         android:permissionFlags="hardRestricted"
         android:protectionLevel="dangerous" />
 
+    <!-- @SystemApi @TestApi Allows an application to forward cell broadcast messages to the cell
+         broadcast module. This is required in order to bind to the cell broadcast service, and
+         ensures that only the system can forward messages to it.
+
+         <p>Protection level: signature
+
+         @hide -->
+    <permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
+        android:label="@string/permlab_bindCellBroadcastService"
+        android:description="@string/permdesc_bindCellBroadcastService"
+        android:protectionLevel="signature" />
+
     <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
          messages and to register a content observer to get notifications when
          a cell broadcast has been received and added to the database. For
@@ -786,6 +832,11 @@
          when the alert is first received, and to delay presenting the info
          to the user until after the initial alert dialog is dismissed.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
          @hide Pending API council approval -->
     <permission android:name="android.permission.READ_CELL_BROADCASTS"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -804,30 +855,39 @@
         android:icon="@drawable/perm_group_storage"
         android:label="@string/permgrouplab_storage"
         android:description="@string/permgroupdesc_storage"
-        android:request="@string/permgrouprequest_storage"
         android:priority="900" />
 
     <!-- Allows an application to read from external storage.
-     <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
-     granted this permission.</p>
-     <p>This permission is enforced starting in API level 19.  Before API level 19, this
-     permission is not enforced and all apps still have access to read from external storage.
-     You can test your app with the permission enforced by enabling <em>Protect USB
-     storage</em> under Developer options in the Settings app on a device running Android 4.1 or
-     higher.</p>
-     <p>Also starting in API level 19, this permission is <em>not</em> required to
-     read/write files in your application-specific directories returned by
-     {@link android.content.Context#getExternalFilesDir} and
-     {@link android.content.Context#getExternalCacheDir}.
-     <p class="note"><strong>Note:</strong> If <em>both</em> your <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
-     minSdkVersion}</a> and <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-     targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
-     grants your app this permission. If you don't need this permission, be sure your <a
-     href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
-     targetSdkVersion}</a> is 4 or higher.
-     -->
+      <p>Any app that declares the {@link #WRITE_EXTERNAL_STORAGE} permission is implicitly
+      granted this permission.</p>
+      <p>This permission is enforced starting in API level 19.  Before API level 19, this
+      permission is not enforced and all apps still have access to read from external storage.
+      You can test your app with the permission enforced by enabling <em>Protect USB
+      storage</em> under Developer options in the Settings app on a device running Android 4.1 or
+      higher.</p>
+      <p>Also starting in API level 19, this permission is <em>not</em> required to
+      read/write files in your application-specific directories returned by
+      {@link android.content.Context#getExternalFilesDir} and
+      {@link android.content.Context#getExternalCacheDir}.
+      <p class="note"><strong>Note:</strong> If <em>both</em> your <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code
+      minSdkVersion}</a> and <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> values are set to 3 or lower, the system implicitly
+      grants your app this permission. If you don't need this permission, be sure your <a
+      href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
+      targetSdkVersion}</a> is 4 or higher.
+
+      <p> This is a soft restricted permission which cannot be held by an app it its
+      full form until the installer on record whitelists the permission.
+      Specifically, if the permission is whitelisted the holder app can access
+      external storage and the visual and aural media collections while if the
+      permission is not whitelisted the holder app can only access to the visual
+      and aural medial collections. Also the permission is immutably restricted
+      meaning that the whitelist state can be specified only at install time and
+      cannot change until the app is installed. For more details see
+      {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+     <p>Protection level: dangerous -->
     <permission android:name="android.permission.READ_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
@@ -848,6 +908,9 @@
          read/write files in your application-specific directories returned by
          {@link android.content.Context#getExternalFilesDir} and
          {@link android.content.Context#getExternalCacheDir}.
+         <p>If this permission is not whitelisted for an app that targets an API level before
+         {@link android.os.Build.VERSION_CODES#Q} this permission cannot be granted to apps.</p>
+         <p>Protection level: dangerous</p>
     -->
     <permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -857,7 +920,8 @@
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access any geographic locations persisted in the
-         user's shared collection. -->
+         user's shared collection.
+         <p>Protection level: dangerous -->
     <permission android:name="android.permission.ACCESS_MEDIA_LOCATION"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_mediaLocation"
@@ -871,8 +935,7 @@
 
     <!-- Allows an application a broad access to external storage in scoped storage.
          Intended to be used by few apps that need to manage files on behalf of the users.
-         <p>Protection level: signature|appop
-         <p>This protection level is temporary and will most likely be changed to |preinstalled -->
+         <p>Protection level: signature|appop|preinstalled -->
     <permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:protectionLevel="signature|appop|preinstalled" />
@@ -887,10 +950,6 @@
         android:icon="@drawable/perm_group_location"
         android:label="@string/permgrouplab_location"
         android:description="@string/permgroupdesc_location"
-        android:request="@string/permgrouprequest_location"
-        android:requestDetail="@string/permgrouprequestdetail_location"
-        android:backgroundRequest="@string/permgroupbackgroundrequest_location"
-        android:backgroundRequestDetail="@string/permgroupbackgroundrequestdetail_location"
         android:priority="400" />
 
     <!-- Allows an app to access precise location.
@@ -915,11 +974,15 @@
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
         android:protectionLevel="dangerous|instant" />
 
-    <!-- Allows an app to access location in the background.  If you
-         are requesting this, you should also request {@link #ACCESS_FINE_LOCATION}.
-         Requesting this by itself is not sufficient to give you
+    <!-- Allows an app to access location in the background. If you're requesting this permission,
+         you must also request either {@link #ACCESS_COARSE_LOCATION} or
+         {@link #ACCESS_FINE_LOCATION}. Requesting this permission by itself doesn't give you
          location access.
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -938,7 +1001,6 @@
         android:icon="@drawable/perm_group_call_log"
         android:label="@string/permgrouplab_calllog"
         android:description="@string/permgroupdesc_calllog"
-        android:request="@string/permgrouprequest_calllog"
         android:priority="450" />
 
     <!-- Allows an application to access the IMS call service: making and
@@ -962,6 +1024,10 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 16 or higher.</p>
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.READ_CALL_LOG"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -982,6 +1048,10 @@
          href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#target">{@code
          targetSdkVersion}</a> is 16 or higher.</p>
          <p>Protection level: dangerous
+
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
     -->
     <permission android:name="android.permission.WRITE_CALL_LOG"
         android:permissionGroup="android.permission-group.UNDEFINED"
@@ -995,6 +1065,10 @@
          abort the call altogether.
          <p>Protection level: dangerous
 
+         <p> This is a hard restricted permission which cannot be held by an app until
+         the installer on record whitelists the permission. For more details see
+         {@link android.content.pm.PackageInstaller.SessionParams#setWhitelistedRestrictedPermissions(Set)}.
+
          @deprecated Applications should use {@link android.telecom.CallRedirectionService} instead
          of the {@link android.content.Intent#ACTION_NEW_OUTGOING_CALL} broadcast.
     -->
@@ -1015,7 +1089,6 @@
         android:icon="@drawable/perm_group_phone_calls"
         android:label="@string/permgrouplab_phone"
         android:description="@string/permgroupdesc_phone"
-        android:request="@string/permgrouprequest_phone"
         android:priority="500" />
 
     <!-- Allows read only access to phone state, including the phone number of the device,
@@ -1091,9 +1164,9 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.MANAGE_OWN_CALLS"
-        android:label="@string/permlab_manageOwnCalls"
-        android:description="@string/permdesc_manageOwnCalls"
-        android:protectionLevel="normal" />
+                android:label="@string/permlab_manageOwnCalls"
+                android:description="@string/permdesc_manageOwnCalls"
+                android:protectionLevel="normal" />
 
     <!--Allows an app which implements the
         {@link android.telecom.InCallService InCallService} API to be eligible to be enabled as a
@@ -1103,9 +1176,9 @@
         <p>Protection level: normal
     -->
     <permission android:name="android.permission.CALL_COMPANION_APP"
-        android:label="@string/permlab_callCompanionApp"
-        android:description="@string/permdesc_callCompanionApp"
-        android:protectionLevel="normal" />
+                android:label="@string/permlab_callCompanionApp"
+                android:description="@string/permdesc_callCompanionApp"
+                android:protectionLevel="normal" />
 
     <!-- Allows a calling app to continue a call which was started in another app.  An example is a
          video calling app that wants to continue a voice call on the user's mobile network.<p>
@@ -1119,10 +1192,10 @@
          <p>Protection level: dangerous
     -->
     <permission android:name="android.permission.ACCEPT_HANDOVER"
-        android:permissionGroup="android.permission-group.UNDEFINED"
-        android.label="@string/permlab_acceptHandover"
-        android:description="@string/permdesc_acceptHandovers"
-        android:protectionLevel="dangerous" />
+                android:permissionGroup="android.permission-group.UNDEFINED"
+                android.label="@string/permlab_acceptHandover"
+                android:description="@string/permdesc_acceptHandovers"
+                android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device microphone                        -->
@@ -1136,7 +1209,6 @@
         android:icon="@drawable/perm_group_microphone"
         android:label="@string/permgrouplab_microphone"
         android:description="@string/permgroupdesc_microphone"
-        android:request="@string/permgrouprequest_microphone"
         android:priority="600" />
 
     <!-- Allows an application to record audio.
@@ -1158,7 +1230,6 @@
         android:icon="@drawable/perm_group_activity_recognition"
         android:label="@string/permgrouplab_activityRecognition"
         android:description="@string/permgroupdesc_activityRecognition"
-        android:request="@string/permgrouprequest_activityRecognition"
         android:priority="1000" />
 
     <!-- Allows an application to recognize physical activity.
@@ -1201,7 +1272,6 @@
         android:icon="@drawable/perm_group_camera"
         android:label="@string/permgrouplab_camera"
         android:description="@string/permgroupdesc_camera"
-        android:request="@string/permgrouprequest_camera"
         android:priority="700" />
 
     <!-- Required to be able to access the camera device.
@@ -1219,15 +1289,15 @@
         android:description="@string/permdesc_camera"
         android:protectionLevel="dangerous|instant" />
 
-    <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
-     system only camera devices.
-     <p>Protection level: system|signature
-     @hide -->
+      <!-- @SystemApi Required in addition to android.permission.CAMERA to be able to access
+           system only camera devices.
+           <p>Protection level: system|signature
+           @hide -->
     <permission android:name="android.permission.SYSTEM_CAMERA"
-                android:permissionGroup="android.permission-group.UNDEFINED"
-                android:label="@string/permlab_systemCamera"
-                android:description="@string/permdesc_systemCamera"
-                android:protectionLevel="system|signature" />
+        android:permissionGroup="android.permission-group.UNDEFINED"
+        android:label="@string/permlab_systemCamera"
+        android:description="@string/permdesc_systemCamera"
+        android:protectionLevel="system|signature" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device sensors                           -->
@@ -1240,7 +1310,6 @@
         android:icon="@drawable/perm_group_sensors"
         android:label="@string/permgrouplab_sensors"
         android:description="@string/permgroupdesc_sensors"
-        android:request="@string/permgrouprequest_sensors"
         android:priority="800" />
 
     <!-- Allows an application to access data from sensors that the user uses to
@@ -1399,7 +1468,7 @@
     <!-- @SystemApi @hide Allows an application to modify cell broadcasts through the content provider.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MODIFY_CELL_BROADCASTS"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- =============================================================== -->
     <!-- Permissions for setting the device alarm                        -->
@@ -1468,6 +1537,7 @@
     -->
     <permission android:name="android.permission.ACCESS_CONTEXT_HUB"
         android:protectionLevel="signature|privileged" />
+    <uses-permission android:name="android.permission.ACCESS_CONTEXT_HUB"/>
 
     <!-- @SystemApi Allows an application to create mock location providers for testing.
          <p>Protection level: signature
@@ -1557,6 +1627,7 @@
 
     <!-- Allows applications to request network
          recommendations and scores from the NetworkScoreService.
+         @SystemApi
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.REQUEST_NETWORK_SCORES"
         android:protectionLevel="signature|setup" />
@@ -1569,6 +1640,7 @@
 
     <!-- Allows network stack services (Connectivity and Wifi) to coordinate
          <p>Not for use by third-party or privileged applications.
+         @SystemApi
          @hide This should only be used by Connectivity and Wifi Services.
     -->
     <permission android:name="android.permission.NETWORK_STACK"
@@ -1584,6 +1656,7 @@
 
     <!-- Allows Settings and SystemUI to call methods in Networking services
          <p>Not for use by third-party or privileged applications.
+         @SystemApi
          @hide This should only be used by Settings and SystemUI.
     -->
     <permission android:name="android.permission.NETWORK_SETTINGS"
@@ -1596,7 +1669,7 @@
          @hide
     -->
     <permission android:name="android.permission.RADIO_SCAN_WITHOUT_LOCATION"
-        android:protectionLevel="signature|companion" />
+                android:protectionLevel="signature|companion" />
 
     <!-- Allows SetupWizard to call methods in Networking services
          <p>Not for use by any other third-party or privileged applications.
@@ -1649,13 +1722,13 @@
     <permission android:name="android.permission.NETWORK_BYPASS_PRIVATE_DNS"
         android:protectionLevel="signature" />
 
-    <!-- #SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can be increased
-         when the device is stationary in order to save power.
+    <!-- @SystemApi @hide Allows device mobility state to be set so that Wifi scan interval can
+         be increased when the device is stationary in order to save power.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_SET_DEVICE_MOBILITY_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- #SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
+    <!-- @SystemApi @hide Allows privileged system APK to update Wifi usability stats and score.
          <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.WIFI_UPDATE_USABILITY_STATS_SCORE"
         android:protectionLevel="signature|privileged" />
@@ -1673,8 +1746,8 @@
         android:label="@string/permlab_bluetooth"
         android:protectionLevel="normal" />
 
-    <!-- @SystemApi Allows an application to suspend other apps, which will prevent the user
-         from using them until they are unsuspended.
+    <!-- @SystemApi @TestApi Allows an application to suspend other apps, which will prevent the
+         user from using them until they are unsuspended.
          @hide
     -->
     <permission android:name="android.permission.SUSPEND_APPS"
@@ -1690,7 +1763,7 @@
 
     <!-- Allows applications to pair bluetooth devices without user interaction, and to
          allow or disallow phonebook access or message access.
-         This is not available to third party applications. -->
+         <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.BLUETOOTH_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -1718,7 +1791,7 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.NFC_TRANSACTION_EVENT"
-        android:protectionLevel="normal" />
+      android:protectionLevel="normal" />
 
     <!-- Allows applications to receive NFC preferred payment service information.
          <p>Protection level: normal
@@ -1733,7 +1806,11 @@
     <permission android:name="android.permission.SECURE_ELEMENT_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
+    <!-- @deprecated This permission used to allow too broad access to sensitive methods and all its
+         uses have been replaced by a more appropriate permission. Most uses have been replaced with
+         a NETWORK_STACK or NETWORK_SETTINGS check. Please look up the documentation of the
+         individual functions to figure out what permission now protects the individual function.
+         @SystemApi Allows an internal user to use privileged ConnectivityManager APIs.
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_INTERNAL"
         android:protectionLevel="signature|privileged" />
@@ -1742,12 +1819,13 @@
          @hide -->
     <permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"
         android:protectionLevel="signature|privileged" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
 
     <!-- @SystemApi Allows an internal user to set signal strength in NetworkRequest. This kind of
          request will wake up device when signal strength meets the given value.
          @hide -->
     <permission android:name="android.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows a system application to access hardware packet offload capabilities.
          @hide -->
@@ -1926,17 +2004,17 @@
     <permission android:name="android.permission.REMOTE_AUDIO_PLAYBACK"
         android:protectionLevel="signature" />
 
-    <!-- @SystemApi Allows TvInputService to access underlying TV input hardware such as
+    <!-- Allows TvInputService to access underlying TV input hardware such as
          built-in tuners and HDMI-in's.
-         @hide This should only be used by OEM's TvInputService's.
-    -->
+         <p>This should only be used by OEM's TvInputService's.
+         @hide @SystemApi -->
     <permission android:name="android.permission.TV_INPUT_HARDWARE"
         android:protectionLevel="signature|privileged|vendorPrivileged" />
 
-    <!-- @SystemApi Allows to capture a frame of TV input hardware such as
+    <!-- Allows to capture a frame of TV input hardware such as
          built-in tuners and HDMI-in's.
-         @hide <p>Not for use by third-party applications.
-    -->
+         <p>Not for use by third-party applications.
+         @hide @SystemApi -->
     <permission android:name="android.permission.CAPTURE_TV_INPUT"
         android:protectionLevel="signature|privileged" />
 
@@ -2013,26 +2091,27 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- Allows read only access to precise phone state.
-         @hide Pending API council approval -->
+         Allows reading of detailed information about phone state for special-use applications
+         such as dialers, carrier applications, or ims applications. -->
     <permission android:name="android.permission.READ_PRECISE_PHONE_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows listen permission to always reported signal strength.
-         @hide Used internally. -->
-    <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
-        android:protectionLevel="signature|telephony" />
-
-    <!-- @SystemApi Allows read access to emergency number information for ongoing calls or SMS
-         sessions.
-         @hide -->
-    <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
-        android:protectionLevel="signature" />
-
     <!-- @SystemApi Allows read access to privileged phone state.
          @hide Used internally. -->
     <permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows read access to emergency number information for ongoing calls or SMS
+         sessions.
+         @hide Used internally. -->
+    <permission android:name="android.permission.READ_ACTIVE_EMERGENCY_SESSION"
+        android:protectionLevel="signature" />
+
+    <!-- @SystemApi Allows listen permission to always reported signal strength.
+         @hide Used internally. -->
+    <permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH"
+        android:protectionLevel="signature|telephony" />
+
     <!-- @SystemApi Protects the ability to register any PhoneAccount with
          PhoneAccount#CAPABILITY_SIM_SUBSCRIPTION. This capability indicates that the PhoneAccount
          corresponds to a device SIM.
@@ -2070,8 +2149,8 @@
          <p>Protection level: signature|privileged
     -->
     <permission
-        android:name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
-        android:protectionLevel="signature|privileged"/>
+      android:name="android.permission.BIND_VISUAL_VOICEMAIL_SERVICE"
+      android:protectionLevel="signature|privileged"/>
 
     <!-- Must be required by a {@link android.telecom.CallScreeningService},
          to ensure that only the system can bind to it.
@@ -2094,7 +2173,7 @@
          <p>Protection level: signature|privileged
     -->
     <permission android:name="android.permission.BIND_CALL_REDIRECTION_SERVICE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by a {@link android.telecom.ConnectionService},
          to ensure that only the system can bind to it.
@@ -2122,8 +2201,8 @@
     <permission android:name="android.permission.RECEIVE_STK_COMMANDS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to send EMBMS download intents to apps
-         @hide -->
+      <!-- Allows an application to send EMBMS download intents to apps
+           @hide -->
     <permission android:name="android.permission.SEND_EMBMS_INTENTS"
         android:protectionLevel="signature|privileged" />
 
@@ -2151,14 +2230,14 @@
     <permission android:name="android.permission.BIND_TELEPHONY_DATA_SERVICE"
         android:protectionLevel="signature|telephony" />
 
-    <!-- Must be required by a telephony network service to ensure that only the
+    <!-- Must be required by a NetworkService to ensure that only the
          system can bind to it.
          <p>Protection level: signature|telephony
          @SystemApi
          @hide
     -->
     <permission android:name="android.permission.BIND_TELEPHONY_NETWORK_SERVICE"
-        android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature|telephony" />
 
     <!-- @SystemApi Allows an application to manage embedded subscriptions (those on a eUICC)
          through EuiccManager APIs.
@@ -2166,15 +2245,15 @@
          @hide
     -->
     <permission android:name="android.permission.WRITE_EMBEDDED_SUBSCRIPTIONS"
-        android:protectionLevel="signature|privileged|development" />
+                android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Must be required by an EuiccService to ensure that only the system can bind to
          it.
-         <p>Protection level: signature
+         <p>Protection level: signature|telephony
          @hide
     -->
     <permission android:name="android.permission.BIND_EUICC_SERVICE"
-        android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature|telephony" />
 
     <!-- Required for reading information about carrier apps from SystemConfigManager.
          <p>Protection level: signature|telephony
@@ -2208,6 +2287,9 @@
 
     <!-- Allows an application to manage access to crates, usually as part
          of a crates picker.
+         <p>This permission should <em>only</em> be requested by the platform
+         management app.  This permission cannot be granted to
+         third-party apps.
          @hide
          @TestApi
     -->
@@ -2254,9 +2336,9 @@
      <p>Protection level: normal
     -->
     <permission android:name="android.permission.REQUEST_PASSWORD_COMPLEXITY"
-        android:label="@string/permlab_requestPasswordComplexity"
-        android:description="@string/permdesc_requestPasswordComplexity"
-        android:protectionLevel="normal" />
+                android:label="@string/permlab_requestPasswordComplexity"
+                android:description="@string/permdesc_requestPasswordComplexity"
+                android:protectionLevel="normal" />
 
     <!-- ================================== -->
     <!-- Permissions to access other installed applications  -->
@@ -2300,6 +2382,7 @@
          @hide -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:protectionLevel="signature|installer|telephony" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
 
     <!-- Allows interaction across profiles in the same profile group. -->
     <permission android:name="android.permission.INTERACT_ACROSS_PROFILES"
@@ -2317,7 +2400,7 @@
     <permission android:name="android.permission.MANAGE_USERS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @hide Allows an application to create, remove users and get the list of
+    <!-- @SystemApi @hide Allows an application to create, remove users and get the list of
          users on the device. Applications holding this permission can only create restricted,
          guest, managed, demo, and ephemeral users. For creating other kind of users,
          {@link android.Manifest.permission#MANAGE_USERS} is needed.
@@ -2356,7 +2439,7 @@
 
     <!-- @SystemApi @TestApi @hide Allows an application to embed other activities -->
     <permission android:name="android.permission.ACTIVITY_EMBEDDING"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Allows an application to start any activity, regardless of permission
          protection or exported state.
@@ -2375,7 +2458,7 @@
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
     <uses-permission android:name="android.permission.SEND_SHOW_SUSPENDED_APP_DETAILS" />
 
     <!-- Allows an application to start an activity as another app, provided that app has been
@@ -2430,7 +2513,7 @@
          The app can check whether it has this authorization by calling
          {@link android.provider.Settings#canDrawOverlays
          Settings.canDrawOverlays()}.
-         <p>Protection level: signature -->
+         <p>Protection level: signature|preinstalled|appop|pre23|development -->
     <permission android:name="android.permission.SYSTEM_ALERT_WINDOW"
         android:label="@string/permlab_systemAlertWindow"
         android:description="@string/permdesc_systemAlertWindow"
@@ -2462,17 +2545,17 @@
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.REQUEST_COMPANION_RUN_IN_BACKGROUND"
-        android:label="@string/permlab_runInBackground"
-        android:description="@string/permdesc_runInBackground"
-        android:protectionLevel="normal" />
+                android:label="@string/permlab_runInBackground"
+                android:description="@string/permdesc_runInBackground"
+                android:protectionLevel="normal" />
 
     <!-- Allows a companion app to use data in the background.
          <p>Protection level: normal
     -->
     <permission android:name="android.permission.REQUEST_COMPANION_USE_DATA_IN_BACKGROUND"
-        android:label="@string/permlab_useDataInBackground"
-        android:description="@string/permdesc_useDataInBackground"
-        android:protectionLevel="normal" />
+                android:label="@string/permlab_useDataInBackground"
+                android:description="@string/permdesc_useDataInBackground"
+                android:protectionLevel="normal" />
 
     <!-- Allows a companion app to associate to Wi-Fi.
          <p>Only for use by a single pre-approved app.
@@ -2480,7 +2563,8 @@
          @SystemApi
     -->
     <permission android:name="android.permission.COMPANION_APPROVE_WIFI_CONNECTIONS"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
+
 
     <!-- ================================== -->
     <!-- Permissions affecting the system wallpaper -->
@@ -2622,7 +2706,8 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to modify the current configuration, such
-         as locale. -->
+         as locale.
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.CHANGE_CONFIGURATION"
         android:protectionLevel="signature|privileged|development" />
 
@@ -2636,7 +2721,7 @@
         can check whether it has this authorization by calling {@link
         android.provider.Settings.System#canWrite Settings.System.canWrite()}.
 
-        <p>Protection level: signature
+        <p>Protection level: signature|preinstalled|appop|pre23
     -->
     <permission android:name="android.permission.WRITE_SETTINGS"
         android:label="@string/permlab_writeSettings"
@@ -2658,10 +2743,10 @@
     <permission android:name="android.permission.READ_DEVICE_CONFIG"
         android:protectionLevel="signature|preinstalled" />
 
-    <!-- @SystemApi @hide Allows an application to monitor access to config settings.
+    <!-- @SystemApi @hide Allows an application to monitor config settings access.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MONITOR_DEVICE_CONFIG_ACCESS"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature"/>
 
     <!-- @SystemApi @TestApi Allows an application to call
         {@link android.app.ActivityManager#forceStopPackage}.
@@ -2829,7 +2914,7 @@
          on device.
          @SystemApi @hide -->
     <permission android:name="android.permission.QUERY_TIME_ZONE_RULES"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Allows a time zone rule updater application to request
          the system installs / uninstalls timezone rules.
@@ -2921,17 +3006,13 @@
     <permission android:name="android.permission.REQUEST_INCIDENT_REPORT_APPROVAL"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @hide @SystemApi
-         Allows an application to register stats pull atom callbacks.
-    <p>Not for use by third-party applications.-->
-    <permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
-        android:protectionLevel="signature|privileged" />
     <!-- ==================================== -->
     <!-- Private permissions                  -->
     <!-- ==================================== -->
     <eat-comment />
 
-    <!-- Allows access to the list of accounts in the Accounts Service. -->
+    <!-- Allows access to the list of accounts in the Accounts Service.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
@@ -2951,16 +3032,19 @@
     <permission android:name="android.permission.STATUS_BAR"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
-    @hide -->
-    <permission android:name="android.permission.STATUS_BAR_SERVICE"
-        android:protectionLevel="signature|telephony" />
-
-    <!-- Allows an application to trigger bugreports via the shell app (which uses bugreport API)
-    @hide -->
+    <!-- Allows an application to trigger bugreport via shell using the bugreport API.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
     <permission android:name="android.permission.TRIGGER_SHELL_BUGREPORT"
         android:protectionLevel="signature" />
 
+    <!-- Allows an application to be the status bar.  Currently used only by SystemUI.apk
+    @hide -->
+    // TODO: remove telephony once decouple settings activity from phone process
+    <permission android:name="android.permission.STATUS_BAR_SERVICE"
+        android:protectionLevel="signature|telephony" />
+
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
          TileService declarations.-->
@@ -3026,7 +3110,7 @@
          @hide
     -->
     <permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- @SystemApi Allows an application to manage (create, destroy,
          Z-order) application tokens in the window manager.
@@ -3066,15 +3150,15 @@
 
     <!-- @hide Allows an application to modify accessibility information from another app. -->
     <permission android:name="android.permission.MODIFY_ACCESSIBILITY_DATA"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to change the accessibility volume. -->
     <permission android:name="android.permission.CHANGE_ACCESSIBILITY_VOLUME"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to collect frame statistics -->
     <permission android:name="android.permission.FRAME_STATS"
-        android:protectionLevel="signature" />
+         android:protectionLevel="signature" />
 
     <!-- @hide Allows an application to temporary enable accessibility on the device. -->
     <permission android:name="android.permission.TEMPORARY_ENABLE_ACCESSIBILITY"
@@ -3160,7 +3244,7 @@
      <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_PRINT_RECOMMENDATION_SERVICE"
-        android:protectionLevel="signature" />
+            android:protectionLevel="signature" />
 
     <!-- Allows applications to get the installed and enabled print services.
          @hide
@@ -3187,8 +3271,8 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.service.quickaccesswallet.QuickAccessWalletService}
-     to ensure that only the system can bind to it.
-     <p>Protection level: signature
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_QUICK_ACCESS_WALLET_SERVICE"
                 android:protectionLevel="signature" />
@@ -3222,7 +3306,7 @@
          @hide
     -->
     <permission android:name="android.permission.BIND_ATTENTION_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
     <uses-permission android:name="android.permission.BIND_ATTENTION_SERVICE" />
 
     <!-- Must be required by a {@link android.net.VpnService},
@@ -3253,12 +3337,12 @@
     <permission android:name="android.permission.BIND_AUTOFILL_SERVICE"
         android:protectionLevel="signature" />
 
-    <!-- Alternative version of android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE.
-         This permission was renamed during the O previews but it was supported on the final O
-         release, so we need to carry it over.
-         <p>Protection level: signature
-         @hide
-     -->
+   <!-- Alternative version of android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE.
+        This permission was renamed during the O previews but it was supported on the final O
+        release, so we need to carry it over.
+        <p>Protection level: signature
+        @hide
+    -->
     <permission android:name="android.permission.BIND_AUTOFILL"
         android:protectionLevel="signature" />
 
@@ -3267,14 +3351,14 @@
          @hide This is not a third-party API (intended for OEMs and system apps).
     -->
     <permission android:name="android.permission.BIND_AUTOFILL_FIELD_CLASSIFICATION_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by an {@link android.service.autofill.InlineSuggestionRenderService}
          to ensure that only the system can bind to it.
          @hide This is not a third-party API (intended for OEMs and system apps).
     -->
     <permission android:name="android.permission.BIND_INLINE_SUGGESTION_RENDER_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by a android.service.textclassifier.TextClassifierService,
          to ensure that only the system can bind to it.
@@ -3282,7 +3366,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_TEXTCLASSIFIER_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by a android.service.contentcapture.ContentCaptureService,
          to ensure that only the system can bind to it.
@@ -3290,7 +3374,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_CONTENT_CAPTURE_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by a android.service.contentsuggestions.ContentSuggestionsService,
          to ensure that only the system can bind to it.
@@ -3298,7 +3382,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_CONTENT_SUGGESTIONS_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by a android.service.autofill.augmented.AugmentedAutofillService,
          to ensure that only the system can bind to it.
@@ -3306,7 +3390,7 @@
          <p>Protection level: signature
     -->
     <permission android:name="android.permission.BIND_AUGMENTED_AUTOFILL_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Must be required by hotword enrollment application,
          to ensure that only the system can interact with it.
@@ -3362,12 +3446,12 @@
     <permission android:name="android.permission.READ_CONTENT_RATING_SYSTEMS"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows an application to notify TV inputs by sending broadcasts.
+    <!-- Allows an application to notify TV inputs by sending broadcasts.
          <p>Protection level: signature|privileged
          <p>Not for use by third-party applications.
-         @hide -->
+         @hide @SystemApi -->
     <permission android:name="android.permission.NOTIFY_TV_INPUTS"
-        android:protectionLevel="signature|privileged" />
+         android:protectionLevel="signature|privileged" />
 
     <!-- This permission is required among systems services when accessing
          tuner resource management related APIs or information.
@@ -3475,7 +3559,7 @@
     <!-- Allows an application to install packages.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.INSTALL_PACKAGES"
-        android:protectionLevel="signature|privileged" />
+      android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to install self updates. This is a limited version
          of {@link android.Manifest.permission#INSTALL_PACKAGES}.
@@ -3532,8 +3616,8 @@
          <p>Protection level: signature
     -->
     <permission
-        android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
-        android:protectionLevel="signature" />
+         android:name="android.permission.MANAGE_SCOPED_ACCESS_DIRECTORY_PERMISSIONS"
+         android:protectionLevel="signature" />
 
     <!-- @hide
          Allows an application to change the status of a persistable URI permission granted
@@ -3546,7 +3630,8 @@
         android:protectionLevel="signature" />
 
     <!-- Old permission for deleting an app's cache files, no longer used,
-         but signals for us to quietly ignore calls instead of throwing an exception. -->
+         but signals for us to quietly ignore calls instead of throwing an exception.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.DELETE_CACHE_FILES"
         android:protectionLevel="signature|privileged" />
 
@@ -3588,12 +3673,12 @@
     <!-- @SystemApi Allows an application to revoke specific permissions.
         @hide -->
     <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
-        android:protectionLevel="signature|installer|verifier" />
+         android:protectionLevel="signature|installer|verifier" />
 
     <!-- @SystemApi Allows the system to read runtime permission state.
         @hide -->
     <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows the system to restore runtime permission state. This might grant
     permissions, hence this is a more scoped, less powerful variant of GRANT_RUNTIME_PERMISSIONS.
@@ -3605,10 +3690,9 @@
     <!-- @SystemApi Allows an application to change policy_fixed permissions.
     @hide -->
     <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
-    <!-- @TestApi Allows an application to upgrade runtime permissions.
-    @hide -->
+    <!-- @hide Allows an application to upgrade runtime permissions. -->
     <permission android:name="android.permission.UPGRADE_RUNTIME_PERMISSIONS"
                 android:protectionLevel="signature" />
 
@@ -3616,7 +3700,7 @@
          on any of the whitelists.
     @hide -->
     <permission android:name="android.permission.WHITELIST_RESTRICTED_PERMISSIONS"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
@@ -3631,12 +3715,12 @@
          @hide
          STOPSHIP b/145526313: Remove wellbeing protection flag from MANAGE_ROLE_HOLDERS. -->
     <permission android:name="android.permission.MANAGE_ROLE_HOLDERS"
-        android:protectionLevel="signature|installer|telephony|wellbeing" />
+                android:protectionLevel="signature|installer|telephony|wellbeing" />
 
     <!-- @SystemApi Allows an application to observe role holder changes.
          @hide -->
     <permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- Allows an application to manage the companion devices.
          @hide -->
@@ -3671,7 +3755,8 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to configure and connect to Wifi displays
-         @hide -->
+         @hide
+         @SystemApi -->
     <permission android:name="android.permission.CONFIGURE_WIFI_DISPLAY"
         android:protectionLevel="signature" />
 
@@ -3862,11 +3947,11 @@
     <permission android:name="android.permission.REBOOT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows low-level access to power management.
-         <p>Not for use by third-party applications.
-         @hide
-     -->
-    <permission android:name="android.permission.DEVICE_POWER"
+   <!-- @SystemApi Allows low-level access to power management.
+        <p>Not for use by third-party applications.
+        @hide
+    -->
+   <permission android:name="android.permission.DEVICE_POWER"
         android:protectionLevel="signature|telephony" />
 
     <!-- Allows toggling battery saver on the system.
@@ -3875,12 +3960,12 @@
     <permission android:name="android.permission.POWER_SAVER"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows access to the PowerManager.userActivity function.
-    <p>Not for use by third-party applications. @hide @SystemApi -->
+   <!-- Allows access to the PowerManager.userActivity function.
+   <p>Not for use by third-party applications. @hide @SystemApi -->
     <permission android:name="android.permission.USER_ACTIVITY"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @hide Allows low-level access to tun tap driver -->
+   <!-- @hide Allows low-level access to tun tap driver -->
     <permission android:name="android.permission.NET_TUNNELING"
         android:protectionLevel="signature" />
 
@@ -3952,11 +4037,21 @@
     <!-- Allows an application to collect component usage
          statistics
          <p>Declaring the permission implies intention to use the API and the user of the
-         device can grant permission through the Settings application. -->
+         device can grant permission through the Settings application.
+         <p>Protection level: signature|privileged|development|appop|retailDemo -->
     <permission android:name="android.permission.PACKAGE_USAGE_STATS"
         android:protectionLevel="signature|privileged|development|appop|retailDemo" />
     <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS" />
 
+    <!-- Allows a data loader to read a package's access logs. The access logs contain the
+         set of pages referenced over time.
+         <p>Declaring the permission implies intention to use the API and the user of the
+         device can grant permission through the Settings application.
+         <p>Protection level: signature|privileged|appop -->
+    <permission android:name="android.permission.LOADER_USAGE_STATS"
+        android:protectionLevel="signature|privileged|appop" />
+    <uses-permission android:name="android.permission.LOADER_USAGE_STATS" />
+
     <!-- @hide @SystemApi Allows an application to observe usage time of apps. The app can register
          for callbacks when apps reach a certain usage time limit, etc. -->
     <permission android:name="android.permission.OBSERVE_APP_USAGE"
@@ -3975,14 +4070,14 @@
 
     <!-- Permission an application must hold in order to use
          {@link android.provider.Settings#ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS}.
-         This is a normal permission: an app requesting it will always be granted the
-         permission, without the user needing to approve or see it. -->
+         <p>Protection level: normal -->
     <permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"
         android:label="@string/permlab_requestIgnoreBatteryOptimizations"
         android:description="@string/permdesc_requestIgnoreBatteryOptimizations"
         android:protectionLevel="normal" />
 
-    <!-- Allows an application to collect battery statistics -->
+    <!-- Allows an application to collect battery statistics
+         <p>Protection level: signature|privileged|development -->
     <permission android:name="android.permission.BATTERY_STATS"
         android:protectionLevel="signature|privileged|development" />
 
@@ -3992,6 +4087,11 @@
     <permission android:name="android.permission.STATSCOMPANION"
         android:protectionLevel="signature" />
 
+    <!--@SystemApi @hide Allows an application to register stats pull atom callbacks.
+    <p>Not for use by third-party applications.-->
+    <permission android:name="android.permission.REGISTER_STATS_PULL_ATOM"
+                android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to control the backup and restore process.
     <p>Not for use by third-party applications.
          @hide pending API council -->
@@ -4019,7 +4119,8 @@
         android:protectionLevel="signature" />
 
     <!-- Must be required by a {@link android.widget.RemoteViewsService},
-         to ensure that only the system can bind to it. -->
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.BIND_REMOTEVIEWS"
         android:protectionLevel="signature|privileged" />
 
@@ -4061,7 +4162,8 @@
          to the path in the provider where global search queries are
          performed.  This permission can not be held by regular applications;
          it is used by applications to protect themselves from everyone else
-         besides global search. -->
+         besides global search.
+         <p>Protection level: signature|privileged -->
     <permission android:name="android.permission.GLOBAL_SEARCH"
         android:protectionLevel="signature|privileged" />
 
@@ -4083,11 +4185,11 @@
     <!-- @SystemApi Internal permission to allows an application to bind to suggestion service.
         @hide -->
     <permission android:name="android.permission.BIND_SETTINGS_SUGGESTIONS_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @hide Internal permission to allows an application to access card content provider. -->
     <permission android:name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows applications to set a live wallpaper.
          @hide XXX Change to signature once the picker is moved to its
@@ -4146,7 +4248,7 @@
          @hide Used internally.
      -->
     <permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"
-        android:protectionLevel="signature" />
+          android:protectionLevel="signature" />
     <uses-permission android:name="android.intent.category.MASTER_CLEAR.permission.C2D_MESSAGE"/>
 
     <!-- @SystemApi @hide Package verifier needs to have this permission before the PackageManager will
@@ -4186,7 +4288,7 @@
     <permission android:name="android.permission.INTENT_FILTER_VERIFICATION_AGENT"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Must be required by intent filter verifier receiver, to ensure that only the
+    <!-- Must be required by intent filter verifier rintent-filtereceiver, to ensure that only the
          system can interact with it.
          @hide
     -->
@@ -4218,7 +4320,7 @@
          User permission is still required before access is granted.
          @hide -->
     <permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi @TestApi Allows an application to read the current set of notifications, including
          any metadata and intents attached.
@@ -4239,12 +4341,12 @@
         processes.
         @hide -->
     <permission android:name="android.permission.MANAGE_NOTIFICATIONS"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Allows notifications to be colorized
          <p>Not for use by third-party applications. @hide -->
     <permission android:name="android.permission.USE_COLORIZED_NOTIFICATIONS"
-        android:protectionLevel="signature|setup" />
+                android:protectionLevel="signature|setup" />
 
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
         @hide -->
@@ -4339,6 +4441,10 @@
          android.service.chooser.ChooserTargetService}, to ensure that
          only the system can bind to it.
          <p>Protection level: signature
+
+         @deprecated For publishing direct share targets, please follow the instructions in
+         https://developer.android.com/training/sharing/receive.html#providing-direct-share-targets
+         instead.
     -->
     <permission android:name="android.permission.BIND_CHOOSER_TARGET_SERVICE"
         android:protectionLevel="signature" />
@@ -4349,7 +4455,7 @@
          @hide
     -->
     <permission android:name="android.permission.PROVIDE_RESOLVER_RANKER_SERVICE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Must be required by services that extend
          {@link android.service.resolver.ResolverRankerService}, to ensure that only the system can
@@ -4380,7 +4486,7 @@
          @hide This is not a third-party API (intended for OEMs and system apps).
     -->
     <permission android:name="android.permission.BIND_CACHE_QUOTA_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to call into a carrier setup flow. It is up to the
          carrier setup application to enforce that this permission is required
@@ -4435,63 +4541,51 @@
         android:description="@string/permdesc_bindCarrierServices"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi @TestApi Allows an application to forward cell broadcast messages to the cell
-         broadcast module. This is required in order to bind to the cell broadcast service, and
-         ensures that only the system can forward messages to it.
-
-         <p>Protection level: signature|privileged
-
-         @hide -->
-    <permission android:name="android.permission.BIND_CELL_BROADCAST_SERVICE"
-        android:label="@string/permlab_bindCellBroadcastService"
-        android:description="@string/permdesc_bindCellBroadcastService"
-        android:protectionLevel="signature" />
-
     <!--
         Allows the holder to start the permission usage screen for an app.
         <p>Protection level: signature|installer
     -->
     <permission android:name="android.permission.START_VIEW_PERMISSION_USAGE"
-                android:label="@string/permlab_startViewPermissionUsage"
-                android:description="@string/permdesc_startViewPermissionUsage"
-                android:protectionLevel="signature|installer" />
+        android:label="@string/permlab_startViewPermissionUsage"
+        android:description="@string/permdesc_startViewPermissionUsage"
+        android:protectionLevel="signature|installer" />
 
     <!-- Allows an application to query whether DO_NOT_ASK_CREDENTIALS_ON_BOOT
          flag is set.
          @hide -->
     <permission android:name="android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to kill UIDs.
         <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.KILL_UID"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- @SystemApi Allows applications to read the local WiFi and Bluetooth MAC address.
         @hide -->
     <permission android:name="android.permission.LOCAL_MAC_ADDRESS"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
     <uses-permission android:name="android.permission.LOCAL_MAC_ADDRESS"/>
 
     <!-- @SystemApi Allows access to MAC addresses of WiFi and Bluetooth peer devices.
         @hide -->
     <permission android:name="android.permission.PEERS_MAC_ADDRESS"
-        android:protectionLevel="signature|setup" />
+                android:protectionLevel="signature|setup" />
 
     <!-- Allows the Nfc stack to dispatch Nfc messages to applications. Applications
         can use this permission to ensure incoming Nfc messages are from the Nfc stack
         and not simulated by another application.
         @hide -->
     <permission android:name="android.permission.DISPATCH_NFC_MESSAGE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows changing day / night mode when system is configured with
          config_lockDayNightMode set to true. If requesting app does not have permission,
          it will be ignored.
         @hide -->
     <permission android:name="android.permission.MODIFY_DAY_NIGHT_MODE"
-        android:protectionLevel="signature|privileged" />
+      android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows entering or exiting car mode using a specified priority.
         This permission is required to use UiModeManager while specifying a priority for the calling
@@ -4515,26 +4609,26 @@
     <!-- @SystemApi Allows the holder to access and manage instant applications on the device.
          @hide -->
     <permission android:name="android.permission.ACCESS_INSTANT_APPS"
-        android:protectionLevel="signature|installer|verifier|wellbeing" />
+            android:protectionLevel="signature|installer|verifier|wellbeing" />
     <uses-permission android:name="android.permission.ACCESS_INSTANT_APPS"/>
 
     <!-- Allows the holder to view the instant applications on the device.
     @hide -->
     <permission android:name="android.permission.VIEW_INSTANT_APPS"
-        android:protectionLevel="signature|preinstalled" />
+                android:protectionLevel="signature|preinstalled" />
 
     <!-- Allows the holder to manage whether the system can bind to services
          provided by instant apps. This permission is intended to protect
          test/development fucntionality and should be used only in such cases.
     @hide -->
     <permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Allows receiving the usage of media resource e.g. video/audio codec and
          graphic memory.
          @hide -->
     <permission android:name="android.permission.RECEIVE_MEDIA_RESOURCE_USAGE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Must be required by system/priv apps when accessing the sound trigger
          APIs given by {@link SoundTriggerManager}.
@@ -4559,19 +4653,19 @@
          Provisioning app. If requesting app does not have permission, it will be ignored.
          @hide -->
     <permission android:name="android.permission.DISPATCH_PROVISIONING_MESSAGE"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- Allows the holder to read blocked numbers. See
          {@link android.provider.BlockedNumberContract}.
          @hide -->
     <permission android:name="android.permission.READ_BLOCKED_NUMBERS"
-        android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature|telephony" />
 
     <!-- Allows the holder to write blocked numbers. See
          {@link android.provider.BlockedNumberContract}.
          @hide -->
     <permission android:name="android.permission.WRITE_BLOCKED_NUMBERS"
-        android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature|telephony" />
 
     <!-- Must be required by an {@link android.service.vr.VrListenerService}, to ensure that only
          the system can bind to it.
@@ -4589,7 +4683,7 @@
     <!-- Required to make calls to {@link android.service.vr.IVrManager}.
          @hide -->
     <permission android:name="android.permission.ACCESS_VR_MANAGER"
-        android:protectionLevel="signature" />
+            android:protectionLevel="signature" />
 
     <!-- Required to access VR-Mode state and state change events via {android.app.VrStateCallback}
          @hide -->
@@ -4605,12 +4699,12 @@
          in the N-release and later.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to show notifications before the device is provisioned.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.NOTIFICATION_DURING_SETUP"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to manage auto-fill sessions.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -4625,20 +4719,21 @@
     <!-- @SystemApi Allows an application to manage the content suggestions service.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_CONTENT_SUGGESTIONS"
-        android:protectionLevel="signature" />
+         android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an application to manage the app predictions service.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MANAGE_APP_PREDICTIONS"
-        android:protectionLevel="signature|appPredictor" />
+         android:protectionLevel="signature|appPredictor" />
 
     <!-- Allows an app to set the theme overlay in /vendor/overlay
          being used.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.MODIFY_THEME_OVERLAY"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
-    <!-- Allows an instant app to create foreground services. -->
+    <!-- Allows an instant app to create foreground services.
+         <p>Protection level: signature|development|instant|appop -->
     <permission android:name="android.permission.INSTANT_APP_FOREGROUND_SERVICE"
         android:protectionLevel="signature|development|instant|appop" />
 
@@ -4664,7 +4759,7 @@
     <!-- @SystemApi Allows an application to read the runtime profiles of other apps.
          @hide <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.READ_RUNTIME_PROFILES"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @hide Allows audio policy management. -->
     <permission android:name="android.permission.MANAGE_AUDIO_POLICY"
@@ -4673,7 +4768,7 @@
     <!-- @SystemApi Allows an application to turn on / off quiet mode.
          @hide -->
     <permission android:name="android.permission.MODIFY_QUIET_MODE"
-        android:protectionLevel="signature|privileged|wellbeing" />
+                android:protectionLevel="signature|privileged|wellbeing" />
 
     <!-- Allows internal management of the camera framework
          @hide -->
@@ -4695,12 +4790,12 @@
          Details screen.
          @hide <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.OPEN_APP_OPEN_BY_DEFAULT_SETTINGS"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- Allows hidden API checks to be disabled when starting a process.
          @hide <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DISABLE_HIDDEN_API_CHECKS"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @hide Permission that protects the
         {@link android.provider.Telephony.Intents#ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL}
@@ -4708,7 +4803,8 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission.
+           <p>Protection level: signature -->
     <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
         android:protectionLevel="signature" />
 
@@ -4720,16 +4816,16 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Must be required by an {@link android.service.storage.ExternalStorageService} to
-     ensure that only the system can bind to it.
-     @hide This is not a third-party API (intended for OEMs and system apps).
+         ensure that only the system can bind to it.
+         @hide This is not a third-party API (intended for OEMs and system apps).
     -->
     <permission android:name="android.permission.BIND_EXTERNAL_STORAGE_SERVICE"
-                android:protectionLevel="signature" />
+        android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows configuring appops.
      <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.MANAGE_APPOPS"
-        android:protectionLevel="signature|telephony" />
+                android:protectionLevel="signature|telephony" />
 
     <!-- @hide Permission that allows background clipboard access.
          <p>Not for use by third-party applications. -->
@@ -4743,25 +4839,28 @@
 
     <!-- @SystemApi Allows an app to grant a profile owner access to device identifiers.
          <p>Not for use by third-party applications.
+         @deprecated
          @hide -->
     <permission android:name="android.permission.GRANT_PROFILE_OWNER_DEVICE_IDS_ACCESS"
         android:protectionLevel="signature" />
 
-    <!-- Allows an app to set profile owner as managing an organization-owned device.
+    <!-- Allows an app to mark a profile owner as managing an organization-owned device.
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.MARK_DEVICE_ORGANIZATION_OWNED"
                 android:protectionLevel="signature" />
 
-    <!-- Allows financial apps to read filtered sms messages. -->
+    <!-- Allows financial apps to read filtered sms messages.
+         Protection level: signature|appop  -->
     <permission android:name="android.permission.SMS_FINANCIAL_TRANSACTIONS"
         android:protectionLevel="signature|appop" />
 
     <!-- Required for apps targeting {@link android.os.Build.VERSION_CODES#Q} that want to use
          {@link android.app.Notification.Builder#setFullScreenIntent notification full screen
-         intents}.  -->
+         intents}.
+         <p>Protection level: normal -->
     <permission android:name="android.permission.USE_FULL_SCREEN_INTENT"
-        android:protectionLevel="normal" />
+                android:protectionLevel="normal" />
 
     <!-- @SystemApi Allows requesting the framework broadcast the
          {@link Intent#ACTION_DEVICE_CUSTOMIZATION_READY} intent.
@@ -4778,28 +4877,28 @@
     <!-- @SystemApi Allows wallpaper to be rendered in ambient mode.
          @hide -->
     <permission android:name="android.permission.AMBIENT_WALLPAPER"
-        android:protectionLevel="signature|preinstalled" />
+                android:protectionLevel="signature|preinstalled" />
 
     <!-- @SystemApi Allows sensor privacy to be modified.
          @hide -->
     <permission android:name="android.permission.MANAGE_SENSOR_PRIVACY"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
     <!-- @SystemApi Permission that protects the {@link Intent#ACTION_REVIEW_ACCESSIBILITY_SERVICES}
          intent.
          @hide -->
     <permission android:name="android.permission.REVIEW_ACCESSIBILITY_SERVICES"
-        android:protectionLevel="signature" />
+                android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows an activity to replace the app name and icon displayed in share targets
          in the sharesheet for the Q-release and later.
          @hide  <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.SUBSTITUTE_SHARE_TARGET_APP_NAME_AND_ICON"
-        android:protectionLevel="signature|privileged" />
+                android:protectionLevel="signature|privileged" />
 
     <!-- @SystemApi Allows an application to access shared libraries.
          @hide -->
     <permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
-        android:protectionLevel="signature|installer" />
+                android:protectionLevel="signature|installer" />
 
     <!-- Allows an app to log compat change usage.
          @hide  <p>Not for use by third-party applications.</p> -->
@@ -4817,7 +4916,8 @@
     <!-- Allows input events to be monitored. Very dangerous!  @hide -->
     <permission android:name="android.permission.MONITOR_INPUT"
                 android:protectionLevel="signature" />
-    <!-- Allows input device can change association. Very dangerous!  @hide -->
+    <!--  Allows the caller to change the associations between input devices and displays.
+        Very dangerous! @hide -->
     <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT"
                 android:protectionLevel="signature" />
 
@@ -4837,29 +4937,40 @@
          <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.ACCESS_TV_TUNER"
-        android:protectionLevel="signature|privileged" />
+        android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+    <!-- @SystemApi Allows an application to access descrambler of TV tuner HAL
+         <p>Not for use by third-party applications.
+         @hide -->
+    <permission android:name="android.permission.ACCESS_TV_DESCRAMBLER"
+        android:protectionLevel="signature|privileged|vendorPrivileged" />
+
+    <!-- @hide @SystemApi Allows an application to access locusId events in the usage stats. -->
+    <permission android:name="android.permission.ACCESS_LOCUS_ID_USAGE_STATS"
+                android:protectionLevel="signature|appPredictor" />
 
     <application android:process="system"
-        android:persistent="true"
-        android:hasCode="false"
-        android:label="@string/android_system_label"
-        android:allowClearUserData="false"
-        android:backupAgent="com.android.server.backup.SystemBackupAgent"
-        android:killAfterRestore="false"
-        android:icon="@drawable/ic_launcher_android"
-        android:supportsRtl="true"
-        android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
-        android:defaultToDeviceProtectedStorage="true"
-        android:directBootAware="true">
+                 android:persistent="true"
+                 android:hasCode="false"
+                 android:label="@string/android_system_label"
+                 android:allowClearUserData="false"
+                 android:backupAgent="com.android.server.backup.SystemBackupAgent"
+                 android:killAfterRestore="false"
+                 android:icon="@drawable/ic_launcher_android"
+                 android:supportsRtl="true"
+                 android:theme="@style/Theme.DeviceDefault.Light.DarkActionBar"
+                 android:defaultToDeviceProtectedStorage="true"
+                 android:forceQueryable="true"
+                 android:directBootAware="true">
         <activity android:name="com.android.internal.app.ChooserActivity"
-            android:theme="@style/Theme.DeviceDefault.Resolver"
-            android:finishOnCloseSystemDialogs="true"
-            android:excludeFromRecents="true"
-            android:documentLaunchMode="never"
-            android:relinquishTaskIdentity="true"
-            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                android:theme="@style/Theme.DeviceDefault.Resolver"
+                android:finishOnCloseSystemDialogs="true"
+                android:excludeFromRecents="true"
+                android:documentLaunchMode="never"
+                android:relinquishTaskIdentity="true"
+                android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+                android:process=":ui"
+                android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="android.intent.action.CHOOSER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -4867,116 +4978,104 @@
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.AccessibilityButtonChooserActivity"
-            android:exported="false"
-            android:theme="@style/Theme.DeviceDefault.Resolver"
-            android:finishOnCloseSystemDialogs="true"
-            android:excludeFromRecents="true"
-            android:documentLaunchMode="never"
-            android:relinquishTaskIdentity="true"
-            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                  android:exported="false"
+                  android:theme="@style/Theme.DeviceDefault.Dialog.Alert.DayNight"
+                  android:finishOnCloseSystemDialogs="true"
+                  android:excludeFromRecents="true"
+                  android:documentLaunchMode="never"
+                  android:relinquishTaskIdentity="true"
+                  android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
+                  android:process=":ui"
+                  android:visibleToInstantApps="true">
             <intent-filter>
                 <action android:name="com.android.internal.intent.action.CHOOSE_ACCESSIBILITY_BUTTON" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
         </activity>
         <activity android:name="com.android.internal.app.IntentForwarderActivity"
-            android:finishOnCloseSystemDialogs="true"
-            android:theme="@style/Theme.NoDisplay"
-            android:excludeFromRecents="true"
-            android:label="@string/user_owner_label"
-            android:exported="true"
-            android:visibleToInstantApps="true"
-            >
+                android:finishOnCloseSystemDialogs="true"
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:label="@string/user_owner_label"
+                android:exported="true"
+                android:visibleToInstantApps="true"
+                >
         </activity>
         <activity-alias android:name="com.android.internal.app.ForwardIntentToParent"
-            android:targetActivity="com.android.internal.app.IntentForwarderActivity"
-            android:exported="true"
-            android:label="@string/user_owner_label">
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:exported="true"
+                android:label="@string/user_owner_label">
         </activity-alias>
         <activity-alias android:name="com.android.internal.app.ForwardIntentToManagedProfile"
-            android:targetActivity="com.android.internal.app.IntentForwarderActivity"
-            android:icon="@drawable/ic_corp_badge"
-            android:exported="true"
-            android:label="@string/managed_profile_label">
+                android:targetActivity="com.android.internal.app.IntentForwarderActivity"
+                android:icon="@drawable/ic_corp_badge"
+                android:exported="true"
+                android:label="@string/managed_profile_label">
         </activity-alias>
         <activity android:name="com.android.internal.app.HeavyWeightSwitcherActivity"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog"
-            android:label="@string/heavy_weight_switcher_title"
-            android:finishOnCloseSystemDialogs="true"
-            android:excludeFromRecents="true"
-            android:process=":ui">
+                android:theme="@style/Theme.DeviceDefault.System.Dialog.Alert"
+                android:label="@string/heavy_weight_switcher_title"
+                android:finishOnCloseSystemDialogs="true"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.PlatLogoActivity"
-            android:theme="@style/Theme.Wallpaper.NoTitleBar.Fullscreen"
-            android:configChanges="orientation|keyboardHidden"
-            android:process=":ui">
+                android:theme="@style/Theme.DeviceDefault.DayNight"
+                android:configChanges="orientation|keyboardHidden"
+                android:icon="@drawable/platlogo"
+                android:process=":ui">
         </activity>
         <activity android:name="com.android.internal.app.DisableCarModeActivity"
-            android:theme="@style/Theme.NoDisplay"
-            android:excludeFromRecents="true"
-            android:process=":ui">
+                android:theme="@style/Theme.NoDisplay"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
-        <activity android:name="com.android.internal.app.DumpHeapActivity"
-            android:theme="@style/Theme.Translucent.NoTitleBar"
-            android:label="@string/dump_heap_title"
-            android:finishOnCloseSystemDialogs="true"
-            android:noHistory="true"
-            android:excludeFromRecents="true"
-            android:process=":ui">
-        </activity>
-        <provider android:name="com.android.server.am.DumpHeapProvider"
-            android:authorities="com.android.server.heapdump"
-            android:grantUriPermissions="true"
-            android:multiprocess="false"
-            android:singleUser="true" />
 
         <activity android:name="android.accounts.ChooseAccountActivity"
-            android:excludeFromRecents="true"
-            android:exported="true"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog"
-            android:label="@string/choose_account_label"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseTypeAndAccountActivity"
-            android:excludeFromRecents="true"
-            android:exported="true"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog"
-            android:label="@string/choose_account_label"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.ChooseAccountTypeActivity"
-            android:excludeFromRecents="true"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog"
-            android:label="@string/choose_account_label"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                android:excludeFromRecents="true"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+                android:label="@string/choose_account_label"
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.accounts.CantAddAccountActivity"
-            android:excludeFromRecents="true"
-            android:exported="true"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
-            android:process=":ui">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.DeviceDefault.Light.Dialog.NoActionBar"
+                android:process=":ui">
         </activity>
 
         <activity android:name="android.accounts.GrantCredentialsPermissionActivity"
-            android:excludeFromRecents="true"
-            android:exported="true"
-            android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
-            android:process=":ui"
-            android:visibleToInstantApps="true">
+                android:excludeFromRecents="true"
+                android:exported="true"
+                android:theme="@style/Theme.DeviceDefault.Light.DialogWhenLarge"
+                android:process=":ui"
+                android:visibleToInstantApps="true">
         </activity>
 
         <activity android:name="android.content.SyncActivityTooManyDeletes"
-            android:theme="@style/Theme.DeviceDefault.Light.Dialog"
-            android:label="@string/sync_too_many_deletes"
-            android:process=":ui">
+               android:theme="@style/Theme.DeviceDefault.Light.Dialog"
+               android:label="@string/sync_too_many_deletes"
+               android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.ShutdownActivity"
@@ -4994,16 +5093,16 @@
         </activity>
 
         <activity android:name="com.android.internal.app.NetInitiatedActivity"
-            android:theme="@style/Theme.Dialog.Confirmation"
-            android:excludeFromRecents="true"
-            android:process=":ui">
+                android:theme="@style/Theme.Dialog.Confirmation"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.SystemUserHomeActivity"
-            android:enabled="false"
-            android:process=":ui"
-            android:systemUserOnly="true"
-            android:theme="@style/Theme.Translucent.NoTitleBar">
+                  android:enabled="false"
+                  android:process=":ui"
+                  android:systemUserOnly="true"
+                  android:theme="@style/Theme.Translucent.NoTitleBar">
             <intent-filter android:priority="-100">
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.HOME" />
@@ -5013,9 +5112,9 @@
         <!-- Activity to prompt user if it's ok to create a new user sandbox for a
              specified account. -->
         <activity android:name="com.android.internal.app.ConfirmUserCreationActivity"
-            android:excludeFromRecents="true"
-            android:process=":ui"
-            android:theme="@style/Theme.Dialog.Confirmation">
+                android:excludeFromRecents="true"
+                android:process=":ui"
+                android:theme="@style/Theme.Dialog.Confirmation">
             <intent-filter android:priority="1000">
                 <action android:name="android.os.action.CREATE_USER" />
                 <category android:name="android.intent.category.DEFAULT" />
@@ -5023,39 +5122,45 @@
         </activity>
 
         <activity android:name="com.android.internal.app.SuspendedAppActivity"
-            android:theme="@style/Theme.Dialog.Confirmation"
-            android:excludeFromRecents="true"
-            android:process=":ui">
+                  android:theme="@style/Theme.Dialog.Confirmation"
+                  android:excludeFromRecents="true"
+                  android:process=":ui">
         </activity>
 
         <activity android:name="com.android.internal.app.UnlaunchableAppActivity"
-            android:theme="@style/Theme.Dialog.Confirmation"
-            android:excludeFromRecents="true"
-            android:process=":ui">
+                android:theme="@style/Theme.Dialog.Confirmation"
+                android:excludeFromRecents="true"
+                android:process=":ui">
+        </activity>
+
+        <activity android:name="com.android.internal.app.BlockedAppActivity"
+                android:theme="@style/Theme.Dialog.Confirmation"
+                android:excludeFromRecents="true"
+                android:process=":ui">
         </activity>
 
         <activity android:name="com.android.settings.notification.NotificationAccessConfirmationActivity"
-            android:theme="@style/Theme.Dialog.Confirmation"
-            android:excludeFromRecents="true">
+                  android:theme="@style/Theme.Dialog.Confirmation"
+                  android:excludeFromRecents="true">
         </activity>
 
         <activity android:name="com.android.internal.app.HarmfulAppWarningActivity"
-            android:theme="@style/Theme.Dialog.Confirmation"
-            android:excludeFromRecents="true"
-            android:process=":ui"
-            android:label="@string/harmful_app_warning_title"
-            android:exported="false">
+                  android:theme="@style/Theme.Dialog.Confirmation"
+                  android:excludeFromRecents="true"
+                  android:process=":ui"
+                  android:label="@string/harmful_app_warning_title"
+                  android:exported="false">
         </activity>
 
         <receiver android:name="com.android.server.BootReceiver"
-            android:systemUserOnly="true">
+                android:systemUserOnly="true">
             <intent-filter android:priority="1000">
                 <action android:name="android.intent.action.BOOT_COMPLETED" />
             </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.updates.CertPinInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_PINS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5063,7 +5168,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_INTENT_FIREWALL" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5071,7 +5176,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.SmsShortCodesInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_SMS_SHORT_CODES" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5079,7 +5184,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.NetworkWatchlistInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                  android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_NETWORK_WATCHLIST" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5087,7 +5192,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.ApnDbInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="com.android.internal.intent.action.UPDATE_APN_DB" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5095,7 +5200,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.CarrierProvisioningUrlsInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_CARRIER_PROVISIONING_URLS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5103,7 +5208,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.CertificateTransparencyLogInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_CT_LOGS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5111,7 +5216,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.LangIdInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_LANG_ID" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5119,7 +5224,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.SmartSelectionInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_SMART_SELECTION" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5127,7 +5232,7 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.ConversationActionsInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                  android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.intent.action.UPDATE_CONVERSATION_ACTIONS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
@@ -5135,17 +5240,25 @@
         </receiver>
 
         <receiver android:name="com.android.server.updates.CarrierIdInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
+                  android:permission="android.permission.UPDATE_CONFIG">
             <intent-filter>
                 <action android:name="android.os.action.UPDATE_CARRIER_ID_DB" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
             </intent-filter>
         </receiver>
 
+        <receiver android:name="com.android.server.updates.EmergencyNumberDbInstallReceiver"
+                  android:permission="android.permission.UPDATE_CONFIG">
+            <intent-filter>
+                <action android:name="android.os.action.UPDATE_EMERGENCY_NUMBER_DB" />
+                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
+            </intent-filter>
+        </receiver>
+
         <receiver android:name="com.android.server.MasterClearReceiver"
             android:permission="android.permission.MASTER_CLEAR">
             <intent-filter
-                android:priority="100" >
+                    android:priority="100" >
                 <!-- For Checkin, Settings, etc.: action=FACTORY_RESET -->
                 <action android:name="android.intent.action.FACTORY_RESET" />
                 <!-- As above until all the references to the deprecated MASTER_CLEAR get updated to
@@ -5159,91 +5272,102 @@
         </receiver>
 
         <receiver android:name="com.android.server.WallpaperUpdateReceiver"
-            android:permission="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY">
+                  android:permission="android.permission.RECEIVE_DEVICE_CUSTOMIZATION_READY">
             <intent-filter>
                 <action android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY"/>
             </intent-filter>
         </receiver>
 
-        <receiver android:name="com.android.server.updates.EmergencyNumberDbInstallReceiver"
-            android:permission="android.permission.UPDATE_CONFIG">
-            <intent-filter>
-                <action android:name="android.os.action.UPDATE_EMERGENCY_NUMBER_DB" />
-                <data android:scheme="content" android:host="*" android:mimeType="*/*" />
-            </intent-filter>
-        </receiver>
-
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
 
         <service android:name="com.android.server.MountServiceIdler"
-            android:exported="true"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:exported="true"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.ZramWriteback"
-            android:exported="false"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:exported="false"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.backup.FullBackupJob"
-            android:exported="true"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:exported="true"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.backup.KeyValueBackupJob"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.content.SyncJobService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.pm.BackgroundDexOptService"
-            android:exported="true"
-            android:permission="android.permission.BIND_JOB_SERVICE">
+                 android:exported="true"
+                 android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
         <service android:name="com.android.server.pm.DynamicCodeLoggingService"
-            android:permission="android.permission.BIND_JOB_SERVICE">
+                 android:permission="android.permission.BIND_JOB_SERVICE">
         </service>
 
         <service android:name="com.android.server.PruneInstantAppsJobService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.storage.DiskStatsLoggingService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.PreloadsFileCacheExpirationJobService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.camera.CameraStatsJobService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.timezone.TimeZoneUpdateIdler"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
+        <service android:name="com.android.server.usage.UsageStatsIdleService"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.net.watchlist.ReportWatchlistJobService"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service android:name="com.android.server.display.BrightnessIdleJob"
-            android:permission="android.permission.BIND_JOB_SERVICE" >
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
         </service>
 
         <service
-            android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
-            android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
-            android:exported="true">
+                android:name="com.android.server.autofill.AutofillCompatAccessibilityService"
+                android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"
+                android:visibleToInstantApps="true"
+                android:exported="true">
             <meta-data
-                android:name="android.accessibilityservice"
-                android:resource="@xml/autofill_compat_accessibility_service" />
+                    android:name="android.accessibilityservice"
+                    android:resource="@xml/autofill_compat_accessibility_service" />
+        </service>
+
+        <service android:name="com.google.android.startop.iorap.IorapForwardingService$IorapdJobServiceProxy"
+                 android:permission="android.permission.BIND_JOB_SERVICE" >
+        </service>
+
+        <service android:name="com.android.server.blob.BlobStoreIdleJobService"
+                 android:permission="android.permission.BIND_JOB_SERVICE">
+        </service>
+
+        <service android:name="com.android.server.pm.PackageManagerShellCommandDataLoader">
+            <intent-filter>
+                <action android:name="android.intent.action.LOAD_DATA" />
+            </intent-filter>
         </service>
 
     </application>
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
index fa92437..abbc029 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedPermissionsTest.java
@@ -89,27 +89,9 @@
     private static final String APK_USES_SMS_CALL_LOG_29 =
             "/data/local/tmp/cts/permissions2/CtsSMSCallLogPermissionsUserSdk29.apk";
 
-    private static final String APK_USES_STORAGE_DEFAULT_22 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk22.apk";
-
-    private static final String APK_USES_STORAGE_DEFAULT_28 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk28.apk";
-
     private static final String APK_USES_STORAGE_DEFAULT_29 =
             "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk29.apk";
 
-    private static final String APK_USES_STORAGE_OPT_IN_22 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.apk";
-
-    private static final String APK_USES_STORAGE_OPT_IN_28 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk";
-
-    private static final String APK_USES_STORAGE_OPT_OUT_29 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk";
-
-    private static final String APK_USES_STORAGE_OPT_OUT_30 =
-            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk30.apk";
-
     private static final String PKG = "android.permission2.cts.restrictedpermissionuser";
 
     private static final String APK_USES_SMS_RESTRICTED_SHARED_UID =
@@ -193,7 +175,7 @@
     @AppModeFull
     public void testDefaultAllRestrictedPermissionsWhitelistedAtInstall22() throws Exception {
         // Install with no changes to whitelisted permissions
-        runShellCommand("pm install -g " + APK_USES_SMS_CALL_LOG_22);
+        runShellCommand("pm install -g --force-queryable " + APK_USES_SMS_CALL_LOG_22);
 
         // All restricted permission should be whitelisted.
         assertAllRestrictedPermissionWhitelisted();
@@ -323,378 +305,6 @@
 
     @Test
     @AppModeFull
-    public void testStorageTargetingSdk22DefaultWhitelistedHasFullAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_22, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk22OptInWhitelistedHasIsolatedAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_22, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
-
-        // Check expected storage mode
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29CanOptOutViaUpdate() throws Exception {
-        installApp(APK_USES_STORAGE_DEFAULT_29, null);
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
-        installApp(APK_USES_STORAGE_DEFAULT_29, null);
-        installApp(APK_USES_STORAGE_DEFAULT_28, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk30_cannotOptOut() throws Exception {
-        // Apps that target R and above cannot opt out of isolated storage.
-        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
-
-        // Check expected storage mode
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
-        installApp(APK_USES_STORAGE_OPT_IN_28, null);
-        installApp(APK_USES_STORAGE_DEFAULT_28, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
-        installApp(APK_USES_STORAGE_OPT_IN_28, null);
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28DoesNotLoseAccessWhenOptingIn() throws Exception {
-        installApp(APK_USES_STORAGE_DEFAULT_28, null);
-        assertHasFullStorageAccess();
-        installApp(APK_USES_STORAGE_OPT_IN_28, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28DoesNotLoseAccessViaUpdate() throws Exception {
-        installApp(APK_USES_STORAGE_DEFAULT_28, null);
-        assertHasFullStorageAccess();
-        installApp(APK_USES_STORAGE_DEFAULT_29, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29DoesNotLoseAccessViaUpdate() throws Exception {
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
-        assertHasFullStorageAccess();
-        installApp(APK_USES_STORAGE_DEFAULT_29, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29DoesNotLoseAccessWhenOptingIn() throws Exception {
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
-        assertHasFullStorageAccess();
-        installApp(APK_USES_STORAGE_OPT_IN_28, null);
-
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk29LosesAccessViaUpdateToTargetSdk30() throws Exception {
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
-        assertHasFullStorageAccess();
-
-        installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testStorageTargetingSdk28LosesAccessViaUpdateToTargetSdk30() throws Exception {
-        installApp(APK_USES_STORAGE_DEFAULT_28, null);
-        assertHasFullStorageAccess();
-
-        installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void testCannotControlStorageWhitelistPostInstall1() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
-
-        // Check expected state of restricted permissions.
-        assertCannotUnWhitelistStorage();
-    }
-
-    @Test
-    @AppModeFull
-    public void testCannotControlStorageWhitelistPostInstall2() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
-
-        // Check expected state of restricted permissions.
-        assertCannotWhitelistStorage();
-    }
-
-    @Test
-    @AppModeFull
-    public void cannotGrantStorageTargetingSdk22NotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_22, Collections.emptySet(), null);
-
-        eventually(() -> {
-            // Could not grant permission+app-op as targetSDK<29 and not whitelisted
-            assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
-
-            // Permissions are always granted for pre-23 apps
-            assertThat(
-                    isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
-        });
-    }
-
-    @Test
-    @AppModeFull
-    public void cannotGrantStorageTargetingSdk22OptInNotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_22, Collections.emptySet(), null);
-
-        eventually(() -> {
-            // Could not grant permission as targetSDK<29 and not whitelisted
-            assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
-
-            // Permissions are always granted for pre-23 apps
-            assertThat(
-                    isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue();
-        });
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk22Whitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_22, null, null);
-
-        // Could grant permission
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk22OptInWhitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_22, null, null);
-
-        // Could grant permission
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet(), null);
-
-        // Could not grant permission as targetSDK<29 and not whitelisted
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
-    }
-
-    @Test
-    @AppModeFull
-    public void cannotGrantStorageTargetingSdk28OptInNotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_28, Collections.emptySet(), null);
-
-        // Could not grant permission as targetSDK<29 and not whitelisted
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk28Whitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_28, null, null);
-
-        // Could grant permission
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk28OptInWhitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_IN_28, null, null);
-
-        // Could grant permission
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk29NotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet(), null);
-
-        // Could grant permission as targetSDK=29 apps can always grant
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk29OptOutNotWhitelisted() throws Exception {
-        // Install with no whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet(), null);
-
-        // Could grant permission as targetSDK=29 apps can always grant
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk29Whitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_DEFAULT_29, null, null);
-
-        // Could grant permission as targetSDK=29 apps can always grant
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void canGrantStorageTargetingSdk29OptOutWhitelisted() throws Exception {
-        // Install with whitelisted permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29, null, null);
-
-        // Could grant permission as targetSDK=29 apps can always grant
-        eventually(() -> assertThat(
-                isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
-    }
-
-    @Test
-    @AppModeFull
-    public void restrictedWritePermDoesNotImplyIsolatedStorageAccess() throws Exception {
-        // Install with whitelisted read permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29,
-                Collections.singleton(Manifest.permission.READ_EXTERNAL_STORAGE), null);
-
-        // It does not matter that write is restricted as the storage access level is only
-        // controlled by the read perm
-        assertHasFullStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
-    public void whitelistedWritePermDoesNotImplyFullStorageAccess() throws Exception {
-        // Install with whitelisted read permissions.
-        installApp(APK_USES_STORAGE_OPT_OUT_29,
-                Collections.singleton(Manifest.permission.WRITE_EXTERNAL_STORAGE), null);
-
-        // It does not matter that write is white listed as the storage access level is only
-        // controlled by the read perm
-        assertHasIsolatedStorageAccess();
-    }
-
-    @Test
-    @AppModeFull
     public void onSideLoadRestrictedPermissionsWhitelistingDefault() throws Exception {
         installRestrictedPermissionUserApp(new SessionParams(SessionParams.MODE_FULL_INSTALL));
 
@@ -743,8 +353,10 @@
     @AppModeFull
     public void shareUidBetweenRestrictedAndNotRestrictedApp() throws Exception {
         runShellCommand(
-                "pm install -g --restrict-permissions " + APK_USES_SMS_RESTRICTED_SHARED_UID);
-        runShellCommand("pm install -g " + APK_USES_SMS_NOT_RESTRICTED_SHARED_UID);
+                "pm install -g --force-queryable --restrict-permissions "
+                + APK_USES_SMS_RESTRICTED_SHARED_UID);
+        runShellCommand("pm install -g --force-queryable "
+                + APK_USES_SMS_NOT_RESTRICTED_SHARED_UID);
 
         eventually(
                 () -> assertThat(isGranted(PKG_USES_SMS_RESTRICTED_SHARED_UID, READ_SMS)).isTrue());
@@ -807,26 +419,6 @@
         }
     }
 
-    private void assertHasFullStorageAccess() throws Exception {
-        runWithShellPermissionIdentity(() -> {
-            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-            final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
-            eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
-                    AppOpsManager.OPSTR_LEGACY_STORAGE,
-                    uid, PKG)).isEqualTo(AppOpsManager.MODE_ALLOWED));
-        });
-    }
-
-    private void assertHasIsolatedStorageAccess() throws Exception {
-        runWithShellPermissionIdentity(() -> {
-            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
-            final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
-            eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
-                    AppOpsManager.OPSTR_LEGACY_STORAGE,
-                    uid, PKG)).isNotEqualTo(AppOpsManager.MODE_ALLOWED));
-        });
-    }
-
     private void assertWeCannotReadOrWriteWhileShellCanReadAndWrite(int whitelist)
             throws Exception {
         final PackageManager packageManager = getContext().getPackageManager();
@@ -855,108 +447,6 @@
         });
     }
 
-    private void assertCannotWhitelistStorage()
-            throws Exception {
-        final PackageManager packageManager = getContext().getPackageManager();
-
-        runWithShellPermissionIdentity(() -> {
-            // Assert added only to none whitelist.
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
-        });
-
-        // Assert we cannot add.
-        try {
-            packageManager.addWhitelistedRestrictedPermission(PKG,
-                    permission.READ_EXTERNAL_STORAGE,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-            fail();
-        } catch (SecurityException expected) {}
-        try {
-            packageManager.addWhitelistedRestrictedPermission(PKG,
-                    permission.WRITE_EXTERNAL_STORAGE,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-            fail();
-        } catch (SecurityException expected) {}
-
-        runWithShellPermissionIdentity(() -> {
-            // Assert added only to none whitelist.
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
-        });
-    }
-
-    private void assertCannotUnWhitelistStorage()
-            throws Exception {
-        final PackageManager packageManager = getContext().getPackageManager();
-
-        runWithShellPermissionIdentity(() -> {
-            // Assert added only to install whitelist.
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .contains(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .contains(permission.WRITE_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
-                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
-                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
-        });
-
-        try {
-            // Assert we cannot remove.
-            packageManager.removeWhitelistedRestrictedPermission(PKG,
-                    permission.READ_EXTERNAL_STORAGE,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-            fail();
-        } catch (SecurityException expected) {}
-        try {
-            packageManager.removeWhitelistedRestrictedPermission(PKG,
-                    permission.WRITE_EXTERNAL_STORAGE,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
-            fail();
-        } catch (SecurityException expected) {}
-
-        runWithShellPermissionIdentity(() -> {
-            // Assert added only to install whitelist.
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .contains(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
-                    .contains(permission.WRITE_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
-                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
-            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
-                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
-                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
-                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
-        });
-    }
-
     private @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception {
         final PackageManager packageManager = getContext().getPackageManager();
         final Set<String> restrictedPermissions = new ArraySet<>();
@@ -1135,7 +625,8 @@
     private void installApp(@NonNull String app, @Nullable Set<String> whitelistedPermissions,
             @Nullable Set<String> grantedPermissions) throws Exception {
         // Install the app and whitelist/grant all permission if requested.
-        String installResult = runShellCommand("pm install -r --restrict-permissions " + app);
+        String installResult = runShellCommand("pm install -r --force-queryable "
+                + "--restrict-permissions " + app);
         assertThat(installResult.trim()).isEqualTo("Success");
 
         final Set<String> adjustedWhitelistedPermissions;
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java
index b8289d4..044abe2 100644
--- a/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionSharedUidTest.java
@@ -127,9 +127,9 @@
 
         void install() {
             if (isRestricted) {
-                runShellCommand("pm install -g --restrict-permissions " + mApk);
+                runShellCommand("pm install -g --force-queryable --restrict-permissions " + mApk);
             } else {
-                runShellCommand("pm install -g " + mApk);
+                runShellCommand("pm install -g --force-queryable " + mApk);
             }
         }
 
diff --git a/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionTest.java b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionTest.java
new file mode 100644
index 0000000..f9ce0ac
--- /dev/null
+++ b/tests/tests/permission2/src/android/permission2/cts/RestrictedStoragePermissionTest.java
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2020 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.permission2.cts;
+
+import static android.permission.cts.PermissionUtils.isGranted;
+import static android.permission.cts.PermissionUtils.isPermissionGranted;
+
+import static com.android.compatibility.common.util.SystemUtil.eventually;
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.fail;
+
+import android.Manifest;
+import android.Manifest.permission;
+import android.app.AppOpsManager;
+import android.content.Context;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PermissionInfo;
+import android.platform.test.annotations.AppModeFull;
+import android.util.ArraySet;
+
+import androidx.annotation.NonNull;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.compatibility.common.util.SystemUtil.ThrowingRunnable;
+
+import org.junit.After;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.annotation.Nullable;
+
+/** Tests for restricted storage-related permissions. */
+public class RestrictedStoragePermissionTest {
+    private static final String APK_USES_STORAGE_DEFAULT_22 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk22.apk";
+
+    private static final String APK_USES_STORAGE_DEFAULT_28 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk28.apk";
+
+    private static final String APK_USES_STORAGE_DEFAULT_29 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserDefaultSdk29.apk";
+
+    private static final String APK_USES_STORAGE_OPT_IN_22 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk22.apk";
+
+    private static final String APK_USES_STORAGE_OPT_IN_28 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptInSdk28.apk";
+
+    private static final String APK_USES_STORAGE_OPT_OUT_29 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk29.apk";
+
+    private static final String APK_USES_STORAGE_OPT_OUT_30 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsUserOptOutSdk30.apk";
+
+    private static final String APK_USES_STORAGE_PRESERVED_OPT_OUT_30 =
+            "/data/local/tmp/cts/permissions2/CtsStoragePermissionsPreservedUserOptOutSdk30.apk";
+
+    private static final String PKG = "android.permission2.cts.restrictedpermissionuser";
+
+    private static final long ENABLE_SCOPED_STORAGE_CHANGE_ID = 144914977L;
+
+    private static final long REQUIRE_SCOPED_STORAGE_CHANGE_ID = 131432978L;
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk22DefaultWhitelistedHasFullAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_22, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk22OptInWhitelistedHasIsolatedAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_22, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28DefaultWhitelistedHasFullAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28OptInWhitelistedHasIsolatedAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_28, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29DefaultWhitelistedHasIsolatedAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29DefaultNotWhitelistedHasIsolatedAccess() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_29, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29OptOutWhitelistedHasFullAccess() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null /*whitelistedPermissions*/);
+
+        // Check expected storage mode
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29OptOutNotWhitelistedHasIsolatedAccess() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29CanOptOutViaUpdate() throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29CanOptOutViaDowngradeTo28() throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk30_cannotOptOut() throws Exception {
+        // Apps that target R and above cannot opt out of isolated storage.
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+
+        // Check expected storage mode
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk30_withRequireScopedStorageCompatChangeDisabled_canOptOut()
+            throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+        disableCompat(REQUIRE_SCOPED_STORAGE_CHANGE_ID, PKG);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk30_withAllScopedStorageCompatChangesDisabled_hasFullAccess()
+            throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+        // As REQUIRE_SCOPED_STORAGE supersedes ENABLE_SCOPED_STORAGE, we need to disable both.
+        disableCompat(REQUIRE_SCOPED_STORAGE_CHANGE_ID, PKG);
+        disableCompat(ENABLE_SCOPED_STORAGE_CHANGE_ID, PKG);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk30_withEnableScopedStorageOnlyDisabled_isNoOp() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+        // Leave REQUIRE_SCOPED_STORAGE explicitly enabled (as is the default for apps
+        // targeting SDK 30).
+        disableCompat(ENABLE_SCOPED_STORAGE_CHANGE_ID, PKG);
+
+        // Disabling only ENABLE_SCOPED_STORAGE must have been be a no-op.
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28CanRemoveOptInViaUpdate() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_IN_28, null);
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28CanRemoveOptInByOptingOut() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_IN_28, null);
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28DoesNotLoseAccessWhenOptingIn() throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
+        installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28DoesNotLoseAccessViaUpdate() throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29DoesNotLoseAccessViaUpdate() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29DoesNotLoseAccessWhenOptingIn() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
+        installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk29LosesAccessViaUpdateToTargetSdk30() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
+
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testTargetingSdk28LosesAccessViaUpdateToTargetSdk30() throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+        assertHasFullStorageAccess();
+
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null); // opt-out is a no-op on 30
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testCannotControlStorageWhitelistPostInstall1() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_28, null /*whitelistedPermissions*/);
+
+        // Check expected state of restricted permissions.
+        assertCannotUnWhitelistStorage();
+    }
+
+    @Test
+    @AppModeFull
+    public void testCannotControlStorageWhitelistPostInstall2() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+
+        // Check expected state of restricted permissions.
+        assertCannotWhitelistStorage();
+    }
+
+    @Test
+    @AppModeFull
+    public void cannotGrantStorageTargetingSdk22NotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_22, Collections.emptySet());
+
+        eventually(() -> {
+            // Could not grant permission+app-op as targetSDK<29 and not whitelisted
+            assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
+
+            // Permissions are always granted for pre-23 apps
+            assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE))
+                    .isTrue();
+        });
+    }
+
+    @Test
+    @AppModeFull
+    public void cannotGrantStorageTargetingSdk22OptInNotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_22, Collections.emptySet());
+
+        eventually(() -> {
+            // Could not grant permission as targetSDK<29 and not whitelisted
+            assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse();
+
+            // Permissions are always granted for pre-23 apps
+            assertThat(isPermissionGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE))
+                    .isTrue();
+        });
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk22Whitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_22, null);
+
+        // Could grant permission
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk22OptInWhitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_22, null);
+
+        // Could grant permission
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void cannotGrantStorageTargetingSdk28NotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_28, Collections.emptySet());
+
+        // Could not grant permission as targetSDK<29 and not whitelisted
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
+    }
+
+    @Test
+    @AppModeFull
+    public void cannotGrantStorageTargetingSdk28OptInNotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_28, Collections.emptySet());
+
+        // Could not grant permission as targetSDK<29 and not whitelisted
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isFalse());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk28Whitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_28, null);
+
+        // Could grant permission
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk28OptInWhitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_IN_28, null);
+
+        // Could grant permission
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk29NotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_29, Collections.emptySet());
+
+        // Could grant permission as targetSDK=29 apps can always grant
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk29OptOutNotWhitelisted() throws Exception {
+        // Install with no whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_OUT_29, Collections.emptySet());
+
+        // Could grant permission as targetSDK=29 apps can always grant
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk29Whitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+
+        // Could grant permission as targetSDK=29 apps can always grant
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void canGrantStorageTargetingSdk29OptOutWhitelisted() throws Exception {
+        // Install with whitelisted permissions.
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+        // Could grant permission as targetSDK=29 apps can always grant
+        eventually(() ->
+                assertThat(isGranted(PKG, Manifest.permission.READ_EXTERNAL_STORAGE)).isTrue());
+    }
+
+    @Test
+    @AppModeFull
+    public void restrictedWritePermDoesNotImplyIsolatedStorageAccess() throws Exception {
+        // Install with whitelisted read permissions.
+        installApp(
+                APK_USES_STORAGE_OPT_OUT_29,
+                Collections.singleton(Manifest.permission.READ_EXTERNAL_STORAGE));
+
+        // It does not matter that write is restricted as the storage access level is only
+        // controlled by the read perm
+        assertHasFullStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void whitelistedWritePermDoesNotImplyFullStorageAccess() throws Exception {
+        // Install with whitelisted read permissions.
+        installApp(
+                APK_USES_STORAGE_OPT_OUT_29,
+                Collections.singleton(Manifest.permission.WRITE_EXTERNAL_STORAGE));
+
+        // It does not matter that write is white listed as the storage access level is only
+        // controlled by the read perm
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testStorageTargetingSdk30CanPreserveLegacyOnUpdateFromLegacy() throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+
+        // Updating with the flag preserves legacy
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+        assertHasFullStorageAccess();
+
+        // And with the flag still preserves legacy
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+        assertHasFullStorageAccess();
+
+        // But without the flag loses legacy
+        installApp(APK_USES_STORAGE_OPT_OUT_30, null);
+        assertHasIsolatedStorageAccess();
+
+        // And again with the flag doesn't bring back legacy
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testStorageTargetingSdk30CannotPreserveLegacyAfterLegacyUninstall()
+            throws Exception {
+        installApp(APK_USES_STORAGE_OPT_OUT_29, null);
+        assertHasFullStorageAccess();
+
+        runShellCommand("pm uninstall " + PKG);
+
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testStorageTargetingSdk30CannotPreserveLegacyOnUpdateFromNonLegacy()
+            throws Exception {
+        installApp(APK_USES_STORAGE_DEFAULT_29, null);
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+
+        assertHasIsolatedStorageAccess();
+    }
+
+    @Test
+    @AppModeFull
+    public void testStorageTargetingSdk30CannotPreserveLegacyOnInstall() throws Exception {
+        installApp(APK_USES_STORAGE_PRESERVED_OPT_OUT_30, null);
+
+        assertHasIsolatedStorageAccess();
+    }
+
+    private void assertHasFullStorageAccess() throws Exception {
+        runWithShellPermissionIdentity(() -> {
+            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+            final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
+            eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
+                    AppOpsManager.OPSTR_LEGACY_STORAGE,
+                    uid, PKG)).isEqualTo(AppOpsManager.MODE_ALLOWED));
+        });
+    }
+
+    private void assertHasIsolatedStorageAccess() throws Exception {
+        runWithShellPermissionIdentity(() -> {
+            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+            final int uid = getContext().getPackageManager().getPackageUid(PKG, 0);
+            eventually(() -> assertThat(appOpsManager.unsafeCheckOpRawNoThrow(
+                    AppOpsManager.OPSTR_LEGACY_STORAGE,
+                    uid, PKG)).isNotEqualTo(AppOpsManager.MODE_ALLOWED));
+        });
+    }
+
+    private void assertCannotWhitelistStorage() throws Exception {
+        final PackageManager packageManager = getContext().getPackageManager();
+
+        runWithShellPermissionIdentity(() -> {
+            // Assert added only to none whitelist.
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+        });
+
+        // Assert we cannot add.
+        try {
+            packageManager.addWhitelistedRestrictedPermission(
+                    PKG,
+                    permission.READ_EXTERNAL_STORAGE,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            packageManager.addWhitelistedRestrictedPermission(
+                    PKG,
+                    permission.WRITE_EXTERNAL_STORAGE,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        runWithShellPermissionIdentity(() -> {
+            // Assert added only to none whitelist.
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+        });
+    }
+
+    private void assertCannotUnWhitelistStorage() throws Exception {
+        final PackageManager packageManager = getContext().getPackageManager();
+
+        runWithShellPermissionIdentity(() -> {
+            // Assert added only to install whitelist.
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .contains(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .contains(permission.WRITE_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+        });
+
+        try {
+            // Assert we cannot remove.
+            packageManager.removeWhitelistedRestrictedPermission(
+                    PKG,
+                    permission.READ_EXTERNAL_STORAGE,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+            fail();
+        } catch (SecurityException expected) {
+        }
+        try {
+            packageManager.removeWhitelistedRestrictedPermission(
+                    PKG,
+                    permission.WRITE_EXTERNAL_STORAGE,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+            fail();
+        } catch (SecurityException expected) {
+        }
+
+        runWithShellPermissionIdentity(() -> {
+            // Assert added only to install whitelist.
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .contains(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER))
+                    .contains(permission.WRITE_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+                    .doesNotContain(permission.READ_EXTERNAL_STORAGE);
+            assertThat(packageManager.getWhitelistedRestrictedPermissions(PKG,
+                    PackageManager.FLAG_PERMISSION_WHITELIST_UPGRADE
+                            | PackageManager.FLAG_PERMISSION_WHITELIST_SYSTEM))
+                    .doesNotContain(permission.WRITE_EXTERNAL_STORAGE);
+        });
+    }
+
+    private @NonNull Set<String> getPermissionsOfAppWithAnyOfFlags(int flags) throws Exception {
+        final PackageManager packageManager = getContext().getPackageManager();
+        final Set<String> restrictedPermissions = new ArraySet<>();
+        for (String permission : getRequestedPermissionsOfApp()) {
+            PermissionInfo permInfo = packageManager.getPermissionInfo(permission, 0);
+
+            if ((permInfo.flags & flags) != 0) {
+                restrictedPermissions.add(permission);
+            }
+        }
+        return restrictedPermissions;
+    }
+
+    private @NonNull Set<String> getRestrictedPermissionsOfApp() throws Exception {
+        return getPermissionsOfAppWithAnyOfFlags(
+                PermissionInfo.FLAG_HARD_RESTRICTED | PermissionInfo.FLAG_SOFT_RESTRICTED);
+    }
+
+    private @NonNull String[] getRequestedPermissionsOfApp() throws Exception {
+        final PackageManager packageManager = getContext().getPackageManager();
+        final PackageInfo packageInfo =
+                packageManager.getPackageInfo(PKG, PackageManager.GET_PERMISSIONS);
+        return packageInfo.requestedPermissions;
+    }
+
+    private static @NonNull Context getContext() {
+        return InstrumentationRegistry.getInstrumentation().getContext();
+    }
+
+    private static void runWithShellPermissionIdentity(@NonNull ThrowingRunnable command)
+            throws Exception {
+        InstrumentationRegistry.getInstrumentation()
+                .getUiAutomation()
+                .adoptShellPermissionIdentity();
+        try {
+            command.runOrThrow();
+        } finally {
+            InstrumentationRegistry.getInstrumentation()
+                    .getUiAutomation()
+                    .dropShellPermissionIdentity();
+        }
+    }
+
+    /**
+     * Install an app.
+     *
+     * @param app The app to be installed
+     * @param whitelistedPermissions The permission to be whitelisted. {@code null} == all
+     * @param grantedPermissions The permission to be granted. {@code null} == all
+     */
+    private void installApp(
+            @NonNull String app,
+            @Nullable Set<String> whitelistedPermissions)
+            throws Exception {
+        // Install the app and whitelist/grant all permission if requested.
+        String installResult = runShellCommand("pm install -r --restrict-permissions " + app);
+        assertThat(installResult.trim()).isEqualTo("Success");
+
+        final Set<String> adjustedWhitelistedPermissions;
+        if (whitelistedPermissions == null) {
+            adjustedWhitelistedPermissions = getRestrictedPermissionsOfApp();
+        } else {
+            adjustedWhitelistedPermissions = whitelistedPermissions;
+        }
+
+        final Set<String> adjustedGrantedPermissions = getRestrictedPermissionsOfApp();
+
+        // Whitelist subset of permissions if requested
+        runWithShellPermissionIdentity(() -> {
+            final PackageManager packageManager = getContext().getPackageManager();
+            for (String permission : adjustedWhitelistedPermissions) {
+                packageManager.addWhitelistedRestrictedPermission(
+                        PKG,
+                        permission,
+                        PackageManager.FLAG_PERMISSION_WHITELIST_INSTALLER);
+            }
+        });
+
+        // Grant subset of permissions if requested
+        runWithShellPermissionIdentity(() -> {
+            final PackageManager packageManager = getContext().getPackageManager();
+            for (String permission : adjustedGrantedPermissions) {
+                packageManager.grantRuntimePermission(PKG, permission, getContext().getUser());
+                packageManager.updatePermissionFlags(
+                        permission,
+                        PKG,
+                        PackageManager.FLAG_PERMISSION_REVOKED_COMPAT,
+                        0,
+                        getContext().getUser());
+            }
+        });
+
+        // Mark all permissions as reviewed as for pre-22 apps the restriction state might not be
+        // applied until reviewed
+        runWithShellPermissionIdentity(() -> {
+            final PackageManager packageManager = getContext().getPackageManager();
+            for (String permission : getRequestedPermissionsOfApp()) {
+                packageManager.updatePermissionFlags(
+                        permission,
+                        PKG,
+                        PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED,
+                        0,
+                        getContext().getUser());
+            }
+        });
+    }
+
+    @After
+    public void uninstallApp() {
+        runShellCommand("pm uninstall " + PKG);
+    }
+
+    private void disableCompat(long changeId, String packageName) throws Exception {
+        runShellCommand("am compat disable " + changeId + " " + packageName);
+    }
+
+    private void resetCompat(long changeId, String packageName) {
+        runShellCommand("am compat reset " + changeId + " " + packageName);
+    }
+
+    @After
+    public void resetCompat() {
+        resetCompat(REQUIRE_SCOPED_STORAGE_CHANGE_ID, PKG);
+        resetCompat(ENABLE_SCOPED_STORAGE_CHANGE_ID, PKG);
+    }
+}
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
index da10f33..d436d22 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Images_MediaTest.java
@@ -489,6 +489,8 @@
                     c.getString(c.getColumnIndex(ImageColumns.INSTANCE_ID)));
             assertEquals("3F9DD7A46B26513A7C35272F0D623A06",
                     c.getString(c.getColumnIndex(ImageColumns.ORIGINAL_DOCUMENT_ID)));
+            assertTrue(new String(c.getBlob(c.getColumnIndex(ImageColumns.XMP)))
+                    .contains("exif:ShutterSpeedValue"));
 
             // Confirm that timestamp was parsed with offset information
             assertEquals(1447346778000L + 25200000L,
diff --git a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
index 58731ff..e6efc71 100644
--- a/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
+++ b/tests/tests/provider/src/android/provider/cts/media/MediaStore_Video_MediaTest.java
@@ -407,6 +407,8 @@
                     c.getString(c.getColumnIndex(VideoColumns.INSTANCE_ID)));
             assertEquals("4F9DD7A46B26513A7C35272F0D623A06",
                     c.getString(c.getColumnIndex(VideoColumns.ORIGINAL_DOCUMENT_ID)));
+            assertTrue(new String(c.getBlob(c.getColumnIndex(VideoColumns.XMP)))
+                    .contains("exif:ShutterSpeedValue"));
 
             // Confirm that timestamp was parsed
             assertEquals(1539711603000L, c.getLong(c.getColumnIndex(VideoColumns.DATE_TAKEN)));
diff --git a/tests/tests/security/AndroidTest.xml b/tests/tests/security/AndroidTest.xml
index 45220d9..4dfec996 100644
--- a/tests/tests/security/AndroidTest.xml
+++ b/tests/tests/security/AndroidTest.xml
@@ -17,7 +17,7 @@
     <option name="test-suite-tag" value="cts" />
     <option name="config-descriptor:metadata" key="component" value="security" />
     <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
-    <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
+    <option name="config-descriptor:metadata" key="parameter" value="not_instant_app" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
diff --git a/tests/tests/security/res/raw/bug_123700383.mid b/tests/tests/security/res/raw/bug_123700383.mid
new file mode 100644
index 0000000..1e1ae6b
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_123700383.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127310810.mid b/tests/tests/security/res/raw/bug_127310810.mid
new file mode 100644
index 0000000..8a64142
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127310810.mid
@@ -0,0 +1,3 @@
+BEGIN:IMELODY
+BEAT:900
+MELODY:((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((((ledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonledonr5;@32767)
\ No newline at end of file
diff --git a/tests/tests/security/res/raw/bug_127312550.mid b/tests/tests/security/res/raw/bug_127312550.mid
new file mode 100644
index 0000000..ea66e75
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127312550.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313223.mid b/tests/tests/security/res/raw/bug_127313223.mid
new file mode 100644
index 0000000..6558be7
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313223.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313537.mid b/tests/tests/security/res/raw/bug_127313537.mid
new file mode 100644
index 0000000..658ab92
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313537.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/bug_127313764.mid b/tests/tests/security/res/raw/bug_127313764.mid
new file mode 100644
index 0000000..bda2dfb
--- /dev/null
+++ b/tests/tests/security/res/raw/bug_127313764.mid
Binary files differ
diff --git a/tests/tests/security/res/raw/cve_2019_10489.avi b/tests/tests/security/res/raw/cve_2019_10489.avi
deleted file mode 100644
index a3eba77..0000000
--- a/tests/tests/security/res/raw/cve_2019_10489.avi
+++ /dev/null
Binary files differ
diff --git a/tests/tests/security/src/android/security/cts/StagefrightTest.java b/tests/tests/security/src/android/security/cts/StagefrightTest.java
index 9ebb0ab..6b122da 100644
--- a/tests/tests/security/src/android/security/cts/StagefrightTest.java
+++ b/tests/tests/security/src/android/security/cts/StagefrightTest.java
@@ -1104,16 +1104,6 @@
         doStagefrightTest(R.raw.cve_2019_10541);
     }
 
-    @SecurityTest(minPatchLevel = "2019-09")
-    public void testStagefright_cve_2019_10488() throws Exception {
-        doStagefrightTest(R.raw.cve_2019_10488);
-    }
-
-    @SecurityTest(minPatchLevel = "2019-08")
-    public void testStagefright_cve_2019_10489() throws Exception {
-        doStagefrightTest(R.raw.cve_2019_10489);
-    }
-
     @SecurityTest(minPatchLevel = "2018-02")
     public void testStagefright_cve_2017_13233() throws Exception {
         doStagefrightTestRawBlob(R.raw.cve_2017_13233_hevc, "video/hevc", 640,
@@ -1378,8 +1368,10 @@
             Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service"),
             Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.clearkey"),
             Pattern.compile("android\\.hardware\\.drm@\\d+?\\.\\d+?-service\\.widevine"),
+            Pattern.compile("omx@\\d+?\\.\\d+?-service"),  // name:omx@1.0-service
             Pattern.compile("android\\.process\\.media"),
             Pattern.compile("mediadrmserver"),
+            Pattern.compile("mediaextractor"),
             Pattern.compile("media\\.extractor"),
             Pattern.compile("media\\.metrics"),
             Pattern.compile("mediaserver"),
@@ -1971,6 +1963,36 @@
         doStagefrightTestRawBlob(R.raw.bug_70897394_avc, "video/avc", 320, 240, false);
     }
 
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_123700383() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_123700383);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127310810() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127310810);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127312550() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127312550);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313223() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313223);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313537() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313537);
+    }
+
+    @SecurityTest(minPatchLevel = "Unknown")
+    public void testBug_127313764() throws Exception {
+        assertExtractorDoesNotHang(R.raw.bug_127313764);
+    }
+
     private int[] getFrameSizes(int rid) throws IOException {
         final Context context = getInstrumentation().getContext();
         final Resources resources =  context.getResources();
@@ -2392,4 +2414,35 @@
         thr.stopLooper();
         thr.join();
     }
+
+    protected void assertExtractorDoesNotHang(int rid) throws Exception {
+        // The media extractor has a watchdog, currently set to 10 seconds.
+        final long timeoutMs = 12 * 1000;
+
+        Thread thread = new Thread(() -> {
+            MediaExtractor ex = new MediaExtractor();
+            AssetFileDescriptor fd =
+                    getInstrumentation().getContext().getResources().openRawResourceFd(rid);
+            try {
+                ex.setDataSource(fd.getFileDescriptor(), fd.getStartOffset(), fd.getLength());
+            } catch (IOException e) {
+                // It is OK for the call to fail, we're only making sure it doesn't hang.
+            } finally {
+                closeQuietly(fd);
+                ex.release();
+            }
+        });
+        thread.start();
+
+        thread.join(timeoutMs);
+        boolean hung = thread.isAlive();
+        if (hung) {
+            // We don't have much to do at this point. Attempt to un-hang the thread, the media
+            // extractor process is likely still spinning. At least we found a bug...
+            // TODO: reboot the media extractor process.
+            thread.interrupt();
+        }
+
+        assertFalse(hung);
+    }
 }
diff --git a/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp b/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
index e8667b9..6c5d7ca 100644
--- a/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
+++ b/tests/tests/selinux/common/jni/android_security_SELinuxTargetSdkTest.cpp
@@ -33,6 +33,37 @@
 typedef std::unique_ptr<char[], SecurityContext_Delete> Unique_SecurityContext;
 
 /**
+ * Function: checkNetlinkRouteGetlink
+ * Purpose: Checks to see if RTM_GETLINK is allowed on a netlink route socket.
+ * Returns: 13 (expected) if RTM_GETLINK fails with permission denied.
+ *          0 if socket creation fails
+ *          -1 if bind() succeeds.
+ */
+static jint checkNetlinkRouteGetlink() {
+    int sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+    if (sock < 0) {
+        __android_log_print(ANDROID_LOG_ERROR, "SELLinuxTargetSdkTest", "socket creation failed.");
+        return 0;
+    }
+    struct NetlinkMessage {
+        nlmsghdr hdr;
+        rtgenmsg msg;
+    } request;
+    memset(&request, 0, sizeof(request));
+    request.hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+    request.hdr.nlmsg_type = RTM_GETLINK;
+    request.hdr.nlmsg_len = sizeof(request);
+    request.msg.rtgen_family = AF_UNSPEC;
+
+    int ret = send(sock, &request, sizeof(request), 0);
+    if (ret < 0) {
+        return errno;
+    }
+
+    return -1;
+}
+
+/**
  * Function: checkNetlinkRouteBind
  * Purpose: Checks to see if bind() is allowed on a netlink route socket.
  * Returns: 13 (expected) if bind() fails with permission denied.
@@ -90,6 +121,7 @@
 static JNINativeMethod gMethods[] = {
     { "getFileContext", "(Ljava/lang/String;)Ljava/lang/String;", (void*) getFileContext },
     { "checkNetlinkRouteBind", "()I", (void*) checkNetlinkRouteBind },
+    { "checkNetlinkRouteGetlink", "()I", (void*) checkNetlinkRouteGetlink },
 };
 
 int register_android_security_SELinuxTargetSdkTest(JNIEnv* env)
diff --git a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
index aa6800e..eeb8312 100644
--- a/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
+++ b/tests/tests/selinux/common/src/android/security/SELinuxTargetSdkTestBase.java
@@ -29,27 +29,6 @@
         }
     }
 
-    protected static void noExecuteOnly() throws IOException {
-        String[] maps = {"^[0-9a-z]+-[0-9a-z]+\\s+--xp.*\\/apex\\/com\\.android\\.runtime\\/.*",
-            "^[0-9a-z]+-[0-9a-z]+\\s+--xp.*\\/system\\/.*"};
-        for (String map : maps) {
-            final Pattern mapsPattern = Pattern.compile(map);
-            BufferedReader reader = new BufferedReader(new FileReader("/proc/self/maps"));
-            String line;
-            try {
-                while ((line = reader.readLine()) != null) {
-                    Matcher m = mapsPattern.matcher(line);
-                    assertFalse("System provided libraries should be not be marked execute-only " +
-                           "for apps with targetSdkVersion<Q, but an execute-only segment was " +
-                           "found:\n" + line, m.matches());
-                }
-
-            } finally {
-                reader.close();
-            }
-        }
-    }
-
     protected static String getProperty(String property)
             throws IOException {
         Process process = new ProcessBuilder("getprop", property).start();
@@ -78,6 +57,12 @@
         }
     }
 
+    protected static void noNetlinkRouteGetlink() throws IOException {
+        assertEquals("RTM_GETLINK is not allowed on a netlink route sockets. Verify that the " +
+			"following patch has been applied to your kernel: " +
+			"https://android-review.googlesource.com/q/I7b44ce60ad98f858c412722d41b9842f8577151f",
+                13, checkNetlinkRouteGetlink());
+    }
 
     protected static void noNetlinkRouteBind() throws IOException {
         assertEquals("Bind() is not allowed on a netlink route sockets",
@@ -161,6 +146,7 @@
         return true;
     }
 
+    private static final native int checkNetlinkRouteGetlink();
     private static final native int checkNetlinkRouteBind();
     private static final native String getFileContext(String path);
 }
diff --git a/tests/tests/selinux/selinuxTargetSdk25/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk25/src/android/security/SELinuxTargetSdkTest.java
index dddd3d9..ec2af2d 100644
--- a/tests/tests/selinux/selinuxTargetSdk25/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk25/src/android/security/SELinuxTargetSdkTest.java
@@ -68,8 +68,4 @@
     public void testDex2oat() throws Exception {
         checkDex2oatAccess(true);
     }
-
-    public void testNoExecuteOnly() throws IOException {
-        noExecuteOnly();
-    }
 }
diff --git a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
index e7c0e67..0394a18 100644
--- a/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk27/src/android/security/SELinuxTargetSdkTest.java
@@ -64,8 +64,4 @@
     public void testDex2oat() throws Exception {
         checkDex2oatAccess(true);
     }
-
-    public void testNoExecuteOnly() throws IOException {
-        noExecuteOnly();
-    }
 }
diff --git a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
index 1ab9706..92e1070 100644
--- a/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdk28/src/android/security/SELinuxTargetSdkTest.java
@@ -64,8 +64,4 @@
     public void testDex2oat() throws Exception {
         checkDex2oatAccess(true);
     }
-
-    public void testNoExecuteOnly() throws IOException {
-        noExecuteOnly();
-    }
 }
diff --git a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
index e6d8796..859864e 100644
--- a/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
+++ b/tests/tests/selinux/selinuxTargetSdkCurrent/src/android/security/SELinuxTargetSdkTest.java
@@ -33,6 +33,10 @@
         noDns();
     }
 
+    public void testNoNetlinkRouteGetlink() throws IOException {
+        noNetlinkRouteGetlink();
+    }
+
     public void testNoNetlinkRouteBind() throws IOException {
         noNetlinkRouteBind();
     }
diff --git a/tests/tests/tagging/Android.bp b/tests/tests/tagging/Android.bp
new file mode 100644
index 0000000..d89cd28
--- /dev/null
+++ b/tests/tests/tagging/Android.bp
@@ -0,0 +1,21 @@
+cc_test_library {
+    name: "libtaggingtest",
+    srcs: ["libtaggingtest/android_tagging_cts_TaggingTest.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    sdk_version: "current",
+    gtest: false,
+}
+
+cc_test_library {
+    name: "libtaggingdisabledtest",
+    srcs: ["libtaggingtest/android_tagging_disabled_cts_TaggingTest.cpp"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+    ],
+    sdk_version: "current",
+    gtest: false,
+}
diff --git a/tests/tests/tagging/OWNERS b/tests/tests/tagging/OWNERS
new file mode 100644
index 0000000..9686261
--- /dev/null
+++ b/tests/tests/tagging/OWNERS
@@ -0,0 +1,5 @@
+# Bug component: 14890
+eugenis@google.com
+pcc@google.com
+mitchp@google.com
+
diff --git a/tests/tests/tagging/TEST_MAPPING b/tests/tests/tagging/TEST_MAPPING
new file mode 100644
index 0000000..6a9b662
--- /dev/null
+++ b/tests/tests/tagging/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsTaggingTestCases"
+    },
+    {
+      "name": "CtsTaggingDisabledTestCases"
+    }
+  ]
+}
diff --git a/tests/tests/tagging/disabled/Android.bp b/tests/tests/tagging/disabled/Android.bp
new file mode 100644
index 0000000..078261b
--- /dev/null
+++ b/tests/tests/tagging/disabled/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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.
+
+android_test {
+    name: "CtsTaggingDisabledTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    // When built, explicitly put it in the data partition.
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    static_libs: [
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+    ],
+    jni_libs: [
+        "libtaggingdisabledtest",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    use_embedded_native_libs: false,
+}
diff --git a/tests/tests/tagging/disabled/AndroidManifest.xml b/tests/tests/tagging/disabled/AndroidManifest.xml
new file mode 100644
index 0000000..29dbb1f
--- /dev/null
+++ b/tests/tests/tagging/disabled/AndroidManifest.xml
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.tagging.disabled.cts"
+    android:targetSandboxVersion="2">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <application android:extractNativeLibs="true"
+                 android:allowNativeHeapPointerTagging="false">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.tagging.disabled.cts"
+                     android:label="CTS tests of heap pointer tagging">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/net/AndroidTest.xml b/tests/tests/tagging/disabled/AndroidTest.xml
similarity index 67%
copy from tests/tests/net/AndroidTest.xml
copy to tests/tests/tagging/disabled/AndroidTest.xml
index 3ff019e..e69dcdc 100644
--- a/tests/tests/net/AndroidTest.xml
+++ b/tests/tests/tagging/disabled/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -12,22 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Net test cases">
+<configuration description="Config for CTS Tagging test cases">
     <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="networking" />
-    <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-    <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsNetTestCases.apk" />
+        <option name="test-file-name" value="CtsTaggingDisabledTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.net.cts" />
-        <option name="runtime-hint" value="9m4s" />
-        <option name="hidden-api-checks" value="false" />
-        <option name="isolated-storage" value="false" />
+        <option name="package" value="android.tagging.disabled.cts" />
     </test>
 </configuration>
diff --git a/tests/tests/tagging/disabled/src/android/tagging/disabled/cts/TaggingTest.java b/tests/tests/tagging/disabled/src/android/tagging/disabled/cts/TaggingTest.java
new file mode 100644
index 0000000..2ea47a1
--- /dev/null
+++ b/tests/tests/tagging/disabled/src/android/tagging/disabled/cts/TaggingTest.java
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2020 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.tagging.disabled.cts;
+
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TaggingTest {
+
+    static {
+      System.loadLibrary("taggingdisabledtest");
+    }
+
+    public static native int nativeHeapPointerTag();
+
+    @Test
+    public void testHeapTaggingDisabled() {
+      assertEquals(0, nativeHeapPointerTag());
+    }
+}
diff --git a/tests/tests/tagging/enabled/Android.bp b/tests/tests/tagging/enabled/Android.bp
new file mode 100644
index 0000000..0571e42
--- /dev/null
+++ b/tests/tests/tagging/enabled/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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.
+
+android_test {
+    name: "CtsTaggingTestCases",
+    defaults: ["cts_defaults"],
+    compile_multilib: "both",
+    // When built, explicitly put it in the data partition.
+    // Tag this module as a cts test artifact
+    test_suites: [
+        "cts",
+        "vts",
+        "general-tests",
+    ],
+    static_libs: [
+        "ctstestrunner-axt",
+        "androidx.test.rules",
+        "androidx.test.core",
+        "androidx.test.ext.junit",
+    ],
+    jni_libs: [
+        "libtaggingtest",
+    ],
+    srcs: ["src/**/*.java"],
+    sdk_version: "current",
+    use_embedded_native_libs: false,
+}
diff --git a/tests/tests/tagging/enabled/AndroidManifest.xml b/tests/tests/tagging/enabled/AndroidManifest.xml
new file mode 100644
index 0000000..886c29a
--- /dev/null
+++ b/tests/tests/tagging/enabled/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.tagging.cts"
+    android:targetSandboxVersion="2">
+
+    <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
+    <application android:extractNativeLibs="true">
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!-- This is a self-instrumenting test package. -->
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+                     android:targetPackage="android.tagging.cts"
+                     android:label="CTS tests of heap pointer tagging">
+        <meta-data android:name="listener"
+            android:value="com.android.cts.runner.CtsTestRunListener" />
+    </instrumentation>
+
+</manifest>
+
diff --git a/tests/tests/net/AndroidTest.xml b/tests/tests/tagging/enabled/AndroidTest.xml
similarity index 67%
copy from tests/tests/net/AndroidTest.xml
copy to tests/tests/tagging/enabled/AndroidTest.xml
index 3ff019e..689594c 100644
--- a/tests/tests/net/AndroidTest.xml
+++ b/tests/tests/tagging/enabled/AndroidTest.xml
@@ -1,4 +1,5 @@
-<!-- Copyright (C) 2015 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -12,22 +13,17 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<configuration description="Config for CTS Net test cases">
+<configuration description="Config for CTS Tagging test cases">
     <option name="test-suite-tag" value="cts" />
-    <option name="config-descriptor:metadata" key="component" value="networking" />
-    <option name="config-descriptor:metadata" key="token" value="SIM_CARD" />
+    <option name="config-descriptor:metadata" key="component" value="art" />
     <option name="config-descriptor:metadata" key="parameter" value="instant_app" />
-    <option name="config-descriptor:metadata" key="parameter" value="not_multi_abi" />
+    <option name="config-descriptor:metadata" key="parameter" value="multi_abi" />
     <option name="config-descriptor:metadata" key="parameter" value="secondary_user" />
-    <option name="not-shardable" value="true" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
-        <option name="test-file-name" value="CtsNetTestCases.apk" />
+        <option name="test-file-name" value="CtsTaggingTestCases.apk" />
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
-        <option name="package" value="android.net.cts" />
-        <option name="runtime-hint" value="9m4s" />
-        <option name="hidden-api-checks" value="false" />
-        <option name="isolated-storage" value="false" />
+        <option name="package" value="android.tagging.cts" />
     </test>
 </configuration>
diff --git a/tests/tests/tagging/enabled/src/android/tagging/cts/TaggingTest.java b/tests/tests/tagging/enabled/src/android/tagging/cts/TaggingTest.java
new file mode 100644
index 0000000..189b8de
--- /dev/null
+++ b/tests/tests/tagging/enabled/src/android/tagging/cts/TaggingTest.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2020 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.tagging.cts;
+
+import android.os.Build;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class TaggingTest {
+
+    static {
+      System.loadLibrary("taggingtest");
+    }
+
+    public static native boolean kernelSupportsTaggedPointers();
+    public static native int nativeHeapPointerTag();
+
+    @Test
+    public void testHeapTaggingEnabled() {
+      // Skip the test if not Arm64.
+      if (Build.CPU_ABI.startsWith("arm64")) {
+        int tag = nativeHeapPointerTag();
+        if (kernelSupportsTaggedPointers()) {
+          assertNotEquals(0, tag);
+        } else {
+          assertEquals(0, tag);
+        }
+      }
+    }
+}
diff --git a/tests/tests/tagging/libtaggingtest/android_tagging_cts_TaggingTest.cpp b/tests/tests/tagging/libtaggingtest/android_tagging_cts_TaggingTest.cpp
new file mode 100644
index 0000000..be63288
--- /dev/null
+++ b/tests/tests/tagging/libtaggingtest/android_tagging_cts_TaggingTest.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/*
+ * Native implementation for the JniStaticTest parts.
+ */
+
+#include <jni.h>
+#include <stdlib.h>
+#include <sys/prctl.h>
+
+extern "C" JNIEXPORT jboolean Java_android_tagging_cts_TaggingTest_kernelSupportsTaggedPointers() {
+#ifdef __aarch64__
+#define PR_SET_TAGGED_ADDR_CTRL 55
+#define PR_TAGGED_ADDR_ENABLE (1UL << 0)
+  int res = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0);
+  return res >= 0 && res & PR_TAGGED_ADDR_ENABLE;
+#else
+  return false;
+#endif
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_android_tagging_cts_TaggingTest_nativeHeapPointerTag(
+        JNIEnv*) {
+#ifdef __aarch64__
+  void* p = malloc(10);
+  jint tag = reinterpret_cast<uintptr_t>(p) >> 56;
+  free(p);
+  return tag;
+#else
+  return 0;
+#endif
+}
diff --git a/tests/tests/tagging/libtaggingtest/android_tagging_disabled_cts_TaggingTest.cpp b/tests/tests/tagging/libtaggingtest/android_tagging_disabled_cts_TaggingTest.cpp
new file mode 100644
index 0000000..2b6918e
--- /dev/null
+++ b/tests/tests/tagging/libtaggingtest/android_tagging_disabled_cts_TaggingTest.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+/*
+ * Native implementation for the JniStaticTest parts.
+ */
+
+#include <jni.h>
+#include <stdlib.h>
+
+extern "C" JNIEXPORT jint JNICALL Java_android_tagging_disabled_cts_TaggingTest_nativeHeapPointerTag(
+        JNIEnv*) {
+#ifdef __aarch64__
+  void* p = malloc(10);
+  jint tag = reinterpret_cast<uintptr_t>(p) >> 56;
+  free(p);
+  return tag;
+#else
+  return 0;
+#endif
+}
diff --git a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
index 6b1444a..a6fe2bf 100644
--- a/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/CallDetailsTest.java
@@ -283,8 +283,8 @@
         mConnection.setConnectionProperties(Connection.PROPERTY_IS_RTT);
         assertCallProperties(mCall, Call.Details.PROPERTY_RTT);
 
-        mConnection.setConnectionProperties(Connection.PROPERTY_ASSISTED_DIALING_USED);
-        assertCallProperties(mCall, Call.Details.PROPERTY_ASSISTED_DIALING_USED);
+        mConnection.setConnectionProperties(Connection.PROPERTY_ASSISTED_DIALING);
+        assertCallProperties(mCall, Call.Details.PROPERTY_ASSISTED_DIALING);
 
         mConnection.setConnectionProperties(Connection.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
         assertCallProperties(mCall, Call.Details.PROPERTY_NETWORK_IDENTIFIED_EMERGENCY_CALL);
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
index 771f09b..cb0d769 100644
--- a/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConferenceTest.java
@@ -199,7 +199,7 @@
         // Consumed internally in Telecom; no verifiable manner to see the end point of this data
         // through public APIs.
         mConferenceObject.setConnectionTime(0);
-        mConferenceObject.setConnectionStartElapsedRealTime(0);
+        mConferenceObject.setConnectionStartElapsedRealtimeMillis(0);
 
         Bundle extras = new Bundle();
         extras.putString(TelecomManager.EXTRA_CALL_DISCONNECT_MESSAGE, "Test");
diff --git a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
index e0bb29e..08931eb 100755
--- a/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/ConnectionServiceTest.java
@@ -272,8 +272,8 @@
         connection.setCallDirection(Call.Details.DIRECTION_OUTGOING);
         connection.setConnectTimeMillis(1000L);
         assertEquals(1000L, connection.getConnectTimeMillis());
-        connection.setConnectionStartElapsedRealTime(100L);
-        assertEquals(100L, connection.getConnectElapsedTimeMillis());
+        connection.setConnectionStartElapsedRealtimeMillis(100L);
+        assertEquals(100L, connection.getConnectionStartElapsedRealtimeMillis());
 
         CtsConnectionService.addExistingConnectionToTelecom(TEST_PHONE_ACCOUNT_HANDLE, connection);
         assertNumCalls(mInCallCallbacks.getService(), 2);
diff --git a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
index ed6decb..3db905f 100644
--- a/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
+++ b/tests/tests/telecom/src/android/telecom/cts/DefaultDialerOperationsTest.java
@@ -96,7 +96,7 @@
         assertEquals(TestUtils.PACKAGE, mTelecomManager.getDefaultDialerPackage());
         assertEquals(mTelecomManager.getDefaultDialerPackage(),
                 ShellIdentityUtils.invokeMethodWithShellPermissions(mTelecomManager,
-                        tm -> tm.getDefaultDialerPackage(Process.myUserHandle().getIdentifier())));
+                        tm -> tm.getDefaultDialerPackage(Process.myUserHandle())));
     }
 
     /** Default dialer should be the default package handling ACTION_DIAL. */
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
index cfc1214..4423ed5 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/CellInfoTest.java
@@ -24,9 +24,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
-import android.Manifest;
-import android.Manifest.permission;
-import android.app.UiAutomation;
+import android.annotation.Nullable;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.Parcel;
@@ -51,14 +49,14 @@
 import android.telephony.CellSignalStrengthNr;
 import android.telephony.CellSignalStrengthTdscdma;
 import android.telephony.CellSignalStrengthWcdma;
+import android.telephony.ClosedSubscriberGroupInfo;
 import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.TelephonyManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
-import androidx.test.InstrumentationRegistry;
-
 import org.junit.Before;
 import org.junit.Test;
 
@@ -329,8 +327,9 @@
         assertTrue("Invalid timestamp in CellInfo: " + info.getTimeStamp(),
                 info.getTimeStamp() > 0 && info.getTimeStamp() < Long.MAX_VALUE);
 
-        assertTrue("Invalid timestamp in CellInfo: " + info.getTimestampNanos(),
-                info.getTimestampNanos() > 0 && info.getTimestampNanos() < Long.MAX_VALUE);
+        long curTime = SystemClock.elapsedRealtime();
+        assertTrue("Invalid timestamp in CellInfo: " + info.getTimestampMillis(),
+                info.getTimestampMillis() > 0 && info.getTimestampMillis() <= curTime);
 
         if (mRadioHalVersion >= RADIO_HAL_VERSION_1_2) {
             // In HAL 1.2 or greater, the connection status must be reported
@@ -517,6 +516,14 @@
     }
 
     private void verifyCellIdentityNr(CellIdentityNr nr, boolean isRegistered) {
+        // This class was added after numeric mcc/mncs were no longer provided, so it lacks the
+        // basic getMcc() and getMnc() - Dummy out those checks.
+        String mccStr = nr.getMccString();
+        String mncStr = nr.getMncString();
+        verifyPlmnInfo(mccStr, mncStr,
+                mccStr != null ? Integer.parseInt(mccStr) : CellInfo.UNAVAILABLE,
+                mncStr != null ? Integer.parseInt(mncStr) : CellInfo.UNAVAILABLE);
+
         int pci = nr.getPci();
         assertTrue("getPci() out of range [0, 1007], pci = " + pci, 0 <= pci && pci <= 1007);
 
@@ -527,15 +534,9 @@
         assertTrue("getNrarfcn() out of range [0, 3279165], nrarfcn = " + nrArfcn,
                 0 <= nrArfcn && nrArfcn <= 3279165);
 
-        String mccStr = nr.getMccString();
-        String mncStr = nr.getMncString();
-        // mccStr is set as NULL if empty, unknown or invalid.
-        assertTrue("getMccString() out of range [0, 999], mcc=" + mccStr,
-                mccStr == null || mccStr.matches("^[0-9]{3}$"));
-
-        // mncStr is set as NULL if empty, unknown or invalid.
-        assertTrue("getMncString() out of range [0, 999], mnc=" + mncStr,
-                mncStr == null || mncStr.matches("^[0-9]{2,3}$"));
+        for (String plmnId : nr.getAdditionalPlmns()) {
+            verifyPlmnId(plmnId);
+        }
 
         // If the cell is reported as registered, then all the logical cell info must be reported
         if (isRegistered) {
@@ -631,6 +632,12 @@
                 mobileNetworkOperator == null
                         || mobileNetworkOperator.matches("^[0-9]{5,6}$"));
 
+        for (String plmnId : lte.getAdditionalPlmns()) {
+            verifyPlmnId(plmnId);
+        }
+
+        verifyCsgInfo(lte.getClosedSubscriberGroupInfo());
+
         // If the cell is reported as registered, then all the logical cell info must be reported
         if (isRegistered) {
             assertTrue("TAC is required for registered cells", tac != Integer.MAX_VALUE);
@@ -757,6 +764,12 @@
         assertTrue("getUarfcn() out of range [412,11000], uarfcn=" + uarfcn,
                 uarfcn >= 412 && uarfcn <= 11000);
 
+        for (String plmnId : wcdma.getAdditionalPlmns()) {
+            verifyPlmnId(plmnId);
+        }
+
+        verifyCsgInfo(wcdma.getClosedSubscriberGroupInfo());
+
         // If the cell is reported as registered, then all the logical cell info must be reported
         if (isRegistered) {
             assertTrue("LAC is required for registered cells", lac != Integer.MAX_VALUE);
@@ -855,6 +868,10 @@
         // TODO(b/32774471) - Bsic should always be valid
         //assertTrue("getBsic() out of range [0,63]", bsic >= 0 && bsic <=63);
 
+        for (String plmnId : gsm.getAdditionalPlmns()) {
+            verifyPlmnId(plmnId);
+        }
+
         // If the cell is reported as registered, then all the logical cell info must be reported
         if (isRegistered) {
             assertTrue("LAC is required for registered cells", lac != Integer.MAX_VALUE);
@@ -965,6 +982,10 @@
         assertTrue("getUarfcn() out of range [412,11000], uarfcn=" + uarfcn,
                 uarfcn >= 412 && uarfcn <= 11000);
 
+        for (String plmnId : tdscdma.getAdditionalPlmns()) {
+            verifyPlmnId(plmnId);
+        }
+
         // If the cell is reported as registered, then all the logical cell info must be reported
         if (isRegistered) {
             assertTrue("LAC is required for registered cells", lac != Integer.MAX_VALUE);
@@ -1012,16 +1033,38 @@
     }
 
     // Rssi(in dbm) should be within [MIN_RSSI, MAX_RSSI].
-    private void verifyRssiDbm(int dbm) {
+    private static void verifyRssiDbm(int dbm) {
         assertTrue("getCellSignalStrength().getDbm() out of range, dbm=" + dbm,
                 dbm >= MIN_RSSI && dbm <= MAX_RSSI);
     }
 
-    private void verifyCellConnectionStatus(int status) {
+    private static void verifyCellConnectionStatus(int status) {
         assertTrue("getCellConnectionStatus() invalid [0,2] | Integer.MAX_VALUE, status=",
             status == CellInfo.CONNECTION_NONE
                 || status == CellInfo.CONNECTION_PRIMARY_SERVING
                 || status == CellInfo.CONNECTION_SECONDARY_SERVING
                 || status == CellInfo.CONNECTION_UNKNOWN);
     }
+
+    private static void verifyPlmnId(String plmnId) {
+        if (TextUtils.isEmpty(plmnId)) return;
+
+        assertTrue("PlmnId() out of range [00000 - 999999], PLMN ID=" + plmnId,
+                plmnId.matches("^[0-9]{5,6}$"));
+    }
+
+    private static void verifyCsgInfo(@Nullable ClosedSubscriberGroupInfo csgInfo) {
+        if (csgInfo == null) return;
+
+        // This is boolean, so as long as it doesn't crash, we're good.
+        csgInfo.getCsgIndicator();
+        // This is nullable, and it's free-form so all we can do is ensure it doesn't crash.
+        csgInfo.getHomeNodebName();
+
+        // It might be technically possible to have a CSG ID of zero, but if that's the case
+        // then let someone complain about it. It's far more likely that if it's '0', then there
+        // is a bug.
+        assertTrue("CSG Identity out of range", csgInfo.getCsgIdentity() > 0
+                && csgInfo.getCsgIdentity() <= 0x7FFFFF);
+    }
 }
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java b/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
index 427ede3..a5e75c5 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/NetworkRegistrationInfoTest.java
@@ -15,17 +15,18 @@
  */
 package android.telephony.cts;
 
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotSame;
-
 import android.telephony.AccessNetworkConstants;
 import android.telephony.NetworkRegistrationInfo;
 import android.telephony.TelephonyManager;
 
-import java.util.Arrays;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
 
 import org.junit.Test;
 
+import java.util.Arrays;
+
 public class NetworkRegistrationInfoTest {
 
     @Test
@@ -87,6 +88,30 @@
     }
 
     @Test
+    public void testGetEmergencyServices() {
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setAvailableServices(Arrays.asList(NetworkRegistrationInfo.SERVICE_TYPE_EMERGENCY,
+                        NetworkRegistrationInfo.SERVICE_TYPE_VOICE))
+                .build();
+        assertEquals(Arrays.asList(NetworkRegistrationInfo.SERVICE_TYPE_EMERGENCY,
+                NetworkRegistrationInfo.SERVICE_TYPE_VOICE), nri.getAvailableServices());
+    }
+
+     /**
+     * Basic test to ensure {@link NetworkRegistrationInfo#isSearching()} does not throw any
+     * exception.
+     */
+    @Test
+    public void testNetworkRegistrationInfoIsSearching() {
+        NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
+                .setRegistrationState(
+                    NetworkRegistrationInfo.REGISTRATION_STATE_NOT_REGISTERED_SEARCHING)
+                .build();
+        assertTrue(nri.isSearching());
+    }
+
+
+    @Test
     public void testGetDomain() {
         NetworkRegistrationInfo nri = new NetworkRegistrationInfo.Builder()
                 .setDomain(NetworkRegistrationInfo.DOMAIN_CS)
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
index 3077bbb..0849b64 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SignalStrengthTest.java
@@ -38,13 +38,13 @@
 import android.telephony.TelephonyManager;
 import android.util.Log;
 
+import org.junit.Before;
+import org.junit.Test;
+
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
-import org.junit.Before;
-import org.junit.Test;
-
 /**
  * Test SignalStrength to ensure that valid data is being reported and that invalid data is
  * not reported.
@@ -81,10 +81,10 @@
         SignalStrength ss = mTm.getSignalStrength();
         assertNotNull("TelephonyManager.getSignalStrength() returned NULL!", ss);
 
-        long curTime = SystemClock.elapsedRealtimeNanos();
-        assertTrue("Invalid timestamp in SignalStrength: " + ss.getTimestampNanos(),
-                ss.getTimestampNanos() > 0 && ss.getTimestampNanos() < curTime);
-        Log.d(TAG, "Timestamp of SignalStrength: " + Long.toString(ss.getTimestampNanos()));
+        long curTime = SystemClock.elapsedRealtime();
+        assertTrue("Invalid timestamp in SignalStrength: " + ss.getTimestampMillis(),
+                ss.getTimestampMillis() > 0 && ss.getTimestampMillis() <= curTime);
+        Log.d(TAG, "Timestamp of SignalStrength: " + Long.toString(ss.getTimestampMillis()));
 
         List<CellSignalStrength> signalStrengths = ss.getCellSignalStrengths();
 
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
index 8c855db..7c8c9d46 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/SmsMessageTest.java
@@ -23,7 +23,6 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
 
 import android.content.Context;
 import android.content.pm.PackageManager;
@@ -241,26 +240,22 @@
             return;
         }
 
+        SmsMessage.SubmitPdu smsPdu;
         String scAddress = null, destinationAddress = null;
         String message = null;
         boolean statusReportRequested = false;
 
-        try {
-            // null message, null destination
-            SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException expected) {
-            // expected
-        }
+        // Null message, null destination
+        smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message,
+                statusReportRequested);
+        assertNull(smsPdu);
 
         message = "This is a test message";
-        try {
-            // non-null message
-            SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested);
-            fail("Should throw NullPointerException");
-        } catch (NullPointerException expected) {
-            // expected
-        }
+
+        // Non-null message, null destination
+        smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, message,
+                statusReportRequested);
+        assertNull(smsPdu);
 
         if (mTelephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
             // TODO: temp workaround, OCTET encoding for EMS not properly supported
@@ -271,8 +266,8 @@
         destinationAddress = "18004664411";
         message = "This is a test message";
         statusReportRequested = false;
-        SmsMessage.SubmitPdu smsPdu =
-            SmsMessage.getSubmitPdu(scAddress, destinationAddress, message, statusReportRequested);
+        smsPdu = SmsMessage.getSubmitPdu(
+                scAddress, destinationAddress, message, statusReportRequested);
         assertNotNull(smsPdu);
 
         smsPdu = SmsMessage.getSubmitPdu(scAddress, destinationAddress, (short)80,
diff --git a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
index 6a0f568..e5f5007 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -1456,6 +1456,40 @@
     }
 
     /**
+     * Basic test to ensure {@link NetworkRegistrationInfo#getRegisteredPlmn()} provides valid
+     * information.
+     */
+    @Test
+    public void testNetworkRegistrationInfoRegisteredPlmn() {
+        if (!mPackageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return;
+        }
+        // get NetworkRegistration object
+        ServiceState ss = mTelephonyManager.getServiceState();
+        assertNotNull(ss);
+
+        boolean hasRegistered = false;
+        for (NetworkRegistrationInfo nwReg : ss.getNetworkRegistrationInfoList()) {
+            if (nwReg.isRegistered()
+                        && nwReg.getTransportType() == AccessNetworkConstants.TRANSPORT_TYPE_WWAN) {
+                hasRegistered = true;
+                String plmnId = nwReg.getRegisteredPlmn();
+                // CDMA doesn't have PLMN IDs. Rather than put CID|NID here, instead it will be
+                // empty. It's a case that's becoming less important over time, but for now a
+                // device that's only registered on CDMA needs to pass this test.
+                if (nwReg.getCellIdentity() instanceof android.telephony.CellIdentityCdma) {
+                    assertTrue(TextUtils.isEmpty(plmnId));
+                } else {
+                    assertFalse(TextUtils.isEmpty(plmnId));
+                    assertTrue("PlmnId() out of range [00000 - 999999], PLMN ID=" + plmnId,
+                            plmnId.matches("^[0-9]{5,6}$"));
+                }
+            }
+        }
+        assertTrue(hasRegistered);
+    }
+
+    /**
      * Basic test to ensure {@link NetworkRegistrationInfo#isRoaming()} does not throw any
      * exception.
      */
diff --git a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
index 043d04f..98dbe52 100644
--- a/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
+++ b/tests/tests/tethering/src/android/tethering/cts/TetheringManagerTest.java
@@ -15,13 +15,16 @@
  */
 package android.tethering.test;
 
+import static android.net.TetheringManager.TETHERING_WIFI;
+
 import static org.junit.Assert.fail;
 
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.net.ConnectivityManager;
+import android.net.TetheringManager;
+import android.net.TetheringManager.TetheringRequest;
 import android.os.ConditionVariable;
 
 import androidx.test.InstrumentationRegistry;
@@ -35,6 +38,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Iterator;
+import java.util.concurrent.Executor;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
 
@@ -43,7 +47,7 @@
 
     private Context mContext;
 
-    private ConnectivityManager mCM;
+    private TetheringManager mTM;
 
     private TetherChangeReceiver mTetherChangeReceiver;
 
@@ -57,10 +61,10 @@
                 .getUiAutomation()
                 .adoptShellPermissionIdentity();
         mContext = InstrumentationRegistry.getContext();
-        mCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
+        mTM = (TetheringManager) mContext.getSystemService(Context.TETHERING_SERVICE);
         mTetherChangeReceiver = new TetherChangeReceiver();
         final IntentFilter filter = new IntentFilter(
-                ConnectivityManager.ACTION_TETHER_STATE_CHANGED);
+                TetheringManager.ACTION_TETHER_STATE_CHANGED);
         final Intent intent = mContext.registerReceiver(mTetherChangeReceiver, filter);
         if (intent != null) mTetherChangeReceiver.onReceive(null, intent);
     }
@@ -81,36 +85,37 @@
 
             TetherState(Intent intent) {
                 mAvailable = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_AVAILABLE_TETHER);
+                        TetheringManager.EXTRA_AVAILABLE_TETHER);
                 mActive = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_ACTIVE_TETHER);
+                        TetheringManager.EXTRA_ACTIVE_TETHER);
                 mErrored = intent.getStringArrayListExtra(
-                        ConnectivityManager.EXTRA_ERRORED_TETHER);
+                        TetheringManager.EXTRA_ERRORED_TETHER);
             }
         }
 
         @Override
         public void onReceive(Context content, Intent intent) {
             String action = intent.getAction();
-            if (action.equals(ConnectivityManager.ACTION_TETHER_STATE_CHANGED)) {
+            if (action.equals(TetheringManager.ACTION_TETHER_STATE_CHANGED)) {
                 mResult.add(new TetherState(intent));
             }
         }
 
         public final LinkedBlockingQueue<TetherState> mResult = new LinkedBlockingQueue<>();
 
-        // This method expects either an event where one of the interfaces is active, or an event
-        // where one of the interface is available followed by one where one of the interfaces is
-        // active.
+        // This method expects either an event where one of the interfaces is active, or events
+        // where the interfaces are available followed by one event where one of the interfaces is
+        // active. Here is a typical example for wifi tethering:
+        // AVAILABLE(wlan0) -> AVAILABLE(wlan1) -> ACTIVATE(wlan1).
         public void expectActiveTethering(String[] ifaceRegexs) {
-            TetherState state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
-            if (state == null) fail("Do not receive tethering state change broadcast");
-
-            if (isIfaceActive(ifaceRegexs, state)) return;
-
-            if (isIfaceAvailable(ifaceRegexs, state)) {
+            TetherState state = null;
+            while (true) {
                 state = pollAndAssertNoError(DEFAULT_TIMEOUT_MS);
+                if (state == null) fail("Do not receive active state change broadcast");
+
                 if (isIfaceActive(ifaceRegexs, state)) return;
+
+                if (!isIfaceAvailable(ifaceRegexs, state)) break;
             }
 
             fail("Tethering is not actived, available ifaces: " + state.mAvailable.toString()
@@ -175,16 +180,15 @@
         }
     }
 
-    private class OnStartTetheringCallback extends
-            ConnectivityManager.OnStartTetheringCallback {
+    private class StartTetheringCallback extends TetheringManager.StartTetheringCallback {
         @Override
         public void onTetheringStarted() {
             // Do nothing, TetherChangeReceiver will wait until it receives the broadcast.
         }
 
         @Override
-        public void onTetheringFailed() {
-            fail("startTethering fail");
+        public void onTetheringFailed(final int resultCode) {
+            fail("startTethering fail: " + resultCode);
         }
     }
 
@@ -206,18 +210,19 @@
 
     @Test
     public void testStartTetheringWithStateChangeBroadcast() throws Exception {
-        if (!mCM.isTetheringSupported()) return;
+        if (!mTM.isTetheringSupported()) return;
 
-        final String[] wifiRegexs = mCM.getTetherableWifiRegexs();
+        final String[] wifiRegexs = mTM.getTetherableWifiRegexs();
         if (wifiRegexs.length == 0) return;
 
         mTetherChangeReceiver.expectNoActiveTethering(0 /** timeout */);
 
-        final OnStartTetheringCallback startTetheringCallback = new OnStartTetheringCallback();
-        mCM.startTethering(ConnectivityManager.TETHERING_WIFI, true, startTetheringCallback);
+        final StartTetheringCallback startTetheringCallback = new StartTetheringCallback();
+        mTM.startTethering(new TetheringRequest.Builder(TETHERING_WIFI).build(), c -> c.run(),
+                startTetheringCallback);
         mTetherChangeReceiver.expectActiveTethering(wifiRegexs);
 
-        mCM.stopTethering(ConnectivityManager.TETHERING_WIFI);
+        mTM.stopTethering(TETHERING_WIFI);
         mTetherChangeReceiver.expectNoActiveTethering(DEFAULT_TIMEOUT_MS);
     }
 }
diff --git a/tests/tests/util/AndroidManifest.xml b/tests/tests/util/AndroidManifest.xml
index 77ab380..3d402d5 100644
--- a/tests/tests/util/AndroidManifest.xml
+++ b/tests/tests/util/AndroidManifest.xml
@@ -18,6 +18,12 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="android.util.cts">
 
+    <queries>
+        <package android:name="com.android.cts.install.lib.testapp.A" />
+        <package android:name="com.android.cts.install.lib.testapp.B" />
+        <package android:name="com.android.cts.install.lib.testapp.C" />
+    </queries>
+
     <uses-permission android:name="android.permission.DISABLE_KEYGUARD" />
     <uses-permission android:name="android.permission.READ_LOGS" />
     <application>
diff --git a/tests/tests/view/src/android/view/cts/PixelCopyTest.java b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
index 85c4094..51288cf 100644
--- a/tests/tests/view/src/android/view/cts/PixelCopyTest.java
+++ b/tests/tests/view/src/android/view/cts/PixelCopyTest.java
@@ -796,12 +796,12 @@
         assertBitmapNotColor("Left edge", bitmap, edgeColor, 2, bitmap.getHeight() / 2);
 
         assertBitmapColor("Bottom edge", bitmap, edgeColor,
-                bitmap.getWidth() / 2, bitmap.getHeight() - 2);
+                bitmap.getWidth() / 2, bitmap.getHeight() - 1);
         assertBitmapNotColor("Bottom edge", bitmap, edgeColor,
                 bitmap.getWidth() / 2, bitmap.getHeight() - 3);
 
         assertBitmapColor("Right edge", bitmap, edgeColor,
-                bitmap.getWidth() - 2, bitmap.getHeight() / 2);
+                bitmap.getWidth() - 1, bitmap.getHeight() / 2);
         assertBitmapNotColor("Right edge", bitmap, edgeColor,
                 bitmap.getWidth() - 3, bitmap.getHeight() / 2);
     }
diff --git a/tests/tests/widget/src/android/widget/cts/TextViewTest.java b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
index 86e674e..66f1cb3 100644
--- a/tests/tests/widget/src/android/widget/cts/TextViewTest.java
+++ b/tests/tests/widget/src/android/widget/cts/TextViewTest.java
@@ -2928,7 +2928,16 @@
         mInstrumentation.waitForIdleSync();
         assertTrue(mTextView.isFocused());
 
-        // Tab should
+        // Tab should not cause focus to leave the multiline textfield.
+        CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_TAB);
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.isFocused());
+
+        // Tab on the singleline TextView should.
+        mActivityRule.runOnUiThread(() -> {
+            mTextView.setSingleLine(true);
+        });
+        mInstrumentation.waitForIdleSync();
         CtsKeyEventUtil.sendKeyDownUp(mInstrumentation, mTextView, KeyEvent.KEYCODE_TAB);
         mInstrumentation.waitForIdleSync();
         assertFalse(mTextView.isFocused());