Snap for 11041982 from 512064335e2d6c9231f1de0264b1b71a6e74a7ab to mainline-uwb-release

Change-Id: I19d202e903dfdb1c13e10ebf98224cc120dac252
diff --git a/build/tasks/continuous_instrumentation_tests.mk b/build/tasks/continuous_instrumentation_tests.mk
index 1674d08..34050a4 100644
--- a/build/tasks/continuous_instrumentation_tests.mk
+++ b/build/tasks/continuous_instrumentation_tests.mk
@@ -52,7 +52,7 @@
 $(api_xml) : $(api_text) $(APICHECK)
 	$(hide) echo "Converting API file to XML: $@"
 	$(hide) mkdir -p $(dir $@)
-	$(hide) $(APICHECK_COMMAND) -convert2xml $< $@
+	$(hide) $(APICHECK_COMMAND) signature-to-jdiff --strip $< $@
 
 # CTS API coverage tool
 api_coverage_exe := $(HOST_OUT_EXECUTABLES)/cts-api-coverage
diff --git a/libraries/app-helpers/core/src/android/platform/helpers/HelperAccessor2.java b/libraries/app-helpers/core/src/android/platform/helpers/HelperAccessor2.java
new file mode 100644
index 0000000..f9abfbb
--- /dev/null
+++ b/libraries/app-helpers/core/src/android/platform/helpers/HelperAccessor2.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.platform.helpers;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+/**
+ * @param <T> the helper interface under test.
+ *     <p>A {@code HelperAccessor} can be included in any test to access an App Helper
+ *     implementation.
+ *     <p>For example: <code>
+ *     {@code HelperAccessor<IXHelper> accessor = new HelperAccessor(IXHelper.class);}
+ *     accessor.get().performSomeAction();
+ * </code> To target a specific helper implementation by prefix, build this object and call, <code>
+ * withPrefix</code> on it.
+ */
+public class HelperAccessor2<T extends IAppHelper2> {
+    private final Class<T> mInterfaceClass;
+
+    private T mHelper;
+    private String mPrefix;
+
+    public HelperAccessor2(Class<T> klass) {
+        mInterfaceClass = klass;
+    }
+
+    /** Selects only helpers that begin with the prefix, {@code prefix}. */
+    public HelperAccessor2<T> withPrefix(String prefix) {
+        mPrefix = prefix;
+        // Unset the helper, in case this was changed after first use.
+        mHelper = null;
+        // Return self to follow a pseudo-builder initialization pattern.
+        return this;
+    }
+
+    /** accessor.get().performSomeAction() {@code}. */
+    public T get() {
+        if (mHelper == null) {
+            if (mPrefix == null || mPrefix.isEmpty()) {
+                mHelper =
+                        HelperManager.getInstance(
+                                        InstrumentationRegistry.getInstrumentation().getContext(),
+                                        InstrumentationRegistry.getInstrumentation())
+                                .get(mInterfaceClass);
+            } else {
+                mHelper =
+                        HelperManager.getInstance(
+                                        InstrumentationRegistry.getInstrumentation().getContext(),
+                                        InstrumentationRegistry.getInstrumentation())
+                                .get(mInterfaceClass, mPrefix);
+            }
+        }
+        return mHelper;
+    }
+}
diff --git a/libraries/app-helpers/interfaces/Android.bp b/libraries/app-helpers/interfaces/Android.bp
index 05ca4aa..9c6c1a4 100644
--- a/libraries/app-helpers/interfaces/Android.bp
+++ b/libraries/app-helpers/interfaces/Android.bp
@@ -58,6 +58,7 @@
     libs: [
         "ub-uiautomator",
         "app-helpers-core",
+        "androidx.test.uiautomator_uiautomator",
     ],
     static_libs: [
         "app-helpers-common-interfaces",
diff --git a/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IChromeHelper2.java b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IChromeHelper2.java
new file mode 100644
index 0000000..cfafe41
--- /dev/null
+++ b/libraries/app-helpers/interfaces/handheld/src/android/platform/helpers/IChromeHelper2.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.platform.helpers;
+
+import androidx.test.uiautomator.Direction;
+import androidx.test.uiautomator.UiObject2;
+
+/** {@inheritDoc} */
+public interface IChromeHelper2 extends IAppHelper2 {
+    enum MenuItem {
+        BOOKMARKS("Bookmarks"),
+        NEW_TAB("New tab"),
+        CLOSE_ALL_TABS("Close all tabs"),
+        DOWNLOADS("Downloads"),
+        HISTORY("History"),
+        SETTINGS("Settings");
+
+        private final String mDisplayName;
+
+        MenuItem(String displayName) {
+            mDisplayName = displayName;
+        }
+
+        @Override
+        public String toString() {
+            return mDisplayName;
+        }
+    }
+
+    enum ClearRange {
+        PAST_HOUR("past hour"),
+        PAST_DAY("past day"),
+        PAST_WEEK("past week"),
+        LAST_4_WEEKS("last 4 weeks"),
+        BEGINNING_OF_TIME("beginning of time");
+
+        private final String mDisplayName;
+
+        ClearRange(String displayName) {
+            mDisplayName = displayName;
+        }
+
+        @Override
+        public String toString() {
+            return mDisplayName;
+        }
+    }
+
+    /**
+     * Setup expectations: Chrome is open and on a standard page, i.e. a tab is open.
+     *
+     * <p>This method will open the URL supplied and block until the page is open.
+     */
+    void openUrl(String url);
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will scroll the page as directed and block until idle.
+     */
+    void flingPage(Direction dir);
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will open the overload menu, indicated by three dots and block until open.
+     */
+    void openMenu();
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will open provided item in the menu.
+     */
+    void openMenuItem(IChromeHelper2.MenuItem menuItem);
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will open provided item in the menu.
+     *
+     * @param menuItem The name of menu item.
+     * @param waitForPageLoad Wait for the page to load completely or not.
+     */
+    default void openMenuItem(IChromeHelper2.MenuItem menuItem, boolean waitForPageLoad) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will add a new tab and land on the webpage of given url.
+     */
+    void addNewTab(String url);
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will go to tab switcher by clicking tab switcher button.
+     */
+    void openTabSwitcher();
+
+    /**
+     * Setup expectations: Chrome is open on a page or in tab switcher.
+     *
+     * <p>This method will switch to the tab at tabIndex.
+     */
+    void switchTab(int tabIndex);
+
+    /**
+     * Setup expectations: Chrome has at least one tab.
+     *
+     * <p>This method will close all tabs.
+     */
+    void closeAllTabs();
+
+    /**
+     * Setup expectations: Chrome is open on a page and the tabs are treated as apps.
+     *
+     * <p>This method will change the settings to treat tabs inside of Chrome and block until Chrome
+     * is open on the original tab.
+     */
+    void mergeTabs();
+
+    /**
+     * Setup expectations: Chrome is open on a page and the tabs are merged.
+     *
+     * <p>This method will change the settings to treat tabs outside of Chrome and block until
+     * Chrome is open on the original tab.
+     */
+    void unmergeTabs();
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will reload the page by clicking the refresh button, and block until the page
+     * is reopened.
+     */
+    void reloadPage();
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will stop loading page then reload the page by clicking the refresh button,
+     * and block until the page is reopened.
+     */
+    default void stopAndReloadPage() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will stop loading page then reload the page by clicking the refresh button,
+     *
+     * @param waitForPageLoad Wait for the page to load completely or not.
+     */
+    default void stopAndReloadPage(boolean waitForPageLoad) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method is getter for contentDescription of Tab elements.
+     */
+    String getTabDescription();
+
+    /**
+     * Setup expectations: Chrome is open on a History page.
+     *
+     * <p>This method clears browser history for provided period of time.
+     */
+    void clearBrowsingData(IChromeHelper2.ClearRange range);
+
+    /**
+     * Setup expectations: Chrome is open on a Downloads page.
+     *
+     * <p>This method checks header is displayed on Downloads page.
+     */
+    void checkIfDownloadsOpened();
+
+    /**
+     * Setup expectations: Chrome is open on a Settings page.
+     *
+     * <p>This method clicks on Privacy setting on Settings page.
+     */
+    void openPrivacySettings();
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>This method will add the current page to Bookmarks
+     */
+    default boolean addCurrentPageToBookmark() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a Bookmarks page.
+     *
+     * <p>This method selects a bookmark from the Bookmarks page.
+     *
+     * @param index The Index of bookmark to select.
+     */
+    default void openBookmark(int index) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a Bookmarks page.
+     *
+     * <p>This method selects a bookmark from the Bookmarks page.
+     *
+     * @param bookmarkName The string of the target bookmark to select.
+     * @param waitForPageLoad Wait for the page to load completely or not.
+     */
+    default void openBookmark(String bookmarkName, boolean waitForPageLoad) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>Selects the link with specific text.
+     *
+     * @param linkText The text of the link to select.
+     */
+    default void selectLink(String linkText) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>Performs a scroll gesture on the page.
+     *
+     * @param dir The direction on the page to scroll.
+     * @param percent The distance to scroll as a percentage of the page's visible size.
+     */
+    default void scrollPage(Direction dir, float percent) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectations: Chrome is open on a page.
+     *
+     * <p>Get the UiObject2 of the page screen.
+     */
+    default UiObject2 getWebPage() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectation: Chrome was loading a web page.
+     *
+     * <p>Returns a boolean to state if current page is loaded.
+     */
+    default boolean isWebPageLoaded() {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+
+    /**
+     * Setup expectation: Chrome was loading a web page.
+     *
+     * <p>Checks number of active tabs.
+     */
+    default void tabsCount(int number) {
+        throw new UnsupportedOperationException("Not yet implemented.");
+    }
+}
diff --git a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/LogcatInspector.java b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/LogcatInspector.java
index bd7b00c..997f62e 100644
--- a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/LogcatInspector.java
+++ b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/LogcatInspector.java
@@ -96,17 +96,34 @@
             throws InterruptedException, IOException {
         long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(timeInSeconds);
         int stringIndex = 0;
+        long lastEpochMicroseconds = 0;
         while (timeout >= System.currentTimeMillis()) {
-            stringIndex = 0;
-            InputStream logcatStream = executeShellCommand("logcat -v brief -d " + filterSpec);
+            // '-v epoch' -> Displays time as seconds since Jan 1 1970.
+            // '-v usec' -> Displays time down the microsecond precision.
+            InputStream logcatStream =
+                    executeShellCommand("logcat -v epoch -v usec -d " + filterSpec);
             BufferedReader logcat = new BufferedReader(new InputStreamReader(logcatStream));
             String line;
             while ((line = logcat.readLine()) != null) {
                 if (line.contains(logcatStrings[stringIndex])) {
-                    stringIndex++;
-                    if (stringIndex >= logcatStrings.length) {
-                        StreamUtil.drainAndClose(logcat);
-                        return stringIndex;
+                    // Now we need to get the timestamp of this log line to ensure that
+                    // this log is after the previously matched log.
+
+                    // Strip the leading spaces and split the line by spaces
+                    String[] splitLine = line.stripLeading().split(" ");
+
+                    // The first one is epoch time in seconds, with microsecond precision.
+                    // It is of the format <epoch time in seconds>.xxxxxx
+                    String epochMicrosecondsStr = splitLine[0].replace(".", "");
+                    long epochMicroseconds = Long.parseLong(epochMicrosecondsStr);
+
+                    // Check that this log time is after previously matched log
+                    if (epochMicroseconds >= lastEpochMicroseconds) {
+                        stringIndex++;
+                        if (stringIndex >= logcatStrings.length) {
+                            StreamUtil.drainAndClose(logcat);
+                            return stringIndex;
+                        }
                     }
                 }
             }
diff --git a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/OWNERS b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/OWNERS
index be00f2c..e81b71f 100644
--- a/libraries/compatibility-common-util/src/com/android/compatibility/common/util/OWNERS
+++ b/libraries/compatibility-common-util/src/com/android/compatibility/common/util/OWNERS
@@ -1,2 +1,6 @@
 per-file ReasonType.java = set noparent
-per-file ReasonType.java = ape-relpgm-cls@google.com
\ No newline at end of file
+per-file ReasonType.java = ape-relpgm-cls@google.com
+per-file BackupUtils.java = set noparent
+per-file BackupUtils.java = file:platform/frameworks/base:/services/backup/OWNERS
+per-file LogcatInspector.java = set noparent
+per-file LogcatInspector.java = file:platform/frameworks/base:/services/backup/OWNERS
\ No newline at end of file
diff --git a/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/OWNERS b/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/OWNERS
new file mode 100644
index 0000000..34a5022
--- /dev/null
+++ b/libraries/compatibility-common-util/tests/src/com/android/compatibility/common/util/OWNERS
@@ -0,0 +1,2 @@
+per-file BackupUtilsTest.java = set noparent
+per-file BackupUtilsTest.java = file:platform/frameworks/base:/services/backup/OWNERS
\ No newline at end of file
diff --git a/libraries/sts-common-util/host-side/tests/src/com/android/sts/common/MallocDebugTest.java b/libraries/sts-common-util/host-side/tests/src/com/android/sts/common/MallocDebugTest.java
index 99faf82..f82a907 100644
--- a/libraries/sts-common-util/host-side/tests/src/com/android/sts/common/MallocDebugTest.java
+++ b/libraries/sts-common-util/host-side/tests/src/com/android/sts/common/MallocDebugTest.java
@@ -24,6 +24,8 @@
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
 import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test;
 
+import org.junit.After;
+import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -50,6 +52,26 @@
         }
     }
 
+    @Before
+    public void setUp() throws Exception {
+        assertWithMessage("libc.debug.malloc.options not empty before test")
+                .that(getDevice().getProperty("libc.debug.malloc.options"))
+                .isNull();
+        assertWithMessage("libc.debug.malloc.programs not empty before test")
+                .that(getDevice().getProperty("libc.debug.malloc.programs"))
+                .isNull();
+    }
+
+    @After
+    public void tearDown() throws Exception {
+        assertWithMessage("libc.debug.malloc.options not empty after test")
+                .that(getDevice().getProperty("libc.debug.malloc.options"))
+                .isNull();
+        assertWithMessage("libc.debug.malloc.programs not empty after test")
+                .that(getDevice().getProperty("libc.debug.malloc.programs"))
+                .isNull();
+    }
+
     @Test(expected = Test.None.class /* no exception expected */)
     public void testMallocDebugNoErrors() throws Exception {
         MallocDebug.assertNoMallocDebugErrors(logcatWithoutErrors);
@@ -99,7 +121,7 @@
         final String oldValue = "TEST_VALUE_OLD";
         final String newValue = "TEST_VALUE_NEW";
         assertTrue(
-                "could not set property",
+                "could not set libc.debug.malloc.options",
                 getDevice().setProperty("libc.debug.malloc.options", oldValue));
         assertWithMessage("test property was not properly set on device")
                 .that(getDevice().getProperty("libc.debug.malloc.options"))
@@ -110,8 +132,12 @@
                     .that(getDevice().getProperty("libc.debug.malloc.options"))
                     .isEqualTo(newValue);
         }
+        String afterValue = getDevice().getProperty("libc.debug.malloc.options");
+        assertTrue(
+                "could not clear libc.debug.malloc.options",
+                getDevice().setProperty("libc.debug.malloc.options", ""));
         assertWithMessage("prior property was not restored after test")
-                .that(getDevice().getProperty("libc.debug.malloc.options"))
+                .that(afterValue)
                 .isEqualTo(oldValue);
     }
 }
diff --git a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToExistingSecondaryUser.java b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToExistingSecondaryUser.java
index 2f34e2e..3aa6efd 100644
--- a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToExistingSecondaryUser.java
+++ b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToExistingSecondaryUser.java
@@ -18,12 +18,14 @@
 
 import android.app.UiAutomation;
 import android.content.pm.UserInfo;
+import android.os.Build;
 import android.os.SystemClock;
 import android.platform.helpers.MultiUserHelper;
 import android.platform.test.scenario.annotation.Scenario;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,8 +51,13 @@
         /*
         TODO: Create setup util API
          */
+        // Execute these tests only on devices running Android T or higher
+        Assume.assumeTrue(
+                "Skipping below Android T", Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU);
+
         // Execute user manager APIs with elevated permissions
         mUiAutomation = getUiAutomation();
+        // TODO: b/302175460 - update minimum SDK version
         mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
 
         UserInfo targetUser = mMultiUserHelper
diff --git a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewGuest.java b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewGuest.java
index 6f8d2ed..00897de 100644
--- a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewGuest.java
+++ b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewGuest.java
@@ -18,12 +18,14 @@
 
 import android.app.UiAutomation;
 import android.content.pm.UserInfo;
+import android.os.Build;
 import android.os.SystemClock;
 import android.platform.helpers.MultiUserHelper;
 import android.platform.test.scenario.annotation.Scenario;
 
 import androidx.test.platform.app.InstrumentationRegistry;
 
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -49,8 +51,13 @@
         /*
         TODO: Create setup util API
          */
+        // Execute these tests only on devices running Android T or higher
+        Assume.assumeTrue(
+                "Skipping below Android T", Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU);
+
         // Execute user manager APIs with elevated permissions
         mUiAutomation = getUiAutomation();
+        // TODO: b/302175460 - update minimum SDK version
         mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
         UserInfo currentUser = mMultiUserHelper.getCurrentForegroundUserInfo();
 
diff --git a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewSecondaryUser.java b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewSecondaryUser.java
index 8bfb20d..4feedec 100644
--- a/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewSecondaryUser.java
+++ b/tests/automotive/health/multiuser/src/android/platform/scenario/multiuser/nonui/SwitchToNewSecondaryUser.java
@@ -16,10 +16,16 @@
 
 package android.platform.scenario.multiuser;
 
+import android.app.UiAutomation;
 import android.content.pm.UserInfo;
+import android.os.Build;
 import android.os.SystemClock;
 import android.platform.helpers.MultiUserHelper;
 import android.platform.test.scenario.annotation.Scenario;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Assume;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -37,20 +43,44 @@
 
     private final MultiUserHelper mMultiUserHelper = MultiUserHelper.getInstance();
     private int mTargetUserId;
+    private UiAutomation mUiAutomation = null;
+    private static final String CREATE_USERS_PERMISSION = "android.permission.CREATE_USERS";
 
     @Before
     public void setup() throws Exception {
-    /*
-    TODO(b/194536236): Refactor setup code in multiuser nonui tests and create setup util API instead
-     */
+        /*
+        TODO(b/194536236): Refactor setup code in multiuser nonui tests
+         * and create setup util API instead
+         */
+        // Execute these tests only on devices running Android T or higher
+        Assume.assumeTrue(
+                "Skipping below Android T", Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU);
+
+        // Execute user manager APIs with elevated permissions
+        mUiAutomation = getUiAutomation();
+        // TODO: b/302175460 - update minimum SDK version
+        mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
         UserInfo currentUser = mMultiUserHelper.getCurrentForegroundUserInfo();
+
+        // Drop elevated permissions
+        mUiAutomation.dropShellPermissionIdentity();
+
         if (currentUser.id != MultiUserConstants.DEFAULT_INITIAL_USER) {
             SystemClock.sleep(MultiUserConstants.WAIT_FOR_IDLE_TIME_MS);
+
+            // Execute user manager APIs with elevated permissions
+            mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
             mMultiUserHelper.switchAndWaitForStable(
                 MultiUserConstants.DEFAULT_INITIAL_USER, MultiUserConstants.WAIT_FOR_IDLE_TIME_MS);
+
+            // Drop elevated permissions
+            mUiAutomation.dropShellPermissionIdentity();
         }
+        // Execute user manager APIs with elevated permissions
+        mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
         UserInfo targetUser = mMultiUserHelper
             .getUserByName(MultiUserConstants.SECONDARY_USER_NAME);
+
         if (targetUser != null) {
             if (!mMultiUserHelper.removeUser(targetUser)) {
                 throw new Exception("Failed to remove user: " + targetUser.id);
@@ -60,14 +90,27 @@
             mTargetUserId = mMultiUserHelper
                 .createUser(MultiUserConstants.SECONDARY_USER_NAME, false);
         }
+
+        // Drop elevated permissions
+        mUiAutomation.dropShellPermissionIdentity();
     }
 
     @Test
     public void testSwitch() throws Exception {
+        // Execute user manager APIs with elevated permissions
+        mUiAutomation = getUiAutomation();
+        mUiAutomation.adoptShellPermissionIdentity(CREATE_USERS_PERMISSION);
         if (MultiUserConstants.INCLUDE_CREATION_TIME) {
             mTargetUserId = mMultiUserHelper
                 .createUser(MultiUserConstants.SECONDARY_USER_NAME, false);
         }
         mMultiUserHelper.switchToUserId(mTargetUserId);
+
+        // Drop elevated permissions
+        mUiAutomation.dropShellPermissionIdentity();
+    }
+
+    private UiAutomation getUiAutomation() {
+        return InstrumentationRegistry.getInstrumentation().getUiAutomation();
     }
 }
diff --git a/tests/automotive/health/multiuser/tests/AndroidTest.xml b/tests/automotive/health/multiuser/tests/AndroidTest.xml
new file mode 100644
index 0000000..8fb13db
--- /dev/null
+++ b/tests/automotive/health/multiuser/tests/AndroidTest.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<configuration description="Runs Android Automotive Multiuser Scenario-Based Tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="AndroidAutomotiveMultiuserScenarioTests.apk" />
+    </target_preparer>
+
+    <!-- Switch to User 0 and wait for a some time (milliseconds) until system idle -->
+    <target_preparer class="com.android.tradefed.targetprep.SwitchUserTargetPreparer" >
+      <option name="user-type" value="SYSTEM" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="android.platform.scenario.multiuser" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+    </test>
+</configuration>