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>