Merge "Skip attestation test for first_api_level <=26" into sc-v2-dev
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
index 505ace2..7ee0ed13 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/CommandReceiverActivity.java
@@ -206,7 +206,7 @@
mAm = getSystemService(ActivityManager.class);
mAdmin = DeviceAdminTestReceiver.getReceiverComponentName();
final String command = intent.getStringExtra(EXTRA_COMMAND);
- Log.i(TAG, "Command: " + command);
+ Log.i(TAG, "Command: " + command + " forDeviceOwner: " + forDeviceOwner);
switch (command) {
case COMMAND_SET_USER_RESTRICTION: {
String restrictionKey = intent.getStringExtra(EXTRA_USER_RESTRICTION);
@@ -380,6 +380,7 @@
uninstallHelperPackage();
} break;
case COMMAND_SET_PERMISSION_GRANT_STATE: {
+ Log.d(TAG, "Granting permission using " + mDpm);
mDpm.setPermissionGrantState(mAdmin, getPackageName(),
intent.getStringExtra(EXTRA_PERMISSION),
intent.getIntExtra(EXTRA_GRANT_STATE,
@@ -483,16 +484,22 @@
mDpm.setMaximumFailedPasswordsForWipe(mAdmin, 0);
} break;
case COMMAND_SET_DEFAULT_IME: {
- if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+ if (!mDpm.isDeviceOwnerApp(getPackageName())
+ && !UserManager.isHeadlessSystemUserMode()) {
return;
}
+ Log.d(TAG, "Setting " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+ + mDpm);
mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD,
getPackageName());
} break;
case COMMAND_CLEAR_DEFAULT_IME: {
- if (!mDpm.isDeviceOwnerApp(getPackageName())) {
+ if (!mDpm.isDeviceOwnerApp(getPackageName())
+ && !UserManager.isHeadlessSystemUserMode()) {
return;
}
+ Log.d(TAG, "Clearing " + Settings.Secure.DEFAULT_INPUT_METHOD + " using "
+ + mDpm);
mDpm.setSecureSetting(mAdmin, Settings.Secure.DEFAULT_INPUT_METHOD, null);
} break;
case COMMAND_CREATE_MANAGED_USER:{
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
index 5e8a92f..577a6c8 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/EnterprisePrivacyTestListActivity.java
@@ -16,11 +16,11 @@
package com.android.cts.verifier.managedprovisioning;
+import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
+
import android.Manifest;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.database.DataSetObserver;
import android.os.Bundle;
import android.provider.Settings;
@@ -31,8 +31,6 @@
import com.android.cts.verifier.R;
import com.android.cts.verifier.TestListAdapter.TestListItem;
-import static com.android.cts.verifier.managedprovisioning.Utils.createInteractiveTestItem;
-
/**
* Test class to verify privacy information is shown for devices managed by a Device Owner.
*/
@@ -92,6 +90,12 @@
.putExtra(CommandReceiverActivity.EXTRA_COMMAND, command);
}
+ private Intent buildCommandIntentForCurrentUser(String command) {
+ return buildCommandIntent(command)
+ .putExtra(CommandReceiverActivity.EXTRA_USE_CURRENT_USER_DPM, true);
+ }
+
+
private TestListItem buildCommandTest(String id, int titleRes, int infoRes,
int commandButtonRes, String command) {
return createInteractiveTestItem(this, id, titleRes, infoRes,
@@ -105,12 +109,14 @@
String permission) {
return createInteractiveTestItem(this, id, titleRes, infoRes,
new ButtonInfo[] {
- new ButtonInfo(R.string.enterprise_privacy_reset, buildCommandIntent(
+ new ButtonInfo(R.string.enterprise_privacy_reset,
+ buildCommandIntentForCurrentUser(
CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
.putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
.putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT)),
- new ButtonInfo(R.string.enterprise_privacy_grant, buildCommandIntent(
+ new ButtonInfo(R.string.enterprise_privacy_grant,
+ buildCommandIntentForCurrentUser(
CommandReceiverActivity.COMMAND_SET_PERMISSION_GRANT_STATE)
.putExtra(CommandReceiverActivity.EXTRA_PERMISSION, permission)
.putExtra(CommandReceiverActivity.EXTRA_GRANT_STATE,
@@ -182,11 +188,12 @@
new ButtonInfo(R.string.enterprise_privacy_open_settings,
new Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS)),
new ButtonInfo(R.string.enterprise_privacy_set_keyboard,
- buildCommandIntent(CommandReceiverActivity
- .COMMAND_SET_DEFAULT_IME)),
+ buildCommandIntentForCurrentUser(
+ CommandReceiverActivity.COMMAND_SET_DEFAULT_IME)),
new ButtonInfo(R.string.enterprise_privacy_finish,
- buildCommandIntent(CommandReceiverActivity
- .COMMAND_CLEAR_DEFAULT_IME))}));
+ buildCommandIntentForCurrentUser(
+ CommandReceiverActivity.COMMAND_CLEAR_DEFAULT_IME))
+ }));
adapter.add(createInteractiveTestItem(this, ENTERPRISE_PRIVACY_ALWAYS_ON_VPN,
R.string.enterprise_privacy_always_on_vpn,
R.string.enterprise_privacy_always_on_vpn_info,
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
index 6d43808..7ffabbe 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/BedsteadJUnit4.java
@@ -16,7 +16,10 @@
package com.android.bedstead.harrier;
+import android.os.Bundle;
+
import androidx.annotation.Nullable;
+import androidx.test.platform.app.InstrumentationRegistry;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
@@ -72,18 +75,23 @@
return getAnnotationWeight(a) - getAnnotationWeight(b);
}
- private static int getAnnotationWeight(Annotation a) {
- if (!a.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
+ private static int getAnnotationWeight(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ // Special case, not important
+ return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
+ }
+
+ if (!annotation.annotationType().getPackage().getName().startsWith(BEDSTEAD_PACKAGE_NAME)) {
return AnnotationRunPrecedence.FIRST;
}
try {
- return (int) a.annotationType().getMethod("weight").invoke(a);
+ return (int) annotation.annotationType().getMethod("weight").invoke(annotation);
} catch (NoSuchMethodException e) {
// Default to PRECEDENCE_NOT_IMPORTANT if no weight is found on the annotation.
return AnnotationRunPrecedence.PRECEDENCE_NOT_IMPORTANT;
} catch (IllegalAccessException | InvocationTargetException e) {
- throw new NeneException("Failed to invoke weight on this annotation: " + a, e);
+ throw new NeneException("Failed to invoke weight on this annotation: " + annotation, e);
}
}
@@ -92,7 +100,7 @@
*/
public static final class BedsteadFrameworkMethod extends FrameworkMethod {
- private final Class<? extends Annotation> mParameterizedAnnotation;
+ private final Annotation mParameterizedAnnotation;
private final Map<Class<? extends Annotation>, Annotation> mAnnotationsMap =
new HashMap<>();
private Annotation[] mAnnotations;
@@ -103,8 +111,7 @@
public BedsteadFrameworkMethod(Method method, Annotation parameterizedAnnotation) {
super(method);
- this.mParameterizedAnnotation = (parameterizedAnnotation == null) ? null
- : parameterizedAnnotation.annotationType();
+ mParameterizedAnnotation = parameterizedAnnotation;
calculateAnnotations();
}
@@ -124,6 +131,9 @@
this.mAnnotations = annotations.toArray(new Annotation[0]);
for (Annotation annotation : annotations) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ continue; // don't return this
+ }
mAnnotationsMap.put(annotation.annotationType(), annotation);
}
}
@@ -133,7 +143,7 @@
if (mParameterizedAnnotation == null) {
return super.getName();
}
- return super.getName() + "[" + mParameterizedAnnotation.getSimpleName() + "]";
+ return super.getName() + "[" + getParameterName(mParameterizedAnnotation) + "]";
}
@Override
@@ -162,13 +172,20 @@
}
}
+ private static String getParameterName(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return ((DynamicParameterizedAnnotation) annotation).name();
+ }
+ return annotation.annotationType().getSimpleName();
+ }
+
/**
* Resolve annotations recursively.
*
* @param parameterizedAnnotation The class of the parameterized annotation to expand, if any
*/
public static void resolveRecursiveAnnotations(List<Annotation> annotations,
- @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+ @Nullable Annotation parameterizedAnnotation) {
int index = 0;
while (index < annotations.size()) {
Annotation annotation = annotations.get(index);
@@ -181,11 +198,34 @@
}
}
+ private static boolean isParameterizedAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return true;
+ }
+
+ return annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null;
+ }
+
+ private static Annotation[] getIndirectAnnotations(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return ((DynamicParameterizedAnnotation) annotation).annotations();
+ }
+ return annotation.annotationType().getAnnotations();
+ }
+
+ private static boolean isRepeatingAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ return annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null;
+ }
+
private static List<Annotation> getReplacementAnnotations(Annotation annotation,
- @Nullable Class<? extends Annotation> parameterizedAnnotation) {
+ @Nullable Annotation parameterizedAnnotation) {
List<Annotation> replacementAnnotations = new ArrayList<>();
- if (annotation.annotationType().getAnnotation(RepeatingAnnotation.class) != null) {
+ if (isRepeatingAnnotation(annotation)) {
try {
Annotation[] annotations =
(Annotation[]) annotation.annotationType()
@@ -197,14 +237,12 @@
}
}
- if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null
- && !annotation.annotationType().equals(parameterizedAnnotation)) {
+ if (isParameterizedAnnotation(annotation) && !annotation.equals(parameterizedAnnotation)) {
return replacementAnnotations;
}
- for (Annotation indirectAnnotation : annotation.annotationType().getAnnotations()) {
- String annotationPackage = indirectAnnotation.annotationType().getPackage().getName();
- if (shouldSkipAnnotation(annotationPackage)) {
+ for (Annotation indirectAnnotation : getIndirectAnnotations(annotation)) {
+ if (shouldSkipAnnotation(annotation)) {
continue;
}
@@ -212,12 +250,21 @@
indirectAnnotation, parameterizedAnnotation));
}
- replacementAnnotations.add(annotation);
+ if (!(annotation instanceof DynamicParameterizedAnnotation)) {
+ // We drop the fake annotation once it's replaced
+ replacementAnnotations.add(annotation);
+ }
return replacementAnnotations;
}
- private static boolean shouldSkipAnnotation(String annotationPackage) {
+ private static boolean shouldSkipAnnotation(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ String annotationPackage = annotation.annotationType().getPackage().getName();
+
for (String ignoredPackage : sIgnoredAnnotationPackages) {
if (ignoredPackage.endsWith(".*")) {
if (annotationPackage.startsWith(
@@ -236,6 +283,14 @@
super(testClass);
}
+ private boolean annotationShouldBeSkipped(Annotation annotation) {
+ if (annotation instanceof DynamicParameterizedAnnotation) {
+ return false;
+ }
+
+ return annotation.annotationType().equals(IncludeNone.class);
+ }
+
@Override
protected List<FrameworkMethod> computeTestMethods() {
TestClass testClass = getTestClass();
@@ -252,7 +307,7 @@
}
for (Annotation annotation : parameterizedAnnotations) {
- if (annotation.annotationType().equals(IncludeNone.class)) {
+ if (annotationShouldBeSkipped(annotation)) {
// Special case - does not generate a run
continue;
}
@@ -328,7 +383,7 @@
parseEnterpriseAnnotations(annotations);
for (Annotation annotation : annotations) {
- if (annotation.annotationType().getAnnotation(ParameterizedAnnotation.class) != null) {
+ if (isParameterizedAnnotation(annotation)) {
parameterizedAnnotations.add(annotation);
}
}
@@ -376,7 +431,7 @@
EnterprisePolicy enterprisePolicy =
policy.getAnnotation(EnterprisePolicy.class);
List<Annotation> replacementAnnotations =
- Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy);
+ Policy.cannotSetPolicyStates(policy.getName(), enterprisePolicy, ((CannotSetPolicyTest) annotation).includeDeviceAdminStates(), ((CannotSetPolicyTest) annotation).includeNonDeviceAdminStates());
replacementAnnotations.sort(BedsteadJUnit4::annotationSorter);
annotations.addAll(index, replacementAnnotations);
@@ -418,4 +473,17 @@
return rules;
}
+
+ /**
+ * True if the test is running in debug mode.
+ *
+ * <p>This will result in additional debugging information being added which would otherwise
+ * be dropped to improve test performance.
+ *
+ * <p>To enable this, pass the "bedstead-debug" instrumentation arg as "true"
+ */
+ public static boolean isDebug() {
+ Bundle arguments = InstrumentationRegistry.getArguments();
+ return Boolean.parseBoolean(arguments.getString("bedstead-debug", "false"));
+ }
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
index 9bfec32..bb0783c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DeviceState.java
@@ -60,6 +60,7 @@
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.harrier.annotations.RequireUserSupported;
import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
@@ -85,7 +86,11 @@
import com.android.bedstead.nene.utils.ShellCommand;
import com.android.bedstead.nene.utils.Tags;
import com.android.bedstead.nene.utils.Versions;
+import com.android.bedstead.remotedpc.RemoteDelegate;
import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
import com.android.eventlib.EventLogs;
@@ -346,6 +351,17 @@
continue;
}
+ if (annotation instanceof EnsureHasDelegate) {
+ EnsureHasDelegate ensureHasDelegateAnnotation =
+ (EnsureHasDelegate) annotation;
+ ensureHasDelegate(
+ ensureHasDelegateAnnotation.admin(),
+ Arrays.asList(ensureHasDelegateAnnotation.scopes()),
+ ensureHasDelegateAnnotation.isPrimary());
+ continue;
+ }
+
+
if (annotation instanceof EnsureHasDeviceOwner) {
EnsureHasDeviceOwner ensureHasDeviceOwnerAnnotation =
(EnsureHasDeviceOwner) annotation;
@@ -878,7 +894,7 @@
mProfiles = new HashMap<>();
private DevicePolicyController mDeviceOwner;
private Map<UserReference, DevicePolicyController> mProfileOwners = new HashMap<>();
- private DevicePolicyController mPrimaryDpc;
+ private RemotePolicyManager mPrimaryPolicyManager;
private final List<UserReference> mCreatedUsers = new ArrayList<>();
private final List<UserBuilder> mRemovedUsers = new ArrayList<>();
@@ -1291,9 +1307,11 @@
broadcastReceiver.unregisterQuietly();
}
mRegisteredBroadcastReceivers.clear();
- mPrimaryDpc = null;
+ mPrimaryPolicyManager = null;
}
+ private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
+
private void teardownShareableState() {
if (mOriginalSwitchedUser != null) {
if (!mOriginalSwitchedUser.exists()) {
@@ -1353,6 +1371,11 @@
}
mRemovedUsers.clear();
+
+ for (TestAppInstance installedTestApp : mInstalledTestApps) {
+ installedTestApp.uninstall();
+ }
+ mInstalledTestApps.clear();
}
private UserReference createProfile(
@@ -1394,16 +1417,64 @@
}
}
+ private void ensureHasDelegate(
+ EnsureHasDelegate.AdminType adminType, List<String> scopes, boolean isPrimary) {
+ RemotePolicyManager dpc = getDeviceAdmin(adminType);
+
+
+ boolean specifiesAdminType = adminType != EnsureHasDelegate.AdminType.PRIMARY;
+ boolean currentPrimaryPolicyManagerIsNotDelegator = mPrimaryPolicyManager != dpc;
+
+ if (isPrimary && mPrimaryPolicyManager != null
+ && (specifiesAdminType || currentPrimaryPolicyManagerIsNotDelegator)) {
+ throw new IllegalStateException(
+ "Only one DPC can be marked as primary per test (current primary is "
+ + mPrimaryPolicyManager + ")");
+ }
+
+ if (!dpc.user().equals(TestApis.users().instrumented())) {
+ // INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
+ ensureCanGetPermission(INTERACT_ACROSS_USERS_FULL);
+ }
+
+ ensureTestAppInstalled(RemoteDelegate.sTestApp, dpc.user());
+ RemoteDelegate delegate = new RemoteDelegate(RemoteDelegate.sTestApp, dpc().user());
+ dpc.devicePolicyManager().setDelegatedScopes(
+ dpc.componentName(), delegate.packageName(), scopes);
+
+ if (isPrimary) {
+ mPrimaryPolicyManager = delegate;
+ }
+ }
+
+ private RemotePolicyManager getDeviceAdmin(EnsureHasDelegate.AdminType adminType) {
+ switch (adminType) {
+ case DEVICE_OWNER:
+ return deviceOwner();
+ case PROFILE_OWNER:
+ return profileOwner();
+ case PRIMARY:
+ return dpc();
+ default:
+ throw new IllegalStateException("Unknown device admin type " + adminType);
+ }
+ }
+
+ private void ensureTestAppInstalled(TestApp testApp, UserReference user) {
+ mInstalledTestApps.add(testApp.install(user));
+ }
+
private void ensureHasDeviceOwner(FailureMode failureMode, boolean isPrimary,
Set<String> affiliationIds) {
// TODO(scottjonathan): Should support non-remotedpc device owner (default to remotedpc)
UserReference userReference = TestApis.users().system();
- if (isPrimary && mPrimaryDpc != null && !userReference.equals(mPrimaryDpc.user())) {
+ if (isPrimary && mPrimaryPolicyManager != null && !userReference.equals(
+ mPrimaryPolicyManager.user())) {
throw new IllegalStateException(
"Only one DPC can be marked as primary per test (current primary is "
- + mPrimaryDpc + ")");
+ + mPrimaryPolicyManager + ")");
}
if (!userReference.equals(TestApis.users().instrumented())) {
// INTERACT_ACROSS_USERS_FULL is required for RemoteDPC
@@ -1455,7 +1526,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mDeviceOwner;
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
}
RemoteDpc.forDevicePolicyController(mDeviceOwner)
@@ -1471,7 +1542,8 @@
private void ensureHasProfileOwner(
UserReference user, boolean isPrimary, Set<String> affiliationIds) {
- if (isPrimary && mPrimaryDpc != null && !user.equals(mPrimaryDpc.user())) {
+ if (isPrimary && mPrimaryPolicyManager != null
+ && !user.equals(mPrimaryPolicyManager.user())) {
throw new IllegalStateException("Only one DPC can be marked as primary per test");
}
@@ -1501,7 +1573,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mProfileOwners.get(user);
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
}
if (affiliationIds != null) {
@@ -1670,20 +1742,22 @@
}
/**
- * Get the most appropriate {@link RemoteDpc} instance for the device state.
+ * Get the most appropriate {@link RemotePolicyManager} instance for the device state.
*
* <p>This method should only be used by tests which are annotated with {@link PolicyTest}.
*
- * <p>If no DPC is set as the "primary" DPC for the device state, then this method will first
+ * <p>This may be a DPC, a delegate, or a normal app with or without given permissions.
+ *
+ * <p>If no policy manager is set as "primary" for the device state, then this method will first
* check for a profile owner in the current user, or else check for a device owner.
*
* <p>If no Harrier-managed profile owner or device owner exists, an exception will be thrown.
*
* <p>If the profile owner or device owner is not a RemoteDPC then an exception will be thrown.
*/
- public RemoteDpc dpc() {
- if (mPrimaryDpc != null) {
- return RemoteDpc.forDevicePolicyController(mPrimaryDpc);
+ public RemotePolicyManager dpc() {
+ if (mPrimaryPolicyManager != null) {
+ return mPrimaryPolicyManager;
}
if (mProfileOwners.containsKey(TestApis.users().instrumented())) {
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
new file mode 100644
index 0000000..15afb2b
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/DynamicParameterizedAnnotation.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier;
+
+import java.lang.annotation.Annotation;
+import java.util.Arrays;
+import java.util.Objects;
+
+/**
+ * A fake annotation used inside {@link Policy} and {@link BedsteadJUnit4} to inject
+ * new parameterizations.
+ */
+public final class DynamicParameterizedAnnotation implements Annotation {
+ private final String mName;
+ private final Annotation[] mAnnotations;
+
+ DynamicParameterizedAnnotation(String name, Annotation[] annotations) {
+ mName = name;
+ mAnnotations = annotations;
+ }
+
+ /** Get the parameterization name. */
+ public String name() {
+ return mName;
+ }
+
+ /** Get the annotations applied to the parameterization. */
+ public Annotation[] annotations() {
+ return mAnnotations;
+ }
+
+ @Override
+ public Class<? extends Annotation> annotationType() {
+ // This is special cased in BedsteadJUnit4 so will never be called
+ return null;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DynamicParameterizedAnnotation)) return false;
+ DynamicParameterizedAnnotation that = (DynamicParameterizedAnnotation) o;
+ return Objects.equals(mName, that.mName) && Arrays.equals(mAnnotations,
+ that.mAnnotations);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = Objects.hash(mName);
+ result = 31 * result + Arrays.hashCode(mAnnotations);
+ return result;
+ }
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
index c588ace..e01c8f1 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/Policy.java
@@ -16,6 +16,18 @@
package com.android.bedstead.harrier;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_BLOCK_UNINSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_SELECTION;
+import static android.app.admin.DevicePolicyManager.DELEGATION_ENABLE_SYSTEM_APP;
+import static android.app.admin.DevicePolicyManager.DELEGATION_INSTALL_EXISTING_PACKAGE;
+import static android.app.admin.DevicePolicyManager.DELEGATION_KEEP_UNINSTALLED_PACKAGES;
+import static android.app.admin.DevicePolicyManager.DELEGATION_NETWORK_LOGGING;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PACKAGE_ACCESS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
@@ -28,9 +40,11 @@
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_PARENT;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_UNAFFILIATED_OTHER_USERS;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DO_NOT_APPLY_TO_NEGATIVE_TESTS;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.NO;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
import com.android.bedstead.harrier.annotations.parameterized.IncludeNone;
import com.android.bedstead.harrier.annotations.parameterized.IncludeRunOnAffiliatedDeviceOwnerSecondaryUser;
@@ -47,21 +61,94 @@
import com.google.auto.value.AutoAnnotation;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
/**
* Utility class for enterprise policy tests.
*/
public final class Policy {
+ // Delegate scopes to be used for a "CannotSet" state. All delegate scopes except the ones which
+ // should allow use of the API will be granted
+ private static final ImmutableSet<String> ALL_DELEGATE_SCOPES = ImmutableSet.of(
+ DELEGATION_CERT_INSTALL,
+ DELEGATION_APP_RESTRICTIONS,
+ DELEGATION_BLOCK_UNINSTALL,
+ DELEGATION_PERMISSION_GRANT,
+ DELEGATION_PACKAGE_ACCESS,
+ DELEGATION_ENABLE_SYSTEM_APP,
+ DELEGATION_INSTALL_EXISTING_PACKAGE,
+ DELEGATION_KEEP_UNINSTALLED_PACKAGES,
+ DELEGATION_NETWORK_LOGGING,
+ DELEGATION_CERT_SELECTION,
+ DELEGATION_SECURITY_LOGGING
+ );
+
+ // This is a map containing all Include* annotations and the flags which lead to them
+ // This is not validated - every state must have a single APPLIED_BY annotation
+ private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ STATE_ANNOTATIONS =
+ ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnDeviceOwnerUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnDeviceOwnerUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, singleAnnotation(includeRunOnBackgroundDeviceOwnerUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnBackgroundDeviceOwnerUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnNonAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser()))
+ .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedDeviceOwnerSecondaryUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnUnaffiliatedProfileOwnerSecondaryUser(), /* isPrimary= */ true))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerPrimaryUser(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner(), /* isPrimary= */ true))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, singleAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnParentOfProfileOwnerWithNoDeviceOwner(), /* isPrimary= */ true))
+
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, singleAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS | CAN_BE_DELEGATED, generateDelegateAnnotation(includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile(), /* isPrimary= */ true))
+ .build();
+ // This must contain one key for every APPLIED_BY that is being used, and maps to the
+ // "default" for testing that DPC type
+ // in general this will be a state which runs on the same user as the dpc.
+ private static final ImmutableMap<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ DPC_STATE_ANNOTATIONS_BASE =
+ ImmutableMap.<Integer, Function<EnterprisePolicy, Set<Annotation>>>builder()
+ .put(APPLIED_BY_DEVICE_OWNER, (flags) -> hasFlag(flags.dpc(), APPLIED_BY_DEVICE_OWNER | APPLIES_IN_BACKGROUND) ? ImmutableSet.of(includeRunOnBackgroundDeviceOwnerUser()) : ImmutableSet.of(includeRunOnDeviceOwnerUser()))
+ .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, singleAnnotation(includeRunOnAffiliatedProfileOwnerSecondaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, singleAnnotation(includeRunOnProfileOwnerPrimaryUser()))
+ .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, singleAnnotation(includeRunOnProfileOwnerProfileWithNoDeviceOwner()))
+ .build();
+ private static final Map<Integer, Function<EnterprisePolicy, Set<Annotation>>>
+ DPC_STATE_ANNOTATIONS = DPC_STATE_ANNOTATIONS_BASE.entrySet().stream()
+ .collect(Collectors.toMap(Map.Entry::getKey, Policy::addGeneratedStates));
+ private static final int APPLIED_BY_FLAGS =
+ APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
+ | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
+ | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
+ | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
+ private static final Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>>
+ ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
+
private Policy() {
}
@@ -126,49 +213,42 @@
return new AutoAnnotation_Policy_includeRunOnBackgroundDeviceOwnerUser();
}
- // This is a map containing all Include* annotations and the flags which lead to them
- // This is not validated - every state must have a single APPLIED_BY annotation
- private static final ImmutableMap<Integer, Annotation> STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER, includeRunOnDeviceOwnerUser())
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND, includeRunOnBackgroundDeviceOwnerUser())
+ @AutoAnnotation
+ private static EnsureHasDelegate ensureHasDelegate(EnsureHasDelegate.AdminType admin,
+ String[] scopes, boolean isPrimary) {
+ return new AutoAnnotation_Policy_ensureHasDelegate(admin, scopes, isPrimary);
+ }
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnNonAffiliatedDeviceOwnerSecondaryUser())
- .put(APPLIED_BY_DEVICE_OWNER | APPLIES_TO_AFFILIATED_OTHER_USERS, includeRunOnAffiliatedDeviceOwnerSecondaryUser())
+ private static Function<EnterprisePolicy, Set<Annotation>> singleAnnotation(
+ Annotation annotation) {
+ return (i) -> ImmutableSet.of(annotation);
+ }
- .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER | APPLIES_TO_OWN_USER, includeRunOnUnaffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerPrimaryUser())
+ private static Function<EnterprisePolicy, Set<Annotation>> generateDelegateAnnotation(
+ Annotation annotation, boolean isPrimary) {
+ return (policy) -> {
+ Annotation[] existingAnnotations = annotation.annotationType().getAnnotations();
+ return Arrays.stream(policy.delegatedScopes())
+ .map(scope -> {
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope},
+ isPrimary);
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_OWN_USER, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_PARENT, includeRunOnParentOfProfileOwnerWithNoDeviceOwner())
+ return new DynamicParameterizedAnnotation(
+ annotation.annotationType().getSimpleName() + "Delegate:" + scope,
+ newAnnotations);
+ }).collect(Collectors.toSet());
+ };
+ }
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE | APPLIES_TO_UNAFFILIATED_OTHER_USERS, includeRunOnSecondaryUserInDifferentProfileGroupToProfileOwnerProfile())
- .build();
+ private static Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> calculateAnnotationsMap(
+ Map<Integer, Function<EnterprisePolicy, Set<Annotation>>> annotations) {
+ Map<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> b = new HashMap<>();
- // This must contain one key for every APPLIED_BY that is being used, and maps to the "default" for testing that DPC type
- // in general this will be a state which runs on the same user as the dpc.
- private static final ImmutableMap<Integer, Annotation> DPC_STATE_ANNOTATIONS = ImmutableMap.<Integer, Annotation>builder()
- .put(APPLIED_BY_DEVICE_OWNER, includeRunOnDeviceOwnerUser())
- .put(APPLIED_BY_AFFILIATED_PROFILE_OWNER, includeRunOnAffiliatedProfileOwnerSecondaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER, includeRunOnProfileOwnerPrimaryUser())
- .put(APPLIED_BY_PROFILE_OWNER_USER_WITH_NO_DO, includeRunOnProfileOwnerPrimaryUser())
- .put(APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE, includeRunOnProfileOwnerProfileWithNoDeviceOwner())
- .build();
-
- private static final int APPLIED_BY_FLAGS =
- APPLIED_BY_DEVICE_OWNER | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
- | APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE
- | APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_USER
- | APPLIED_BY_AFFILIATED_PROFILE_OWNER_USER;
-
-
- private static final Map<Annotation, Set<Integer>> ANNOTATIONS_MAP = calculateAnnotationsMap(STATE_ANNOTATIONS);
-
- private static Map<Annotation, Set<Integer>> calculateAnnotationsMap(
- Map<Integer, Annotation> annotations) {
- Map<Annotation, Set<Integer>> b = new HashMap<>();
-
- for (Map.Entry<Integer, Annotation> i : annotations.entrySet()) {
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> i :
+ annotations.entrySet()) {
if (!b.containsKey(i.getValue())) {
b.put(i.getValue(), new HashSet<>());
}
@@ -179,20 +259,39 @@
return b;
}
+ private static Function<EnterprisePolicy, Set<Annotation>> addGeneratedStates(
+ ImmutableMap.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> entry) {
+ return (policy) -> {
+ if (hasFlag(policy.dpc(), entry.getKey() | CAN_BE_DELEGATED)) {
+ Set<Annotation> results = new HashSet<>(entry.getValue().apply(policy));
+ results.addAll(results.stream().flatMap(
+ t -> generateDelegateAnnotation(t, /* isPrimary= */ true).apply(
+ policy).stream())
+ .collect(Collectors.toSet()));
+
+ return results;
+ }
+
+ return entry.getValue().apply(policy);
+ };
+ }
+
/**
- * Get positive state annotations for the given policy.
+ * Get parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is able to be applied.
*/
- public static List<Annotation> positiveStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> positiveStates(String policyName,
+ EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+ for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+ ANNOTATIONS_MAP.entrySet()) {
if (isPositive(enterprisePolicy.dpc(), annotation.getValue())) {
- annotations.add(annotation.getKey());
+ annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
@@ -215,13 +314,15 @@
private static boolean isNegative(int[] policyFlags, Set<Integer> annotationFlags) {
for (int annotationFlag : annotationFlags) {
- if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */ NO)) {
+ if (hasFlag(annotationFlag, DO_NOT_APPLY_TO_NEGATIVE_TESTS, /* nonMatchingFlag= */
+ NO)) {
return false; // We don't support using this annotation for negative tests
}
int appliedByFlag = APPLIED_BY_FLAGS & annotationFlag;
int otherFlags = annotationFlag ^ appliedByFlag; // remove the appliedByFlag
- if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */ otherFlags)) {
+ if (hasFlag(policyFlags, /* matchingFlag= */ appliedByFlag, /* nonMatchingFlag= */
+ otherFlags)) {
return true;
}
}
@@ -230,18 +331,20 @@
}
/**
- * Get negative state annotations for the given policy.
+ * Get negative parameterized test runs for the given policy.
*
* <p>These are states which should be run where the policy is not able to be applied.
*/
- public static List<Annotation> negativeStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> negativeStates(String policyName,
+ EnterprisePolicy enterprisePolicy) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- for (Map.Entry<Annotation, Set<Integer>> annotation : ANNOTATIONS_MAP.entrySet()) {
+ for (Map.Entry<Function<EnterprisePolicy, Set<Annotation>>, Set<Integer>> annotation :
+ ANNOTATIONS_MAP.entrySet()) {
if (isNegative(enterprisePolicy.dpc(), annotation.getValue())) {
- annotations.add(annotation.getKey());
+ annotations.addAll(annotation.getKey().apply(enterprisePolicy));
}
}
@@ -254,23 +357,60 @@
}
/**
- * Get state annotations where the policy cannot be set for the given policy.
+ * Get parameterized test runs where the policy cannot be set for the given policy.
*/
- public static List<Annotation> cannotSetPolicyStates(String policyName, EnterprisePolicy enterprisePolicy) {
+ public static List<Annotation> cannotSetPolicyStates(String policyName,
+ EnterprisePolicy enterprisePolicy, boolean includeDeviceAdminStates,
+ boolean includeNonDeviceAdminStates) {
Set<Annotation> annotations = new HashSet<>();
validateFlags(policyName, enterprisePolicy.dpc());
- // TODO(scottjonathan): Always include a state without a dpc
+ if (includeDeviceAdminStates) {
+ int allFlags = 0;
+ for (int p : enterprisePolicy.dpc()) {
+ allFlags = allFlags | p;
+ }
- int allFlags = 0;
- for (int p : enterprisePolicy.dpc()) {
- allFlags = allFlags | p;
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+ DPC_STATE_ANNOTATIONS.entrySet()) {
+ if ((appliedByFlag.getKey() & allFlags) == 0) {
+ annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
+ }
+ }
}
- for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
- if ((appliedByFlag.getKey() & allFlags) == 0) {
- annotations.add(appliedByFlag.getValue());
+ if (includeNonDeviceAdminStates) {
+ Set<String> validScopes = ImmutableSet.copyOf(enterprisePolicy.delegatedScopes());
+ String[] scopes = ALL_DELEGATE_SCOPES.stream()
+ .filter(i -> !validScopes.contains(i))
+ .toArray(String[]::new);
+ Annotation[] existingAnnotations = IncludeRunOnDeviceOwnerUser.class.getAnnotations();
+
+ if (BedsteadJUnit4.isDebug()) {
+ // Add a non-DPC with no delegate scopes
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{}, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithNoScopes", newAnnotations));
+
+ for (String scope : scopes) {
+ newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, new String[]{scope}, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithScope:" + scope, newAnnotations));
+ }
+ } else {
+ Annotation[] newAnnotations = Arrays.copyOf(existingAnnotations,
+ existingAnnotations.length + 1);
+ newAnnotations[newAnnotations.length - 1] = ensureHasDelegate(
+ EnsureHasDelegate.AdminType.PRIMARY, scopes, /* isPrimary= */ true);
+ annotations.add(
+ new DynamicParameterizedAnnotation("DelegateWithoutValidScope", newAnnotations));
}
}
@@ -296,9 +436,10 @@
allFlags = allFlags | p;
}
- for (Map.Entry<Integer, Annotation> appliedByFlag : DPC_STATE_ANNOTATIONS.entrySet()) {
+ for (Map.Entry<Integer, Function<EnterprisePolicy, Set<Annotation>>> appliedByFlag :
+ DPC_STATE_ANNOTATIONS.entrySet()) {
if ((appliedByFlag.getKey() & allFlags) == appliedByFlag.getKey()) {
- annotations.add(appliedByFlag.getValue());
+ annotations.addAll(appliedByFlag.getValue().apply(enterprisePolicy));
}
}
@@ -311,8 +452,14 @@
if (singleTestOnly) {
// We select one annotation in an arbitrary but deterministic way
- annotationList.sort(Comparator.comparing(a -> a.annotationType().getName()));
- Annotation firstAnnotation = annotationList.get(0);
+ annotationList.sort(Comparator.comparing(
+ a -> a instanceof DynamicParameterizedAnnotation
+ ? "DynamicParameterizedAnnotation" : a.annotationType().getName()));
+
+ // We don't want a delegate to be the representative test
+ Annotation firstAnnotation = annotationList.stream()
+ .filter(i -> !(i instanceof DynamicParameterizedAnnotation))
+ .findFirst().get();
annotationList.clear();
annotationList.add(firstAnnotation);
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
new file mode 100644
index 0000000..9521e88
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/SlowApiTest.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation to indicate that a test can take a long time to run.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface SlowApiTest {
+ String reason();
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
index 9315103..d0f1985 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/CannotSetPolicyTest.java
@@ -45,6 +45,17 @@
Class<?> policy();
/**
+ * If true, then this will run in states where the app is a device admin but is not one which is
+ * allowed to make the call.
+ */
+ boolean includeDeviceAdminStates() default true;
+
+ /**
+ * If true, then this will run in states where the app is not a device admin.
+ */
+ boolean includeNonDeviceAdminStates() default true;
+
+ /**
* Weight sets the order that annotations will be resolved.
*
* <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
new file mode 100644
index 0000000..73c1da7
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.annotations.enterprise;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
+
+import com.android.bedstead.harrier.DeviceState;
+import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test requires that the given admin delegates the given scope to a test app.
+ *
+ * <p>You should use {@link DeviceState} to ensure that the device enters
+ * the correct state for the method. You can use {@link DeviceState#delegate()} to interact with
+ * the delegate.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureHasDelegate {
+
+ enum AdminType {
+ DEVICE_OWNER,
+ PROFILE_OWNER,
+ PRIMARY
+ }
+
+ /**
+ * The admin that should delegate this scope.
+ *
+ * <p>If this is set to {@link AdminType#PRIMARY} and {@link #isPrimary()} is true, then the
+ * delegate will replace the primary dpc as primary without error.
+ */
+ AdminType admin();
+
+ /** The scope being delegated. */
+ String[] scopes();
+
+ /**
+ * Whether this delegate should be returned by calls to {@link DeviceState#policyManager()}.
+ *
+ * <p>Only one policy manager per test should be marked as primary.
+ */
+ boolean isPrimary() default false;
+
+ /**
+ * Weight sets the order that annotations will be resolved.
+ *
+ * <p>Annotations with a lower weight will be resolved before annotations with a higher weight.
+ *
+ * <p>If there is an order requirement between annotations, ensure that the weight of the
+ * annotation which must be resolved first is lower than the one which must be resolved later.
+ *
+ * <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
+ */
+ int weight() default DO_PO_WEIGHT + 1; // Should run after setting DO/PO
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
index 483a73e..2fdfc9d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDeviceOwner.java
@@ -49,13 +49,17 @@
@Retention(RetentionPolicy.RUNTIME)
@RequireFeature(FEATURE_DEVICE_ADMIN)
public @interface EnsureHasDeviceOwner {
+
+ int DO_PO_WEIGHT = MIDDLE;
+
/** Behaviour if the device owner cannot be set. */
FailureMode failureMode() default FailureMode.FAIL;
/**
- * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+ * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+ * {@link DeviceState#policyManager()}}.
*
- * <p>Only one device policy controller per test should be marked as primary.
+ * <p>Only one policy manager per test should be marked as primary.
*/
boolean isPrimary() default false;
@@ -74,5 +78,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
index 197a5fb..307b554 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDeviceOwner.java
@@ -16,7 +16,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -47,5 +47,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
index 72881ba..c97fd7f 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDpc.java
@@ -16,7 +16,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -53,5 +53,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
index 2d24990..561da3c 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoProfileOwner.java
@@ -17,7 +17,7 @@
package com.android.bedstead.harrier.annotations.enterprise;
import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -49,5 +49,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
index eb5c9e6..a408a4d 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasProfileOwner.java
@@ -19,7 +19,7 @@
import static android.content.pm.PackageManager.FEATURE_DEVICE_ADMIN;
import static com.android.bedstead.harrier.DeviceState.UserType.CURRENT_USER;
-import static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.MIDDLE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner.DO_PO_WEIGHT;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AnnotationRunPrecedence;
@@ -45,9 +45,10 @@
DeviceState.UserType onUser() default CURRENT_USER;
/**
- * Whether this DPC should be returned by calls to {@link DeviceState#dpc()}.
+ * Whether this DPC should be returned by calls to {@link DeviceState#dpc()} or
+ * {@link DeviceState#policyManager()}}.
*
- * <p>Only one device policy controller per test should be marked as primary.
+ * <p>Only one policy manager per test should be marked as primary.
*/
boolean isPrimary() default false;
@@ -66,5 +67,5 @@
*
* <p>Weight can be set to a {@link AnnotationRunPrecedence} constant, or to any {@link int}.
*/
- int weight() default MIDDLE;
+ int weight() default DO_PO_WEIGHT;
}
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
index f7f346d..9b3c16a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnterprisePolicy.java
@@ -166,6 +166,14 @@
* {@link APPLIES_IN_BACKGROUND}. */
int DOES_NOT_APPLY_IN_BACKGROUND = 1 << 18;
+
+ /**
+ * A policy which can be applied by a delegate.
+ *
+ * See {@link #delegatedScopes()} for the scopes which enable this.
+ */
+ int CAN_BE_DELEGATED = 1 << 19;
+
/** Flags indicating DPC states which can set the policy. */
int[] dpc() default {};
@@ -186,7 +194,7 @@
/**
* {@link DelegatedScope} indicating which delegated scopes can control the policy.
*
- * <p>Note that this currently does not generate any additional tests but may do in future.
+ * <p>This applies to {@link #dpc()} entries with the {@link #CAN_BE_DELEGATED} flag.
*/
- DelegatedScope[] delegatedScopes() default {};
+ String[] delegatedScopes() default {};
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
index 5944757..9e30dad 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictions.java
@@ -16,10 +16,13 @@
package com.android.bedstead.harrier.policies;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -34,8 +37,11 @@
* {@link DevicePolicyManager#setApplicationRestrictions(ComponentName, String, Bundle)} and
* {@link DevicePolicyManager#getApplicationRestrictions(ComponentName, String)}.
*/
-@EnterprisePolicy(dpc = {
- APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
- APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+@EnterprisePolicy(
+ dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND | CAN_BE_DELEGATED,
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED},
+ delegatedScopes = DELEGATION_APP_RESTRICTIONS
+ )
public final class ApplicationRestrictions {
}
\ No newline at end of file
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
new file mode 100644
index 0000000..379b071
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.bedstead.harrier.policies;
+
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_IN_BACKGROUND;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
+import android.os.Bundle;
+
+import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
+
+/**
+ * Policy for application restrictions.
+ *
+ * <p>This is used by the method
+ * {@link DevicePolicyManager#setApplicationRestrictionsManagingPackage(ComponentName, String, Bundle)}
+ */
+@EnterprisePolicy(
+ dpc = {
+ APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIES_IN_BACKGROUND,
+ APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER})
+public final class ApplicationRestrictionsManagingPackage {
+}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
index 12bb005..bc3861a 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetPermissionGrantState.java
@@ -21,12 +21,12 @@
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy;
-import com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.DelegatedScope;
/**
* Policies around setting the grant state of a basic permission.
@@ -36,8 +36,7 @@
* granting permissions not covered by other policies.
*/
@EnterprisePolicy(
- dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER,
- delegatedScopes = @DelegatedScope(
- scope = DELEGATION_PERMISSION_GRANT, appliesTo = APPLIES_TO_OWN_USER))
+ dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER | CAN_BE_DELEGATED,
+ delegatedScopes = DELEGATION_PERMISSION_GRANT)
public final class SetPermissionGrantState {
}
diff --git a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
index 67f5615..fac7dcd 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/SetSmsPermissionGranted.java
@@ -16,9 +16,12 @@
package com.android.bedstead.harrier.policies;
+import static android.app.admin.DevicePolicyManager.DELEGATION_PERMISSION_GRANT;
+
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_DEVICE_OWNER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIED_BY_PROFILE_OWNER_USER;
import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.APPLIES_TO_OWN_USER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnterprisePolicy.CAN_BE_DELEGATED;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
@@ -34,6 +37,7 @@
*/
// TODO(198311372): Check if APPLIED_BY_PROFILE_OWNER_USER is expected
@EnterprisePolicy(
- dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER)
+ dpc = APPLIED_BY_DEVICE_OWNER | APPLIES_TO_OWN_USER | APPLIED_BY_PROFILE_OWNER_USER | CAN_BE_DELEGATED,
+ delegatedScopes = DELEGATION_PERMISSION_GRANT)
public final class SetSmsPermissionGranted {
}
diff --git a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
index 34a738a..c0290fe 100644
--- a/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
+++ b/common/device-side/bedstead/harrier/src/test/java/com/android/bedstead/harrier/DeviceStateTest.java
@@ -18,6 +18,8 @@
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
+import static android.app.admin.DevicePolicyManager.DELEGATION_CERT_INSTALL;
import static android.content.pm.PackageManager.PERMISSION_DENIED;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -27,6 +29,8 @@
import static com.android.bedstead.harrier.OptionalBoolean.TRUE;
import static com.android.bedstead.harrier.annotations.RequireAospBuild.GMS_CORE_PACKAGE;
import static com.android.bedstead.harrier.annotations.RequireCnGmsBuild.CHINA_GOOGLE_SERVICES_FEATURE;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.DEVICE_OWNER;
+import static com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate.AdminType.PRIMARY;
import static com.android.bedstead.nene.users.UserType.MANAGED_PROFILE_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SECONDARY_USER_TYPE_NAME;
import static com.android.bedstead.nene.users.UserType.SYSTEM_USER_TYPE_NAME;
@@ -38,6 +42,7 @@
import android.app.ActivityManager;
import android.os.Build;
import android.platform.test.annotations.AppModeFull;
+import android.os.Bundle;
import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
@@ -67,6 +72,7 @@
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.harrier.annotations.RequireUserSupported;
import com.android.bedstead.harrier.annotations.TestTag;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDpc;
@@ -82,6 +88,8 @@
import com.android.bedstead.nene.packages.Package;
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.utils.Tags;
+import com.android.bedstead.remotedpc.RemoteDelegate;
+import com.android.bedstead.remotedpc.RemoteDpc;
import org.junit.ClassRule;
import org.junit.Ignore;
@@ -628,7 +636,7 @@
@IncludeRunOnBackgroundDeviceOwnerUser
public void includeRunOnBackgroundDeviceOwnerUserAnnotation_isRunningOnDeviceOwnerUser() {
assertThat(TestApis.users().instrumented())
- .isEqualTo(sDeviceState.dpc().devicePolicyController().user());
+ .isEqualTo(sDeviceState.dpc().user());
}
@Test
@@ -706,4 +714,51 @@
public void testTagAnnoation_testTagIsSet() {
assertThat(Tags.hasTag("TestTag")).isTrue();
}
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+ public void ensureHasPrimaryDelegateAnnotation_dpcReturnsDelegate() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = false)
+ public void ensureHasNonPrimaryDelegateAnnotation_dpcReturnsDpc() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER, scopes = DELEGATION_CERT_INSTALL, isPrimary = true)
+ public void ensureHasDelegateAnnotation_dpcCanUseDelegatedFunctionality() {
+ assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+ }
+
+ @Test
+ @EnsureHasDeviceOwner
+ @EnsureHasDelegate(admin = DEVICE_OWNER,
+ scopes = {DELEGATION_CERT_INSTALL, DELEGATION_APP_RESTRICTIONS}, isPrimary = true)
+ public void ensureHasDelegateAnnotation_multipleScopes_dpcCanUseAllDelegatedFunctionality() {
+ assertThat(sDeviceState.dpc().devicePolicyManager().getEnrollmentSpecificId()).isNotNull();
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sDeviceState.dpc().packageName(), new Bundle());
+ }
+
+ @Test
+ @EnsureHasDeviceOwner(isPrimary = true)
+ @EnsureHasDelegate(admin = PRIMARY, scopes = {})
+ public void ensureHasDelegateAnnotation_primaryAdminWithoutReplace_dpcReturnsDpc() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDpc.class);
+ }
+
+ @Test
+ @EnsureHasDeviceOwner(isPrimary = true)
+ @EnsureHasDelegate(admin = PRIMARY, scopes = {}, isPrimary = true)
+ public void ensureHasDelegateAnnotation_primaryAdminAndReplace_dpcReturnsDelegate() {
+ assertThat(sDeviceState.dpc()).isInstanceOf(RemoteDelegate.class);
+ }
}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
new file mode 100644
index 0000000..714208f
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDelegate.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 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.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppProvider;
+
+/**
+ * {@link RemotePolicyManager} subclass representing an app which has been delegated to.
+ */
+public final class RemoteDelegate extends RemotePolicyManager {
+
+ private static final TestAppProvider sTestAppProvider = new TestAppProvider();
+ public static final TestApp sTestApp = sTestAppProvider.query()
+ .wherePackageName().isEqualTo("com.android.Delegate")
+ .get();
+
+ public RemoteDelegate(TestApp testApp, UserReference user) {
+ super(testApp, user);
+ }
+
+ @Nullable
+ @Override
+ public ComponentName componentName() {
+ return null;
+ }
+}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
index ea230b2..01519a0 100644
--- a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemoteDpc.java
@@ -19,7 +19,6 @@
import static android.os.UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES;
import android.content.ComponentName;
-import android.content.Context;
import android.os.Build;
import android.os.UserHandle;
@@ -33,14 +32,10 @@
import com.android.bedstead.nene.users.UserReference;
import com.android.bedstead.nene.utils.Versions;
import com.android.bedstead.testapp.TestApp;
-import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
/** Entry point to RemoteDPC. */
-public final class RemoteDpc extends TestAppInstance {
-
- // This must be instrumentation not instrumented to access the resources
- private static final Context sContext = TestApis.context().instrumentationContext();
+public final class RemoteDpc extends RemotePolicyManager {
public static final ComponentName DPC_COMPONENT_NAME = new ComponentName(
"com.android.RemoteDPC",
@@ -258,16 +253,9 @@
}
/**
- * Get the {@link TestAppInstance} for the DPC.
- *
- */
- public TestAppInstance app() {
- return sTestApp.instance(mDevicePolicyController.user());
- }
-
- /**
* Get the {@link ComponentName} of the DPC.
*/
+ @Override
public ComponentName componentName() {
return DPC_COMPONENT_NAME;
}
diff --git a/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
new file mode 100644
index 0000000..8532ef3
--- /dev/null
+++ b/common/device-side/bedstead/remotedpc/src/main/java/com/android/bedstead/remotedpc/RemotePolicyManager.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2021 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.bedstead.remotedpc;
+
+import android.content.ComponentName;
+
+import androidx.annotation.Nullable;
+
+import com.android.bedstead.nene.users.UserReference;
+import com.android.bedstead.testapp.TestApp;
+import com.android.bedstead.testapp.TestAppInstance;
+
+/** A Remote app which can change device policy */
+public abstract class RemotePolicyManager extends TestAppInstance {
+
+ RemotePolicyManager(TestApp testApp, UserReference user) {
+ super(testApp, user);
+ }
+
+ /**
+ * Get the {@link ComponentName} of the device admin for the policy manager.
+ *
+ * <p>Null if there is no device admin
+ */
+ @Nullable
+ public abstract ComponentName componentName();
+}
diff --git a/common/device-side/bedstead/testapp/Android.bp b/common/device-side/bedstead/testapp/Android.bp
index 410f94b..bf92e97 100644
--- a/common/device-side/bedstead/testapp/Android.bp
+++ b/common/device-side/bedstead/testapp/Android.bp
@@ -99,7 +99,7 @@
java_genrule {
name: "TestApp_Apps",
- srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
+ srcs: [":EmptyTestApp", ":EmptyTestApp2", ":DeviceAdminTestApp", ":LockTaskApp", ":DelegateTestApp", ":RemoteDPCTestApp", ":SmsApp", ":AccountManagementApp"],
out: ["TestApp_Apps.res.zip"],
tools: ["soong_zip", "index_testapps", "aapt2"],
cmd: "mkdir -p $(genDir)/res/raw"
@@ -107,6 +107,7 @@
+ " && cp $(location :EmptyTestApp2) $(genDir)/res/raw"
+ " && cp $(location :DeviceAdminTestApp) $(genDir)/res/raw"
+ " && cp $(location :LockTaskApp) $(genDir)/res/raw"
+ + " && cp $(location :DelegateTestApp) $(genDir)/res/raw"
+ " && cp $(location :RemoteDPCTestApp) $(genDir)/res/raw"
+ " && cp $(location :SmsApp) $(genDir)/res/raw"
+ " && cp $(location :AccountManagementApp) $(genDir)/res/raw"
@@ -152,6 +153,15 @@
}
android_test_helper_app {
+ name: "DelegateTestApp",
+ static_libs: [
+ "TestApp_TestApps"
+ ],
+ manifest: "manifests/DelegateManifest.xml",
+ min_sdk_version: "28"
+}
+
+android_test_helper_app {
name: "RemoteDPCTestApp",
static_libs: [
"TestApp_TestApps",
diff --git a/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
new file mode 100644
index 0000000..5bd3772
--- /dev/null
+++ b/common/device-side/bedstead/testapp/manifests/DelegateManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ ~ Copyright (C) 2021 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.Delegate" android:targetSandboxVersion="2">
+
+ <application
+ android:appComponentFactory="com.android.bedstead.testapp.TestAppAppComponentFactory">
+
+ <!-- Don't allow this test app to be returned by queries unless filtered by package name -->
+ <meta-data android:name="testapp-package-query-only" android:value="true" />
+
+ </application>
+ <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28"/>
+</manifest>
\ No newline at end of file
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
index ce5023f..d95def6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivities.java
@@ -53,7 +53,7 @@
PackageManager p = TestApis.context().instrumentedContext().getPackageManager();
try {
PackageInfo packageInfo = p.getPackageInfo(
- mInstance.testApp().packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
+ mInstance.packageName(), /* flags= */ PackageManager.GET_ACTIVITIES);
for (android.content.pm.ActivityInfo activityInfo : packageInfo.activities) {
if (activityInfo.name.startsWith("androidx")) {
// Special case: androidx adds non-logging activities
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
index 3eb3633..761dec6 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppActivitiesQueryBuilder.java
@@ -55,7 +55,7 @@
return new UnresolvedTestAppActivity(mTestAppActivities.mInstance,
TestApis.packages().component(
new ComponentName(
- mTestAppActivities.mInstance.testApp().packageName(),
+ mTestAppActivities.mInstance.packageName(),
activity.className())));
}
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
index 4a4b5c8..282b68d 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppBinder.java
@@ -52,7 +52,7 @@
Intent bindIntent = new Intent();
bindIntent.setComponent(new ComponentName(
- mTestAppInstance.testApp().packageName(),
+ mTestAppInstance.packageName(),
bindToService.getClassName()));
Log.i(LOG_TAG, "Attempting to bind to " + bindIntent);
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
index a0db3b4..2a925dd 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppEvents.java
@@ -73,238 +73,238 @@
@Override
public ActivityCreatedEvent.ActivityCreatedEventQuery activityCreated() {
return ActivityCreatedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityDestroyedEvent.ActivityDestroyedEventQuery activityDestroyed() {
return ActivityDestroyedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityPausedEvent.ActivityPausedEventQuery activityPaused() {
return ActivityPausedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityRestartedEvent.ActivityRestartedEventQuery activityRestarted() {
return ActivityRestartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityResumedEvent.ActivityResumedEventQuery activityResumed() {
return ActivityResumedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityStartedEvent.ActivityStartedEventQuery activityStarted() {
return ActivityStartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public ActivityStoppedEvent.ActivityStoppedEventQuery activityStopped() {
return ActivityStoppedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public BroadcastReceivedEvent.BroadcastReceivedEventQuery broadcastReceived() {
return BroadcastReceivedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportFailedEvent.DeviceAdminBugreportFailedEventQuery bugReportFailed() {
return DeviceAdminBugreportFailedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportSharedEvent.DeviceAdminBugreportSharedEventQuery bugReportShared() {
return DeviceAdminBugreportSharedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminBugreportSharingDeclinedEvent.DeviceAdminBugreportSharingDeclinedEventQuery bugReportSharingDeclined() {
return DeviceAdminBugreportSharingDeclinedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminChoosePrivateKeyAliasEvent.DeviceAdminChoosePrivateKeyAliasEventQuery choosePrivateKeyAlias() {
return DeviceAdminChoosePrivateKeyAliasEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminDisabledEvent.DeviceAdminDisabledEventQuery deviceAdminDisabled() {
return DeviceAdminDisabledEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminDisableRequestedEvent.DeviceAdminDisableRequestedEventQuery deviceAdminDisableRequested() {
return DeviceAdminDisableRequestedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminEnabledEvent.DeviceAdminEnabledEventQuery deviceAdminEnabled() {
return DeviceAdminEnabledEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminLockTaskModeEnteringEvent.DeviceAdminLockTaskModeEnteringEventQuery lockTaskModeEntering() {
return DeviceAdminLockTaskModeEnteringEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminLockTaskModeExitingEvent.DeviceAdminLockTaskModeExitingEventQuery lockTaskModeExiting() {
return DeviceAdminLockTaskModeExitingEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminNetworkLogsAvailableEvent.DeviceAdminNetworkLogsAvailableEventQuery networkLogsAvailable() {
return DeviceAdminNetworkLogsAvailableEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminOperationSafetyStateChangedEvent.DeviceAdminOperationSafetyStateChangedEventQuery operationSafetyStateChanged() {
return DeviceAdminOperationSafetyStateChangedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordChangedEvent.DeviceAdminPasswordChangedEventQuery passwordChanged() {
return DeviceAdminPasswordChangedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordExpiringEvent.DeviceAdminPasswordExpiringEventQuery passwordExpiring() {
return DeviceAdminPasswordExpiringEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordFailedEvent.DeviceAdminPasswordFailedEventQuery passwordFailed() {
return DeviceAdminPasswordFailedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminPasswordSucceededEvent.DeviceAdminPasswordSucceededEventQuery passwordSucceeded() {
return DeviceAdminPasswordSucceededEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminProfileProvisioningCompleteEvent.DeviceAdminProfileProvisioningCompleteEventQuery profileProvisioningComplete() {
return DeviceAdminProfileProvisioningCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminReadyForUserInitializationEvent.DeviceAdminReadyForUserInitializationEventQuery readyForUserInitialization() {
return DeviceAdminReadyForUserInitializationEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminSecurityLogsAvailableEvent.DeviceAdminSecurityLogsAvailableEventQuery securityLogsAvailable() {
return DeviceAdminSecurityLogsAvailableEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminSystemUpdatePendingEvent.DeviceAdminSystemUpdatePendingEventQuery systemUpdatePending() {
return DeviceAdminSystemUpdatePendingEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.DeviceAdminTransferAffiliatedProfileOwnershipCompleteEventQuery transferAffiliatedProfileOwnershipComplete() {
return DeviceAdminTransferAffiliatedProfileOwnershipCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminTransferOwnershipCompleteEvent.DeviceAdminTransferOwnershipCompleteEventQuery transferOwnershipComplete() {
return DeviceAdminTransferOwnershipCompleteEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserAddedEvent.DeviceAdminUserAddedEventQuery userAdded() {
return DeviceAdminUserAddedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserRemovedEvent.DeviceAdminUserRemovedEventQuery userRemoved() {
return DeviceAdminUserRemovedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserStartedEvent.DeviceAdminUserStartedEventQuery userStarted() {
return DeviceAdminUserStartedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserStoppedEvent.DeviceAdminUserStoppedEventQuery userStopped() {
return DeviceAdminUserStoppedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
@Override
public DeviceAdminUserSwitchedEvent.DeviceAdminUserSwitchedEventQuery userSwitched() {
return DeviceAdminUserSwitchedEvent.queryPackage(
- mTestApp.testApp().packageName())
+ mTestApp.packageName())
.onUser(mTestApp.user());
}
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
index 56e0443..cea69a3 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppInstance.java
@@ -115,6 +115,13 @@
}
/**
+ * See {@link TestApp#packageName()}.
+ */
+ public String packageName() {
+ return testApp().packageName();
+ }
+
+ /**
* The {@link UserReference} this instance refers to.
*/
public UserReference user() {
diff --git a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
index 287c085..03fbceb 100644
--- a/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
+++ b/common/device-side/bedstead/testapp/src/processor/main/java/com/android/bedstead/testapp/processor/Processor.java
@@ -336,7 +336,14 @@
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
- .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+ .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
+ methodBuilder
.nextControlFlow("catch ($T e)", Throwable.class)
.addStatement(
"throw new $T($S, e)",
@@ -437,6 +444,11 @@
methodBuilder.addStatement("return $L", runLogic);
}
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
.addStatement("throw ($T) e.getCause()", RuntimeException.class)
@@ -536,6 +548,10 @@
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class);
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.addException(ClassName.get(m));
+ }
+
methodBuilder.addParameter(
ParameterSpec.builder(String.class, "activityClassName").build());
@@ -580,7 +596,14 @@
methodBuilder.nextControlFlow(
"catch ($T e)", PROFILE_RUNTIME_EXCEPTION_CLASSNAME)
- .addStatement("throw ($T) e.getCause()", RuntimeException.class)
+ .addStatement("throw ($T) e.getCause()", RuntimeException.class);
+
+ for (TypeMirror m : method.getThrownTypes()) {
+ methodBuilder.nextControlFlow("catch ($T e)", m)
+ .addStatement("throw e");
+ }
+
+ methodBuilder
.nextControlFlow("catch ($T e)", Throwable.class)
.addStatement(
"throw new $T($S, e)",
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
deleted file mode 100644
index 9c73feb..0000000
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/AppRestrictionsDelegateTest.java
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * 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.
- */
-package com.android.cts.delegate;
-
-import static android.app.admin.DevicePolicyManager.DELEGATION_APP_RESTRICTIONS;
-
-import static com.android.cts.delegate.DelegateTestUtils.assertExpectException;
-
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.os.Bundle;
-import android.os.Process;
-import android.util.Log;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.List;
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Test that an app given the {@link DevicePolicyManager#DELEGATION_APP_RESTRICTIONS} scope via
- * {@link DevicePolicyManager#setDelegatedScopes} can manage app restrictions.
- */
-public class AppRestrictionsDelegateTest extends BaseJUnit3TestCase {
-
- private static final String TAG = AppRestrictionsDelegateTest.class.getSimpleName();
-
- private static final String APP_RESTRICTIONS_TARGET_PKG =
- "com.android.cts.apprestrictions.targetapp";
- private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
- APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
- private static final String ACTION_RESTRICTIONS_VALUE =
- "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
- private static final Bundle BUNDLE_0 = createBundle0();
- private static final Bundle BUNDLE_1 = createBundle1();
-
- private static final long TIMEOUT_SECONDS = 10;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- Log.d(TAG, "onReceive(): intent " + action + " on uid " + Process.myUid());
- if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
- mReceivedRestrictions = intent.getBundleExtra("value");
- mOnRestrictionsSemaphore.release();
- }
- }
- };
-
- private final Semaphore mOnRestrictionsSemaphore = new Semaphore(0);
- private Bundle mReceivedRestrictions;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_RESTRICTIONS_VALUE));
- }
-
- @Override
- protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
- super.tearDown();
- }
-
- public void testCannotAccessApis() {
- assertFalse("DelegateApp should not be an app restrictions delegate",
- amIAppRestrictionsDelegate());
-
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, null);
- });
-
- assertExpectException(SecurityException.class,
- "Calling identity is not authorized", () -> {
- mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
- });
- }
-
- public void testCanAccessApis() throws InterruptedException {
- assertTrue("DelegateApp is not an app restrictions delegate", amIAppRestrictionsDelegate());
- try {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
- assertBundle0(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
-
- // Check that the target app can retrieve the same restrictions.
- assertBundle0(waitForChangedRestriction());
-
- // Test overwriting
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
- assertBundle1(mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(waitForChangedRestriction());
- } finally {
- mDpm.setApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- assertTrue(
- mDpm.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
- }
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle0() {
- Bundle result = new Bundle();
- result.putString("placeholderString", "value");
- return result;
- }
-
- // Should be consistent with createBundle0
- private void assertBundle0(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals("value", bundle.getString("placeholderString"));
- }
-
- // Should be consistent with assertBundle1
- private static Bundle createBundle1() {
- Bundle result = new Bundle();
- result.putInt("placeholderInt", 1);
- return result;
- }
-
- // Should be consistent with createBundle1
- private void assertBundle1(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals(1, bundle.getInt("placeholderInt"));
- }
-
- private void startTestActivity() {
- ComponentName component = new ComponentName(
- APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME);
- Log.d(TAG, "Starting activity " + component.flattenToShortString() + " on user "
- + Process.myUserHandle());
- mContext.startActivity(new Intent()
- .setComponent(component)
- .putExtra("admin_type",
- InstrumentationRegistry.getArguments().getString("admin_type"))
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
- }
-
- private Bundle waitForChangedRestriction() throws InterruptedException {
- startTestActivity();
- assertTrue("App restrictions target app did not respond in time",
- mOnRestrictionsSemaphore.tryAcquire(TIMEOUT_SECONDS, TimeUnit.SECONDS));
- return mReceivedRestrictions;
- }
-
- private boolean amIAppRestrictionsDelegate() {
- final List<String> scopes = mDpm.getDelegatedScopes(null, mContext.getPackageName());
- return scopes.contains(DELEGATION_APP_RESTRICTIONS);
- }
-}
diff --git a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
index 869ff7c..b93b884 100644
--- a/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
+++ b/hostsidetests/devicepolicy/app/DelegateApp/src/com/android/cts/delegate/GeneralDelegateTest.java
@@ -16,7 +16,6 @@
package com.android.cts.delegate;
import android.app.admin.DevicePolicyManager;
-import android.content.ComponentName;
import android.os.Bundle;
import android.test.MoreAsserts;
import android.util.Log;
@@ -58,17 +57,4 @@
expected.getMessage());
}
}
-
- public void testSettingAdminComponentNameThrowsException() {
- final String myPackageName = getInstrumentation().getContext().getPackageName();
- final ComponentName myComponentName = new ComponentName(myPackageName,
- GeneralDelegateTest.class.getName());
-
- try {
- mDpm.setUninstallBlocked(myComponentName, myPackageName, true);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex("No active admin", expected.getMessage());
- }
- }
}
diff --git a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
deleted file mode 100644
index 201aeed..0000000
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,338 +0,0 @@
-/*
- * 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
- *
- * 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.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Bundle;
-import android.os.Parcelable;
-import android.os.UserManager;
-import android.test.MoreAsserts;
-
-import androidx.test.InstrumentationRegistry;
-
-import java.util.concurrent.Semaphore;
-import java.util.concurrent.TimeUnit;
-
-/**
- * Functionality tests for application restrictions APIs.
- *
- * <p>APIs are executed locally to assert that what you set can later be retrieved via the getter.
- * It also fires up an external activity to observe an application's view of its restrictions.
- *
- * <p>Finally, it checks that the {@link Intent#ACTION_APPLICATION_RESTRICTIONS_CHANGED} broadcast
- * is sent whenever app restrictions are modified for a given package.
- */
-public class ApplicationRestrictionsTest extends BaseDeviceAdminTest {
-
- private static final String APP_RESTRICTIONS_TARGET_PKG =
- "com.android.cts.apprestrictions.targetapp";
- private static final String APP_RESTRICTIONS_ACTIVITY_NAME =
- APP_RESTRICTIONS_TARGET_PKG + ".ApplicationRestrictionsActivity";
- private static final String ACTION_RESTRICTIONS_VALUE =
- "com.android.cts.apprestrictions.targetapp.RESTRICTIONS_VALUE";
-
- private static final String OTHER_PACKAGE = APP_RESTRICTIONS_TARGET_PKG + "placeholder";
-
- private static final String[] TEST_STRINGS = new String[] {
- "<bad/>",
- ">worse!\"£$%^&*()'<",
- "<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
- + "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
- };
-
- private static final Bundle BUNDLE_0 = createBundle0();
- private static final Bundle BUNDLE_1 = createBundle1();
-
- private static final long RESTRICTIONS_TIMEOUT_SECONDS = 10;
-
- private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- String action = intent.getAction();
- if (ACTION_RESTRICTIONS_VALUE.equals(action)) {
- mReceivedRestrictions = intent.getBundleExtra("value");
- mOnRestrictionsReceivedFromAppSemaphore.release();
- } else if (Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED.equals(action)) {
- mOnAppRestrictionsChangedSemahore.release();
- }
- }
- };
-
- private final Semaphore mOnAppRestrictionsChangedSemahore = new Semaphore(0);
- private final Semaphore mOnRestrictionsReceivedFromAppSemaphore = new Semaphore(0);
- private Bundle mReceivedRestrictions;
- private UserManager mUserManager;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-
- IntentFilter filter = new IntentFilter();
- filter.addAction(ACTION_RESTRICTIONS_VALUE);
- filter.addAction(Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED);
- mContext.registerReceiver(mReceiver, filter);
- }
-
- @Override
- protected void tearDown() throws Exception {
- mContext.unregisterReceiver(mReceiver);
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, new Bundle());
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, mContext.getPackageName(), new Bundle());
-
- super.tearDown();
- }
-
- public void testNullComponentThrowsException() {
- try {
- mDevicePolicyManager.setApplicationRestrictions(
- null, APP_RESTRICTIONS_TARGET_PKG, null);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex(
- "Calling identity is not authorized",
- expected.getMessage());
- }
- try {
- mDevicePolicyManager.getApplicationRestrictions(null, APP_RESTRICTIONS_TARGET_PKG);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- MoreAsserts.assertContainsRegex(
- "Calling identity is not authorized",
- expected.getMessage());
- }
- }
-
- public void testSetApplicationRestrictions() {
- // Test setting restrictions
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_0);
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, BUNDLE_1);
-
- // Retrieve restrictions locally and make sure they are what we put in.
- assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE));
-
- // Check that the target app can retrieve the same restrictions.
- assertBundle0(waitForRestrictionsValueFromTestActivity());
-
- // Test overwriting
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, BUNDLE_1);
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG));
- assertBundle1(waitForRestrictionsValueFromTestActivity());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG, new Bundle());
- assertTrue(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG).isEmpty());
- assertTrue(waitForRestrictionsValueFromTestActivity().isEmpty());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE, null);
- assertTrue(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, OTHER_PACKAGE).isEmpty());
- }
-
- public void testCanRetrieveOwnRestrictionsViaUserManager() {
- final String packageName = mContext.getPackageName();
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_0);
- assertBundle0(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName));
-
- // Check that we got the restrictions changed callback.
- assertBundle0(waitForRestrictionsChangedBroadcast());
-
- mDevicePolicyManager.setApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName, BUNDLE_1);
- assertBundle1(mDevicePolicyManager.getApplicationRestrictions(
- ADMIN_RECEIVER_COMPONENT, packageName));
- assertBundle1(waitForRestrictionsChangedBroadcast());
- }
-
- public void testCannotRetrieveOtherPackageRestrictionsViaUserManager() {
- try {
- mUserManager.getApplicationRestrictions(OTHER_PACKAGE);
- fail("Expected SecurityException not thrown");
- } catch (SecurityException expected) {
- }
- }
-
- public void testSetApplicationRestrictionsManagingPackage() throws NameNotFoundException {
- final String previousValue = mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT);
- try {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, APP_RESTRICTIONS_TARGET_PKG);
- assertEquals(APP_RESTRICTIONS_TARGET_PKG,
- mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, null);
- assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- } finally {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT, previousValue);
- assertEquals(previousValue,
- mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- }
- }
-
- public void testSetApplicationRestrictionsManagingPackageForNotInstalledPackage()
- throws NameNotFoundException {
- try {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
- OTHER_PACKAGE);
- fail("Not throwing exception for not installed package name");
- } catch (NameNotFoundException expected) {
- MoreAsserts.assertContainsRegex(OTHER_PACKAGE, expected.getMessage());
- } finally {
- mDevicePolicyManager.setApplicationRestrictionsManagingPackage(ADMIN_RECEIVER_COMPONENT,
- null);
- assertNull(mDevicePolicyManager.getApplicationRestrictionsManagingPackage(
- ADMIN_RECEIVER_COMPONENT));
- }
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle0() {
- Bundle result = new Bundle();
- // Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
- // Also test for string escaping handling
- result.putBoolean("boolean_0", false);
- result.putBoolean("boolean_1", true);
- result.putInt("integer", 0x7fffffff);
- // If a null is stored, "" will be read back
- result.putString("empty", "");
- result.putString("string", "text");
- result.putStringArray("string[]", TEST_STRINGS);
-
- // Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
- Bundle bundle = new Bundle();
- bundle.putString("bundle_string", "bundle_string");
- bundle.putInt("bundle_int", 1);
- result.putBundle("bundle", bundle);
-
- // Adding an array of 2 bundles
- Bundle[] bundleArray = new Bundle[2];
- bundleArray[0] = new Bundle();
- bundleArray[0].putString("bundle_array_string", "bundle_array_string");
- // Put bundle inside bundle
- bundleArray[0].putBundle("bundle_array_bundle", bundle);
- bundleArray[1] = new Bundle();
- bundleArray[1].putString("bundle_array_string2", "bundle_array_string2");
- result.putParcelableArray("bundle_array", bundleArray);
- return result;
- }
-
- // Should be consistent with createBundle0
- private void assertBundle0(Bundle bundle) {
- assertEquals(8, bundle.size());
- assertEquals(false, bundle.getBoolean("boolean_0"));
- assertEquals(true, bundle.getBoolean("boolean_1"));
- assertEquals(0x7fffffff, bundle.getInt("integer"));
- assertEquals("", bundle.getString("empty"));
- assertEquals("text", bundle.getString("string"));
-
- String[] strings = bundle.getStringArray("string[]");
- assertTrue(strings != null && strings.length == TEST_STRINGS.length);
- for (int i = 0; i < strings.length; i++) {
- assertEquals(strings[i], TEST_STRINGS[i]);
- }
-
- Bundle childBundle = bundle.getBundle("bundle");
- assertEquals("bundle_string", childBundle.getString("bundle_string"));
- assertEquals(1, childBundle.getInt("bundle_int"));
-
- Parcelable[] bundleArray = bundle.getParcelableArray("bundle_array");
- assertEquals(2, bundleArray.length);
- // Verifying bundle_array[0]
- Bundle bundle1 = (Bundle) bundleArray[0];
- assertEquals("bundle_array_string", bundle1.getString("bundle_array_string"));
- Bundle bundle1ChildBundle = bundle1.getBundle("bundle_array_bundle");
- assertNotNull(bundle1ChildBundle);
- assertEquals("bundle_string", bundle1ChildBundle.getString("bundle_string"));
- assertEquals(1, bundle1ChildBundle.getInt("bundle_int"));
- // Verifying bundle_array[1]
- Bundle bundle2 = (Bundle) bundleArray[1];
- assertEquals("bundle_array_string2", bundle2.getString("bundle_array_string2"));
- }
-
- // Should be consistent with assertBundle1
- private static Bundle createBundle1() {
- Bundle result = new Bundle();
- result.putInt("placeholder", 1);
- return result;
- }
-
- // Should be consistent with createBundle1
- private void assertBundle1(Bundle bundle) {
- assertEquals(1, bundle.size());
- assertEquals(1, bundle.getInt("placeholder"));
- }
-
- private void startTestActivity() {
- mContext.startActivity(new Intent()
- .setComponent(new ComponentName(
- APP_RESTRICTIONS_TARGET_PKG, APP_RESTRICTIONS_ACTIVITY_NAME))
- .putExtra("admin_type",
- InstrumentationRegistry.getArguments().getString("admin_type"))
- .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK));
- }
-
- private Bundle waitForRestrictionsValueFromTestActivity() {
- startTestActivity();
-
- try {
- assertTrue(mOnRestrictionsReceivedFromAppSemaphore.tryAcquire(
- RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- fail("waitForRestrictionsValueFromTestActivity() interrupted");
- }
-
- return mReceivedRestrictions;
- }
-
- private Bundle waitForRestrictionsChangedBroadcast() {
- try {
- assertTrue(mOnAppRestrictionsChangedSemahore.tryAcquire(
- RESTRICTIONS_TIMEOUT_SECONDS, TimeUnit.SECONDS));
- } catch (InterruptedException e) {
- fail("waitForRestrictionsChangedBroadcast() interrupted");
- }
-
- return mUserManager.getApplicationRestrictions(mContext.getPackageName());
- }
-}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index e228828..bd1cb47 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
@@ -234,53 +234,6 @@
"testAssertCallerIsApplicationRestrictionsManagingPackage", mUserId);
}
- @Test
- public void testApplicationRestrictions() throws Exception {
- installAppAsUser(DELEGATE_APP_APK, mUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, mUserId);
-
- try {
- // Only the DPC can manage app restrictions by default.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
- executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
- // Letting the DELEGATE_APP_PKG manage app restrictions too.
- changeApplicationRestrictionsManagingPackage(DELEGATE_APP_PKG);
- executeAppRestrictionsManagingPackageTest("testCanAccessApis");
- runDeviceTestsAsUser(DELEGATE_APP_PKG, ".GeneralDelegateTest",
- "testSettingAdminComponentNameThrowsException", mUserId);
-
- // The DPC should still be able to manage app restrictions normally.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
-
- // The app shouldn't be able to manage app restrictions for other users.
- int parentUserId = getPrimaryUser();
- if (parentUserId != mUserId) {
- installAppAsUser(DELEGATE_APP_APK, parentUserId);
- installAppAsUser(APP_RESTRICTIONS_TARGET_APP_APK, parentUserId);
- runDeviceTestsAsUser(DELEGATE_APP_PKG, ".AppRestrictionsDelegateTest",
- "testCannotAccessApis", parentUserId);
- }
-
- // Revoking the permission for DELEGATE_APP_PKG to manage restrictions.
- changeApplicationRestrictionsManagingPackage(null);
- executeAppRestrictionsManagingPackageTest("testCannotAccessApis");
-
- // The DPC should still be able to manage app restrictions normally.
- executeDeviceTestClass(".ApplicationRestrictionsTest");
-
- assertMetricsLogged(getDevice(), () -> {
- executeDeviceTestMethod(".ApplicationRestrictionsTest",
- "testSetApplicationRestrictions");
- }, new DevicePolicyEventWrapper.Builder(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
- .setAdminPackageName(DEVICE_ADMIN_PKG)
- .setStrings(APP_RESTRICTIONS_TARGET_APP_PKG)
- .build());
- } finally {
- changeApplicationRestrictionsManagingPackage(null);
- }
- }
-
/**
* Returns a list of delegation tests that should run. Add delegations tests applicable to both
* device owner and profile owners to this method directly. DO or PO specific tests should be
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
index 6d21042..75af1c8 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/MixedDeviceOwnerTest.java
@@ -142,14 +142,6 @@
@Override
@Test
- @TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "189268544",
- reason = "Will be migrated to new test infra")
- public void testApplicationRestrictions() throws Exception {
- super.testApplicationRestrictions();
- }
-
- @Override
- @Test
@TemporarilyIgnoreOnHeadlessSystemUserMode(bugId = "197909577",
reason = "Will be migrated to new test infra")
public void testAccountManagement_userRestrictionAddAccount() throws Exception {
diff --git a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
index 3038849..955a078 100644
--- a/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
+++ b/hostsidetests/packagemanager/domainverification/device/multiuser/src/com/android/cts/packagemanager/verify/domain/device/multiuser/DomainVerificationWorkUtils.kt
@@ -38,7 +38,7 @@
internal fun DeviceState.getWorkDevicePolicyManager() =
profileOwner(workProfile(DeviceState.UserType.PRIMARY_USER))!!
- .app().devicePolicyManager()
+ .devicePolicyManager()
internal fun <T> withUserContext(user: UserReference, block: (context: Context) -> T) =
TestApis.permissions()
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 3ed02e8..b567e77 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
@@ -42,7 +42,7 @@
import com.android.bedstead.harrier.policies.AccountManagement;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.utils.Poll;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
@@ -85,8 +85,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mAccountManager = sContext.getSystemService(AccountManager.class);
}
@@ -100,7 +100,8 @@
@Test
@Postsubmit(reason = "new test")
- @CannotSetPolicyTest(policy = AccountManagement.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = AccountManagement.class, includeNonDeviceAdminStates = false)
public void setAccountTypesWithManagementDisabled_invalidAdmin_throwsException() {
assertThrows(OperationCanceledException.class, () ->
mDpm.setAccountManagementDisabled(
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
index da08a5c..0c054e3 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ApplicationRestrictionsTest.java
@@ -15,12 +15,21 @@
*/
package android.devicepolicy.cts;
+import static android.content.Intent.ACTION_APPLICATION_RESTRICTIONS_CHANGED;
+
+import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
+import static com.android.eventlib.truth.EventLogsSubject.assertThat;
+
+import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
import static org.testng.Assert.assertThrows;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.os.Bundle;
import android.os.Parcelable;
+import android.stats.devicepolicy.EventId;
import android.util.Log;
import com.android.bedstead.harrier.BedsteadJUnit4;
@@ -31,6 +40,8 @@
import com.android.bedstead.harrier.annotations.enterprise.NegativePolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.ApplicationRestrictions;
+import com.android.bedstead.harrier.policies.ApplicationRestrictionsManagingPackage;
+import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
@@ -45,170 +56,32 @@
@RunWith(BedsteadJUnit4.class)
public final class ApplicationRestrictionsTest {
+ @ClassRule
+ @Rule
+ public static final DeviceState sDeviceState = new DeviceState();
private static final String TAG = ApplicationRestrictionsTest.class.getSimpleName();
-
- private static final String[] TEST_STRINGS = new String[] {
+ private static final String[] TEST_STRINGS = new String[]{
"<bad/>",
">worse!\"£$%^&*()'<",
"<JSON>\"{ \\\"One\\\": { \\\"OneOne\\\": \\\"11\\\", \\\""
+ "OneTwo\\\": \\\"12\\\" }, \\\"Two\\\": \\\"2\\\" } <JSON/>\""
};
-
- private static final Bundle BUNDLE = createBundle();
-
- @ClassRule
- @Rule
- public static final DeviceState sDeviceState = new DeviceState();
-
private static final TestAppProvider sTestAppProvider = new TestAppProvider();
private static final TestApp sTestApp = sTestAppProvider.any();
private static final TestApp sDifferentTestApp = sTestAppProvider.any();
- @Test
- @Postsubmit(reason = "New test")
- @PositivePolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_applicationRestrictionsAreSet() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstance testApp = sTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertEqualToBundle(
- testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertEqualToBundle(
- sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_differentPackage_throwsException() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertThrows(SecurityException.class,
- () -> differentTestApp.userManager().getApplicationRestrictions(
- sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CanSetPolicyTest(policy = ApplicationRestrictions.class)
- public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager()
- .getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertNotEqualToBundle(differentTestApp.userManager().getApplicationRestrictions(
- sDifferentTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @NegativePolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
- Bundle originalApplicationRestrictions =
- sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName());
-
- try (TestAppInstance testApp = sTestApp.install()) {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
-
- assertNotEqualToBundle(testApp.userManager().getApplicationRestrictions(
- sTestApp.packageName()));
- } finally {
- sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
- sDeviceState.dpc().componentName(),
- sTestApp.packageName(), originalApplicationRestrictions);
- }
- }
-
- @Test
- @Postsubmit(reason = "New test")
- @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
- public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
- assertThrows(SecurityException.class, () -> {
- sDeviceState.dpc().devicePolicyManager()
- .setApplicationRestrictions(
- sDeviceState.dpc().componentName(), sTestApp.packageName(),
- BUNDLE);
- });
- }
-
- // Should be consistent with assertBundle0
- private static Bundle createBundle() {
+ // Should be consistent with assertEqualToBundle
+ private static Bundle createBundle(String id) {
Bundle result = new Bundle();
// Tests for 6 allowed types: Integer, Boolean, String, String[], Bundle and Parcelable[]
// Also test for string escaping handling
result.putBoolean("boolean_0", false);
result.putBoolean("boolean_1", true);
- result.putInt("integer", 0x7fffffff);
+ result.putInt("integer", 0xfffff);
// If a null is stored, "" will be read back
result.putString("empty", "");
- result.putString("string", "text");
+ result.putString("string", id);
result.putStringArray("string[]", TEST_STRINGS);
// Adding a bundle, which contain 2 nested restrictions - bundle_string and bundle_int
@@ -229,15 +102,298 @@
return result;
}
- // Should be consistent with createBundle0
- private void assertEqualToBundle(Bundle bundle) {
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_applicationRestrictionsAreSet() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAreSet");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAreSet",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ new Bundle());
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("setApplicationRestrictions_applicationRestrictionsAlreadySet_setsNewRestrictions",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions");
+
+ try {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertEqualToBundle("getApplicationRestrictions_applicationRestrictionsAreSet_returnsApplicationRestrictions",
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_differentPackage_throwsException() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_differentPackage_throwsException");
+
+ try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThrows(SecurityException.class,
+ () -> differentTestApp.userManager().getApplicationRestrictions(
+ sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_setForOtherPackage_returnsNull() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("getApplicationRestrictions_setForOtherPackage_returnsNull");
+
+ try (TestAppInstance differentTestApp = sDifferentTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertNotEqualToBundle("getApplicationRestrictions_setForOtherPackage_returnsNull",
+ differentTestApp.userManager().getApplicationRestrictions(
+ sDifferentTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @NegativePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertNotEqualToBundle("setApplicationRestrictions_policyDoesNotApply_applicationRestrictionsAreNotSet",
+ testApp.userManager().getApplicationRestrictions(sTestApp.packageName()));
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_cannotSetPolicy_throwsException() {
+ Bundle bundle = createBundle("setApplicationRestrictions_cannotSetPolicy_throwsException");
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+ });
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CannotSetPolicyTest(policy = ApplicationRestrictions.class)
+ public void getApplicationRestrictions_cannotSetPolicy_throwsException() {
+ assertThrows(SecurityException.class, () -> {
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ });
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictions.class, singleTestOnly = true)
+ public void setApplicationRestrictions_nullComponent_throwsException() {
+ Bundle bundle = createBundle("setApplicationRestrictions_nullComponent_throwsException");
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(null,
+ sTestApp.packageName(), bundle));
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_restrictionsChangedBroadcastIsReceived() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_restrictionsChangedBroadcastIsReceived");
+
+ try (TestAppInstance testApp = sTestApp.install()) {
+ testApp.registerReceiver(new IntentFilter(ACTION_APPLICATION_RESTRICTIONS_CHANGED));
+
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThat(testApp.events().broadcastReceived().whereIntent().action().isEqualTo(
+ ACTION_APPLICATION_RESTRICTIONS_CHANGED)).eventOccurred();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+ public void setApplicationRestrictionsManagingPackage_applicationRestrictionsManagingPackageIsSet()
+ throws Exception {
+ final String originalApplicationRestrictionsManagingPackage =
+ sDeviceState.dpc().devicePolicyManager().getApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName());
+ try (TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+
+ assertThat(sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictionsManagingPackage(sDeviceState.dpc().componentName()))
+ .isEqualTo(sTestApp.packageName());
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(),
+ originalApplicationRestrictionsManagingPackage);
+ }
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @CanSetPolicyTest(policy = ApplicationRestrictionsManagingPackage.class)
+ public void setApplicationRestrictionsManagingPackage_appNotInstalled_throwsException() {
+ sDifferentTestApp.uninstall();
+
+ assertThrows(PackageManager.NameNotFoundException.class,
+ () -> sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictionsManagingPackage(
+ sDeviceState.dpc().componentName(),
+ sDifferentTestApp.packageName()));
+ }
+
+ @Test
+ @Postsubmit(reason = "New test")
+ @PositivePolicyTest(policy = ApplicationRestrictions.class)
+ public void setApplicationRestrictions_logged() {
+ Bundle originalApplicationRestrictions =
+ sDeviceState.dpc().devicePolicyManager()
+ .getApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName());
+ Bundle bundle = createBundle("setApplicationRestrictions_logged");
+
+ try (EnterpriseMetricsRecorder metrics = EnterpriseMetricsRecorder.create();
+ TestAppInstance testApp = sTestApp.install()) {
+ sDeviceState.dpc().devicePolicyManager()
+ .setApplicationRestrictions(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ bundle);
+
+ assertThat(metrics.query()
+ .whereType().isEqualTo(EventId.SET_APPLICATION_RESTRICTIONS_VALUE)
+ .whereAdminPackageName().isEqualTo(
+ sDeviceState.dpc().packageName())
+ .whereStrings().contains(sTestApp.packageName())
+ .whereStrings().size().isEqualTo(1))
+ .wasLogged();
+ } finally {
+ sDeviceState.dpc().devicePolicyManager().setApplicationRestrictions(
+ sDeviceState.dpc().componentName(),
+ sTestApp.packageName(), originalApplicationRestrictions);
+ }
+ }
+
+ // Should be consistent with createBundle
+ private void assertEqualToBundle(String id, Bundle bundle) {
assertWithMessage("bundle0 size")
.that(bundle.size()).isEqualTo(8);
assertBooleanKey(bundle, "boolean_0", false);
assertBooleanKey(bundle, "boolean_1", true);
- assertIntKey(bundle, "integer", 0x7fffffff);
+ assertIntKey(bundle, "integer", 0xfffff);
assertStringKey(bundle, "empty", "");
- assertStringKey(bundle, "string", "text");
+ assertStringKey(bundle, "string", id);
assertStringsKey(bundle, "string[]", TEST_STRINGS);
Bundle childBundle = bundle.getBundle("bundle");
@@ -300,9 +456,9 @@
return value;
}
- private void assertNotEqualToBundle(Bundle value) {
+ private void assertNotEqualToBundle(String id, Bundle value) {
// This uses an arbitrary value from the test bundle
assertWithMessage("Bundle should not be equal to test bundle")
- .that(value.getInt("integer")).isNotEqualTo(0x7fffffff);
+ .that(value.getString("string")).isNotEqualTo(id);
}
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
index baabdc7..c6f550f 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -42,6 +42,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.permissions.PermissionContext;
import com.android.compatibility.common.util.BlockingCallback;
@@ -66,6 +67,7 @@
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@RunWith(BedsteadJUnit4.class)
public class CredentialManagementAppTest {
@@ -74,6 +76,7 @@
@Rule
public static final DeviceState sDeviceState = new DeviceState();
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
private static final PrivateKey PRIVATE_KEY =
getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
private static final Certificate CERTIFICATE =
@@ -277,6 +280,8 @@
@Test
@Postsubmit(reason = "b/181993922 automatically marked flaky")
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
public void choosePrivateKeyAlias_isCredentialManagementApp_aliasSelected() throws Exception {
setCredentialManagementApp();
@@ -291,7 +296,8 @@
/* keyTypes= */ null, /* issuers= */ null, URI, /* alias = */ null)
);
- assertThat(callback.await()).isEqualTo(ALIAS);
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(ALIAS);
} finally {
// Remove keypair as credential management app
sDevicePolicyManager.removeKeyPair(/* admin = */ null, ALIAS);
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 473c60e..ddd7eeb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
@@ -37,7 +37,7 @@
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.DefaultSmsApplication;
import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import com.android.bedstead.testapp.TestApp;
import com.android.bedstead.testapp.TestAppInstance;
import com.android.bedstead.testapp.TestAppProvider;
@@ -71,8 +71,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
mTelephonyManager = sContext.getSystemService(TelephonyManager.class);
}
@@ -85,9 +85,9 @@
assumeTrue(mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
- assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.testApp().packageName());
+ assertThat(getDefaultSmsPackage()).isEqualTo(smsApp.packageName());
} finally {
mDpm.setDefaultSmsApplication(mAdmin, previousSmsAppName);
}
@@ -101,7 +101,7 @@
assumeTrue(mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
} finally {
@@ -134,7 +134,7 @@
assertThrows(NullPointerException.class, () ->
mDpm.setDefaultSmsApplication(
- /* admin= */ null, smsApp.testApp().packageName()));
+ /* admin= */ null, smsApp.packageName()));
}
}
@@ -146,7 +146,7 @@
assumeTrue(!mTelephonyManager.isSmsCapable());
String previousSmsAppName = getDefaultSmsPackage();
try (TestAppInstance smsApp = sSmsApp.install()) {
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName());
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName());
assertThat(getDefaultSmsPackage()).isEqualTo(previousSmsAppName);
} finally {
@@ -156,12 +156,13 @@
@Test
@Postsubmit(reason = "new test")
- @CannotSetPolicyTest(policy = DefaultSmsApplication.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = DefaultSmsApplication.class, includeNonDeviceAdminStates = false)
public void setDefaultSmsApplication_invalidAdmin_throwsException() {
try (TestAppInstance smsApp = sSmsApp.install()) {
assertThrows(SecurityException.class, () ->
- mDpm.setDefaultSmsApplication(mAdmin, smsApp.testApp().packageName()));
+ mDpm.setDefaultSmsApplication(mAdmin, smsApp.packageName()));
}
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
index 2579f14..fa0ebb8 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
@@ -32,7 +32,7 @@
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.DeprecatedPasswordAPIs;
import com.android.bedstead.nene.TestApis;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import org.junit.Before;
import org.junit.ClassRule;
@@ -57,8 +57,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDpm = dpc.devicePolicyManager();
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 0b65080..fbca7dd 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -34,6 +34,7 @@
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.Postsubmit;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.KeyManagement;
@@ -62,6 +63,7 @@
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
/**
* Test that a DPC can manage keys and certificate on a device by installing, generating and
@@ -74,6 +76,7 @@
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 600;
private static final String RSA = "RSA";
private static final String RSA_ALIAS = "com.android.test.valid-rsa-key-1";
private static final PrivateKey PRIVATE_KEY =
@@ -270,6 +273,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
public void choosePrivateKeyAlias_aliasIsSelectedByAdmin_returnAlias() throws Exception {
try {
// Install keypair
@@ -279,7 +284,8 @@
choosePrivateKeyAlias(callback, RSA_ALIAS);
- assertThat(callback.await()).isEqualTo(RSA_ALIAS);
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(RSA_ALIAS);
} finally {
// Remove keypair
sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
@@ -289,6 +295,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
public void choosePrivateKeyAlias_nonUserSelectedAliasIsSelectedByAdmin_returnAlias()
throws Exception {
try {
@@ -299,7 +307,8 @@
choosePrivateKeyAlias(callback, RSA_ALIAS);
- assertThat(callback.await()).isEqualTo(RSA_ALIAS);
+ assertThat(callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS))
+ .isEqualTo(RSA_ALIAS);
} finally {
// Remove keypair
sDeviceState.dpc().devicePolicyManager().removeKeyPair(DPC_COMPONENT_NAME, RSA_ALIAS);
@@ -309,6 +318,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = KeyManagement.class)
+ @SlowApiTest(reason = "The KeyChain.choosePrivateKeyAlias API sometimes "
+ + "takes a long time to callback")
public void getPrivateKey_aliasIsGranted_returnPrivateKey() throws Exception {
try {
// Install keypair
@@ -317,7 +328,7 @@
// Grant alias via {@code KeyChain.choosePrivateKeyAlias}
KeyChainAliasCallback callback = new KeyChainAliasCallback();
choosePrivateKeyAlias(callback, RSA_ALIAS);
- callback.await();
+ callback.await(KEYCHAIN_CALLBACK_TIMEOUT_SECONDS, TimeUnit.SECONDS);
// Get private key for the granted alias
final PrivateKey privateKey =
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index a56b9ac..5f4bacb 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
@@ -34,6 +34,8 @@
import static com.google.common.truth.Truth.assertWithMessage;
+import static org.testng.Assert.assertThrows;
+
import com.android.bedstead.harrier.BedsteadJUnit4;
import com.android.bedstead.harrier.DeviceState;
import com.android.bedstead.harrier.annotations.AfterClass;
@@ -557,7 +559,7 @@
}
@Test
- @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class)
+ @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
public void grantSmsPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
int existingGrantState = sDeviceState.dpc().devicePolicyManager()
.getPermissionGrantState(sDeviceState.dpc().componentName(),
@@ -583,6 +585,15 @@
}
@Test
+ @CannotSetPolicyTest(policy = SetSmsPermissionGranted.class, includeNonDeviceAdminStates = false)
+ public void grantSmsPermission_nonDeviceAdmin_throwsException() {
+ assertThrows(SecurityException.class,
+ () -> sDeviceState.dpc().devicePolicyManager().setPermissionGrantState(
+ sDeviceState.dpc().componentName(), sTestApp.packageName(),
+ READ_SMS, PERMISSION_GRANT_STATE_GRANTED));
+ }
+
+ @Test
@CannotSetPolicyTest(policy = SetSensorPermissionGranted.class)
public void grantSensorPermission_cannotBeApplied_returnsTrueButDoesNotSetGrantState() {
// TODO(b/188893663): Replace with parameterization
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
index f3873bb..3610ac4 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/SupportMessageTest.java
@@ -31,7 +31,7 @@
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.SupportMessage;
import com.android.bedstead.metricsrecorder.EnterpriseMetricsRecorder;
-import com.android.bedstead.remotedpc.RemoteDpc;
+import com.android.bedstead.remotedpc.RemotePolicyManager;
import org.junit.After;
import org.junit.Before;
@@ -67,8 +67,8 @@
@Before
public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
+ RemotePolicyManager dpc = sDeviceState.dpc();
+ mAdmin = dpc.componentName();
mDevicePolicyManager = dpc.devicePolicyManager();
}
@@ -195,7 +195,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void getLongSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -203,7 +204,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void setLongSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -211,7 +213,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void getShortSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
@@ -219,7 +222,8 @@
}
@Test
- @CannotSetPolicyTest(policy = SupportMessage.class)
+ // We don't include non device admin states as passing a null admin is a NullPointerException
+ @CannotSetPolicyTest(policy = SupportMessage.class, includeNonDeviceAdminStates = false)
@Postsubmit(reason = "new test")
public void setShortSupportMessage_invalidAdmin_fails() {
assertThrows(SecurityException.class, () ->
diff --git a/tests/framework/base/windowmanager/AndroidManifest.xml b/tests/framework/base/windowmanager/AndroidManifest.xml
index 35f50d9..14856b3 100644
--- a/tests/framework/base/windowmanager/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/AndroidManifest.xml
@@ -518,6 +518,18 @@
android:exported="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout|colorMode|density|touchscreen"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
+
+ <activity android:name="android.server.wm.HostActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.server.wm.app.HostActivity"/>
+ </intent-filter>
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/framework/base/windowmanager/app/AndroidManifest.xml b/tests/framework/base/windowmanager/app/AndroidManifest.xml
index 36909cc..fbbbbca 100755
--- a/tests/framework/base/windowmanager/app/AndroidManifest.xml
+++ b/tests/framework/base/windowmanager/app/AndroidManifest.xml
@@ -573,14 +573,9 @@
</intent-filter>
</service>
- <activity android:name=".HostActivity"
- android:exported="true">
- <intent-filter>
- <action android:name="android.server.wm.app.HostActivity"/>
- </intent-filter>
- </activity>
<service android:name=".RenderService"
- android:process=".render_process"/>
+ android:process=".render_process"
+ android:exported="true"/>
<activity android:name=".ClickableToastActivity"
android:exported="true"/>
<activity android:name=".MinimalPostProcessingActivity"
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 1dfb795..79499f7 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
@@ -579,6 +579,12 @@
public static class RenderService {
public static final String PROCESS_NAME = ".render_process";
+ public static final String EXTRAS_BUNDLE = "EXTRAS_BUNDLE";
+ public static final String EXTRAS_DISPLAY_ID = "EXTRAS_DISPLAY_ID";
+ public static final String EXTRAS_HOST_TOKEN = "EXTRAS_HOST_TOKEN";
+ public static final String BROADCAST_EMBED_CONTENT =
+ "android.server.wm.app.RenderService.EMBED_CONTENT";
+ public static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
}
/**
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
index f781d2e..9c611ea 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
+++ b/tests/framework/base/windowmanager/app/src/android/server/wm/app/RenderService.java
@@ -16,13 +16,16 @@
package android.server.wm.app;
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
-import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.IBinder;
@@ -32,18 +35,13 @@
import android.view.MotionEvent;
import android.view.SurfaceControlViewHost;
import android.view.View;
-import android.view.WindowManager;
import android.widget.Button;
-public class RenderService extends Service {
- static final String EXTRAS_BUNDLE = "INTENT_BUNDLE";
- static final String EXTRAS_DISPLAY_ID = "hostDisplayId";
- static final String EXTRAS_HOST_TOKEN = "hostInputToken";
- static final String BROADCAST_EMBED_CONTENT
- = "android.server.wm.app.RenderService.EMBED_CONTENT";
- static final String EXTRAS_SURFACE_PACKAGE = "surfacePackage";
+import java.util.concurrent.CountDownLatch;
+public class RenderService extends Service {
private int mOnMotionEventDelayMs;
+ CountDownLatch mViewDrawnCallbackLatch = new CountDownLatch(1);
private boolean onTouch(View v, MotionEvent event) {
SystemClock.sleep(mOnMotionEventDelayMs);
@@ -60,7 +58,7 @@
SurfaceControlViewHost surfaceControlViewHost = getSurfaceControlViewHost(hostToken,
hostDisplayId);
- sendSurfacePackage(surfaceControlViewHost.getSurfacePackage());
+ new Thread(()-> sendSurfacePackage(surfaceControlViewHost.getSurfacePackage())).start();
return null;
}
@@ -71,6 +69,8 @@
View embeddedView = new Button(this);
embeddedView.setOnTouchListener(this::onTouch);
+ embeddedView.getViewTreeObserver().registerFrameCommitCallback(
+ mViewDrawnCallbackLatch::countDown);
DisplayMetrics metrics = new DisplayMetrics();
displayContext.getDisplay().getMetrics(metrics);
surfaceControlViewHost.setView(embeddedView, metrics.widthPixels, metrics.heightPixels);
@@ -84,8 +84,12 @@
}
private void sendSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) {
- Intent broadcast = new Intent();
- broadcast.setAction(BROADCAST_EMBED_CONTENT);
+ try {
+ // wait until we commit a frame from the embedded viewrootimpl
+ mViewDrawnCallbackLatch.await();
+ } catch (InterruptedException ignored) {
+ }
+ Intent broadcast = new Intent(BROADCAST_EMBED_CONTENT);
broadcast.putExtra(EXTRAS_SURFACE_PACKAGE, surfacePackage);
sendBroadcast(broadcast);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
index 312fb4c..91b42dc 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/AnrTests.java
@@ -23,17 +23,15 @@
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_CREATE_DELAY_MS;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_KEYDOWN_DELAY_MS;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.view.Display.DEFAULT_DISPLAY;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
-import android.app.ActivityTaskManager;
import android.content.ComponentName;
import android.os.SystemClock;
import android.platform.test.annotations.Presubmit;
-import android.server.wm.app.Components.RenderService;
import android.provider.Settings;
+import android.server.wm.app.Components.RenderService;
import android.server.wm.settings.SettingsSession;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
@@ -43,14 +41,16 @@
import android.util.Log;
import android.view.KeyEvent;
+import androidx.test.core.app.ActivityScenario;
+import androidx.test.filters.FlakyTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.util.List;
-
-import androidx.test.filters.FlakyTest;
-import androidx.test.platform.app.InstrumentationRegistry;
+import java.util.concurrent.CountDownLatch;
/**
* Test scenarios that lead to ANR dialog being shown.
@@ -123,15 +123,11 @@
startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
UNRESPONSIVE_ACTIVITY);
- // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
mWmState.computeState();
// Tap on the UnresponsiveActivity
final WindowManagerState.Task unresponsiveActivityTask =
mWmState.getTaskByActivity(UNRESPONSIVE_ACTIVITY);
- tapOnTaskCenter(unresponsiveActivityTask);
- SystemClock.sleep(1000);
- tapOnTaskCenter(unresponsiveActivityTask);
-
+ mTouchHelper.tapOnTaskCenterAsync(unresponsiveActivityTask);
clickCloseAppOnAnrDialog();
assertEventLogsContainsAnr(UnresponsiveActivity.PROCESS_NAME);
}
@@ -141,19 +137,19 @@
*/
@Test
public void embeddedWindowTriggersAnr() {
- startUnresponsiveActivity(EXTRA_ON_MOTIONEVENT_DELAY_MS, true /* waitForCompletion */,
- HOST_ACTIVITY);
-
- // TODO(b/143566069) investigate why we need multiple taps on display to trigger anr.
- mWmState.computeState();
- // Tap on the HostActivity
- final WindowManagerState.Task hostActivityTask =
- mWmState.getTaskByActivity(HOST_ACTIVITY);
- tapOnTaskCenter(hostActivityTask);
- SystemClock.sleep(1000);
- tapOnTaskCenter(hostActivityTask);
-
- clickCloseAppOnAnrDialog();
+ try (ActivityScenario<HostActivity> scenario =
+ ActivityScenario.launch(HostActivity.class)) {
+ CountDownLatch[] latch = new CountDownLatch[1];
+ scenario.onActivity(activity -> latch[0] = activity.mEmbeddedViewAttachedLatch);
+ latch[0].await();
+ mWmState.computeState();
+ final WindowManagerState.Task hostActivityTask =
+ mWmState.getTaskByActivity(new ComponentName("android.server.wm.cts",
+ "android.server.wm.HostActivity"));
+ mTouchHelper.tapOnTaskCenterAsync(hostActivityTask);
+ clickCloseAppOnAnrDialog();
+ } catch (InterruptedException ignored) {
+ }
assertEventLogsContainsAnr(RenderService.PROCESS_NAME);
}
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
index e948001..ad1d0e3 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/CompatChangeTests.java
@@ -45,7 +45,6 @@
import android.util.Size;
import androidx.annotation.Nullable;
-import androidx.test.filters.FlakyTest;
import libcore.junit.util.compat.CoreCompatChangeRule.DisableCompatChanges;
import libcore.junit.util.compat.CoreCompatChangeRule.EnableCompatChanges;
diff --git a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
similarity index 65%
rename from tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
rename to tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
index 4a365a3..318e1e6 100644
--- a/tests/framework/base/windowmanager/app/src/android/server/wm/app/HostActivity.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/HostActivity.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2020 The Android Open Source Project
+ * Copyright (C) 2021 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.
@@ -14,14 +14,14 @@
* limitations under the License.
*/
-package android.server.wm.app;
+package android.server.wm;
+import static android.server.wm.app.Components.RenderService.BROADCAST_EMBED_CONTENT;
+import static android.server.wm.app.Components.RenderService.EXTRAS_BUNDLE;
+import static android.server.wm.app.Components.RenderService.EXTRAS_DISPLAY_ID;
+import static android.server.wm.app.Components.RenderService.EXTRAS_HOST_TOKEN;
+import static android.server.wm.app.Components.RenderService.EXTRAS_SURFACE_PACKAGE;
import static android.server.wm.app.Components.UnresponsiveActivity.EXTRA_ON_MOTIONEVENT_DELAY_MS;
-import static android.server.wm.app.RenderService.BROADCAST_EMBED_CONTENT;
-import static android.server.wm.app.RenderService.EXTRAS_BUNDLE;
-import static android.server.wm.app.RenderService.EXTRAS_DISPLAY_ID;
-import static android.server.wm.app.RenderService.EXTRAS_HOST_TOKEN;
-import static android.server.wm.app.RenderService.EXTRAS_SURFACE_PACKAGE;
import android.app.Activity;
import android.content.BroadcastReceiver;
@@ -32,15 +32,18 @@
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
-import android.view.SurfaceControlViewHost.SurfacePackage;
+import android.view.SurfaceControlViewHost;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
+import java.util.concurrent.CountDownLatch;
+
+
public class HostActivity extends Activity implements SurfaceHolder.Callback{
private SurfaceView mSurfaceView;
-
+ public CountDownLatch mEmbeddedViewAttachedLatch = new CountDownLatch(1);
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {}
@@ -49,13 +52,14 @@
public void onServiceDisconnected(ComponentName className) {}
};
- private BroadcastReceiver receiver = new BroadcastReceiver() {
+ private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- SurfacePackage surfacePackage =
+ SurfaceControlViewHost.SurfacePackage surfacePackage =
intent.getParcelableExtra(EXTRAS_SURFACE_PACKAGE);
if (surfacePackage != null) {
mSurfaceView.setChildSurfacePackage(surfacePackage);
+ mEmbeddedViewAttachedLatch.countDown();
}
}
};
@@ -64,9 +68,8 @@
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- IntentFilter filter = new IntentFilter();
- filter.addAction(BROADCAST_EMBED_CONTENT);
- registerReceiver(receiver, filter);
+ IntentFilter filter = new IntentFilter(BROADCAST_EMBED_CONTENT);
+ registerReceiver(mReceiver, filter);
final RelativeLayout content = new RelativeLayout(this);
mSurfaceView = new SurfaceView(this);
@@ -81,20 +84,21 @@
@Override
protected void onPause() {
- unregisterReceiver(receiver);
+ unregisterReceiver(mReceiver);
super.onPause();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
- Intent mIntent = new Intent(this, RenderService.class);
- Bundle b = new Bundle();
- b.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
- b.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
- b.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS,
- getIntent().getIntExtra(EXTRA_ON_MOTIONEVENT_DELAY_MS, 2000));
- mIntent.putExtra(EXTRAS_BUNDLE, b);
- bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE|Context.BIND_IMPORTANT);
+ Intent mIntent = new Intent();
+ mIntent.setComponent(new ComponentName(
+ "android.server.wm.app", "android.server.wm.app.RenderService"));
+ Bundle bundle = new Bundle();
+ bundle.putBinder(EXTRAS_HOST_TOKEN, mSurfaceView.getHostToken());
+ bundle.putInt(EXTRAS_DISPLAY_ID, getDisplay().getDisplayId());
+ bundle.putInt(EXTRA_ON_MOTIONEVENT_DELAY_MS, 10000);
+ mIntent.putExtra(EXTRAS_BUNDLE, bundle);
+ bindService(mIntent, mConnection, Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);
}
@Override
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
index 3d6d97c..49d2dba 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PrivacyIndicatorBoundsTests.java
@@ -21,6 +21,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.server.wm.RoundedCornerTests.TestActivity.EXTRA_ORIENTATION;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -31,9 +32,11 @@
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
import android.app.Activity;
import android.app.AppOpsManager;
+import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
@@ -56,7 +59,7 @@
@Presubmit
@RunWith(Parameterized.class)
-public class PrivacyIndicatorBoundsTests {
+public class PrivacyIndicatorBoundsTests extends ActivityManagerTestBase {
private static final String TAG = PrivacyIndicatorBoundsTests.class.getSimpleName();
private static final long TIMEOUT_MS = 1000;
@@ -85,6 +88,10 @@
@Test
public void testStaticBoundsAreNotNull() {
+ // TODO(b/187757919): Allow Automotive to skip this test until privacy chip is implemented
+ // in immersive mode
+ assumeFalse(isCar());
+
final PrivacyIndicatorBoundsTests.TestActivity activity = mTestActivity.launchActivity(
new Intent().putExtra(EXTRA_ORIENTATION, orientation));
getInstrumentation().runOnMainSync(() -> {
diff --git a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
index 8a68de1..34a16a5 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/TaskFragmentOrganizerTestBase.java
@@ -30,7 +30,6 @@
import android.os.IBinder;
import android.server.wm.WindowManagerState.WindowContainer;
import android.util.ArrayMap;
-import android.window.TaskFragmentAppearedInfo;
import android.window.TaskFragmentCreationParams;
import android.window.TaskFragmentInfo;
import android.window.TaskFragmentOrganizer;
@@ -259,11 +258,9 @@
}
@Override
- public void onTaskFragmentAppeared(
- @NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {
- super.onTaskFragmentAppeared(taskFragmentAppearedInfo);
- final TaskFragmentInfo info = taskFragmentAppearedInfo.getTaskFragmentInfo();
- mInfos.put(info.getFragmentToken(), info);
+ public void onTaskFragmentAppeared(@NonNull TaskFragmentInfo taskFragmentInfo) {
+ super.onTaskFragmentAppeared(taskFragmentInfo);
+ mInfos.put(taskFragmentInfo.getFragmentToken(), taskFragmentInfo);
mAppearedLatch.countDown();
}
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 2b133f4..054da4c 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/WindowInsetsControllerTests.java
@@ -607,8 +607,10 @@
@Test
public void testInsetsDispatch() throws Exception {
- // Start an activity which hides system bars.
- final TestHideOnCreateActivity activity = startActivity(TestHideOnCreateActivity.class);
+ // Start an activity which hides system bars in fullscreen mode,
+ // otherwise, it might not be able to hide system bars in other windowing modes.
+ final TestHideOnCreateActivity activity = startActivityInWindowingModeFullScreen(
+ TestHideOnCreateActivity.class);
final View rootView = activity.getWindow().getDecorView();
ANIMATION_CALLBACK.waitForFinishing();
PollingCheck.waitFor(TIMEOUT,
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 e37f284..1c2fdf9 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
@@ -1308,7 +1308,7 @@
*/
protected static class DisableScreenDozeRule implements TestRule {
- /** Copied from android.provider.Settings.Secure since these keys are hiden. */
+ /** Copied from android.provider.Settings.Secure since these keys are hidden. */
private static final String[] DOZE_SETTINGS = {
"doze_enabled",
"doze_always_on",
@@ -1317,7 +1317,8 @@
"doze_pulse_on_double_tap",
"doze_wake_screen_gesture",
"doze_wake_display_gesture",
- "doze_tap_gesture"
+ "doze_tap_gesture",
+ "doze_quick_pickup_gesture"
};
private String get(String key) {
diff --git a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
index 39afb54..54c9b3e 100644
--- a/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
+++ b/tests/framework/base/windowmanager/util/src/android/server/wm/TouchHelper.java
@@ -163,4 +163,11 @@
KeyEvent.ACTION_UP, keyCode, 0 /* repeatCount */);
getInstrumentation().getUiAutomation().injectInputEvent(upEvent, sync);
}
+
+ public void tapOnTaskCenterAsync(WindowManagerState.Task task) {
+ final Rect bounds = task.getBounds();
+ final int x = bounds.left + bounds.width() / 2;
+ final int y = bounds.top + bounds.height() / 2;
+ tapOnDisplay(x, y, task.mDisplayId, false /* sync*/);
+ }
}
diff --git a/tests/inputmethod/AndroidManifest.xml b/tests/inputmethod/AndroidManifest.xml
index 8ce099b..18c6ebf 100644
--- a/tests/inputmethod/AndroidManifest.xml
+++ b/tests/inputmethod/AndroidManifest.xml
@@ -29,7 +29,7 @@
<activity android:name="android.view.inputmethod.cts.util.TestActivity"
android:theme="@style/no_starting_window"
android:label="TestActivity"
- android:configChanges="fontScale"
+ android:configChanges="fontScale|smallestScreenSize|screenSize|screenLayout"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/tests/tests/media/src/android/media/cts/AudioTrackTest.java b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
index d179c5a..8065633 100755
--- a/tests/tests/media/src/android/media/cts/AudioTrackTest.java
+++ b/tests/tests/media/src/android/media/cts/AudioTrackTest.java
@@ -3367,6 +3367,122 @@
}
}
+ /**
+ * Test AudioTrack Builder error handling.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void testAudioTrackBuilderError() throws Exception {
+ if (!hasAudioOutput()) {
+ return;
+ }
+
+ final AudioTrack[] audioTrack = new AudioTrack[1]; // pointer to audio track.
+ final int BIGNUM = Integer.MAX_VALUE; // large value that should be invalid.
+ final int INVALID_SESSION_ID = 1024; // can never occur (wrong type in 3 lsbs)
+ final int INVALID_CHANNEL_MASK = -1;
+
+ try {
+ // NOTE:
+ // Tuner Configuration builder error tested in testTunerConfiguration (same file).
+ // AudioAttributes tested in AudioAttributesTest#testAudioAttributesBuilderError.
+ // AudioFormat tested in AudioFormatTest#testAudioFormatBuilderError.
+
+ // We must be able to create the AudioTrack.
+ audioTrack[0] = new AudioTrack.Builder().build();
+ audioTrack[0].release();
+
+ // Out of bounds buffer size. A large size will fail in AudioTrack creation.
+ assertThrows(UnsupportedOperationException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setBufferSizeInBytes(BIGNUM)
+ .build();
+ });
+
+ // 0 and negative buffer size throw IllegalArgumentException
+ for (int bufferSize : new int[] {-BIGNUM, -1, 0}) {
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setBufferSizeInBytes(bufferSize)
+ .build();
+ });
+ }
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setEncapsulationMode(BIGNUM)
+ .build();
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setPerformanceMode(BIGNUM)
+ .build();
+ });
+
+ // Invalid session id that is positive.
+ // (logcat error message vague)
+ assertThrows(UnsupportedOperationException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setSessionId(INVALID_SESSION_ID)
+ .build();
+ });
+
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setTransferMode(BIGNUM)
+ .build();
+ });
+
+ // Specialty AudioTrack build errors.
+
+ // Bad audio encoding DRA expected unsupported.
+ try {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setChannelMask(AudioFormat.CHANNEL_OUT_STEREO)
+ .setEncoding(AudioFormat.ENCODING_DRA)
+ .build())
+ .build();
+ // Don't throw an exception, maybe it is supported somehow, but warn.
+ // Note: often specialty audio formats are offloaded (see setOffloadedPlayback).
+ // AudioTrackSurroundTest and AudioTrackOffloadedTest can be used as examples.
+ Log.w(TAG, "ENCODING_DRA is expected to be unsupported");
+ audioTrack[0].release();
+ audioTrack[0] = null;
+ } catch (UnsupportedOperationException e) {
+ ; // OK expected
+ }
+
+ // Sample rate out of bounds.
+ // System levels caught on AudioFormat.
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setSampleRate(BIGNUM)
+ .build())
+ .build();
+ });
+
+ // Invalid channel mask - caught here on use.
+ assertThrows(IllegalArgumentException.class, () -> {
+ audioTrack[0] = new AudioTrack.Builder()
+ .setAudioFormat(new AudioFormat.Builder()
+ .setChannelMask(INVALID_CHANNEL_MASK)
+ .build())
+ .build();
+ });
+ } finally {
+ // Did we successfully complete for some reason but did not
+ // release?
+ if (audioTrack[0] != null) {
+ audioTrack[0].release();
+ audioTrack[0] = null;
+ }
+ }
+ }
+
/* Do not run in JB-MR1. will be re-opened in the next platform release.
public void testResourceLeakage() throws Exception {
final int BUFFER_SIZE = 600 * 1024;
diff --git a/tests/tests/settings/Android.bp b/tests/tests/settings/Android.bp
index 246e3fd..b1a443e 100644
--- a/tests/tests/settings/Android.bp
+++ b/tests/tests/settings/Android.bp
@@ -17,12 +17,20 @@
static_libs: [
"androidx.slice_slice-core",
"androidx.slice_slice-view",
+ "androidx.test.core",
"ctstestrunner-axt",
"junit",
+ "kotlin-stdlib",
"truth-prebuilt",
+ "ctsWindowExtLib",
],
srcs: ["src/**/*.java"],
sdk_version: "test_current",
}
+
+android_library_import {
+ name: "ctsWindowExtLib",
+ aars: ["libs/cts_window_ext_lib.aar"],
+}
diff --git a/tests/tests/settings/AndroidManifest.xml b/tests/tests/settings/AndroidManifest.xml
index 9225b6a..007b36d 100644
--- a/tests/tests/settings/AndroidManifest.xml
+++ b/tests/tests/settings/AndroidManifest.xml
@@ -20,9 +20,20 @@
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/>
+ <uses-permission android:name="android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK"/>
<application>
<uses-library android:name="android.test.runner"/>
+ <uses-library android:name="androidx.window.extensions" android:required="false"/>
+ <uses-library android:name="androidx.window.sidecar" android:required="false"/>
+
+ <activity android:name=".RightPaneActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.settings.cts.LAUNCH_RIGHT_PANE"/>
+ <category android:name="android.intent.category.DEFAULT"/>
+ </intent-filter>
+ </activity>
</application>
<instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
diff --git a/tests/tests/settings/libs/cts_window_ext_lib.aar b/tests/tests/settings/libs/cts_window_ext_lib.aar
new file mode 100644
index 0000000..ca58b36
--- /dev/null
+++ b/tests/tests/settings/libs/cts_window_ext_lib.aar
Binary files differ
diff --git a/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
new file mode 100644
index 0000000..86391e7
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/RightPaneActivity.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2021 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.settings.cts;
+
+import android.app.Activity;
+import android.provider.Settings;
+
+/**
+ * For SettingsMultiPaneDeepLinkTest to test if
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+public class RightPaneActivity extends Activity {
+}
diff --git a/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
new file mode 100644
index 0000000..b6103c8
--- /dev/null
+++ b/tests/tests/settings/src/android/settings/cts/SettingsMultiPaneDeepLinkTest.java
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2021 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.settings.cts;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.app.Instrumentation.ActivityMonitor;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.provider.Settings;
+
+import androidx.test.platform.app.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+import androidx.window.embedding.SplitController;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/**
+ * Tests to ensure the Activity to handle
+ * {@link Settings#ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY}
+ */
+@RunWith(AndroidJUnit4.class)
+public class SettingsMultiPaneDeepLinkTest {
+
+ private static final String DEEP_LINK_PERMISSION =
+ "android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK";
+
+ boolean mIsSplitSupported;
+ ResolveInfo mDeepLinkIntentResolveInfo;
+
+ @Before
+ public void setUp() throws Exception {
+ // runOnMainSync or SplitController#isSplitSupported will return wrong value for large
+ // screen devices.
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
+ @Override
+ public void run() {
+ mIsSplitSupported = SplitController.getInstance().isSplitSupported();
+ }
+ });
+ mDeepLinkIntentResolveInfo = InstrumentationRegistry.getInstrumentation().getContext()
+ .getPackageManager().resolveActivity(
+ new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY),
+ /* flags= */ PackageManager.MATCH_DEFAULT_ONLY);
+
+ assumeFalse("Skipping test: The device does not support Activity embedding",
+ !mIsSplitSupported && mDeepLinkIntentResolveInfo == null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_protectedWithPermission() throws Exception {
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be protected by " + DEEP_LINK_PERMISSION,
+ DEEP_LINK_PERMISSION.equals(mDeepLinkIntentResolveInfo.activityInfo.permission));
+ }
+
+ @Test
+ public void deepLinkHomeActivity_splitSupported_deepLinkHomeEnabled() throws Exception {
+ assumeTrue(mIsSplitSupported);
+
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be enabled when the device supports Activity embedding",
+ mDeepLinkIntentResolveInfo != null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_splitNotSupported_deepLinkHomeDisabled() throws Exception {
+ assumeFalse(mIsSplitSupported);
+
+ assertTrue("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY must"
+ + " be disabled when the device does NOT support Activity embedding",
+ mDeepLinkIntentResolveInfo == null);
+ }
+
+ @Test
+ public void deepLinkHomeActivity_receiveMultiPaneDeepLinkIntent_shouldStartActivity()
+ throws Exception {
+ Intent intent = new Intent(Settings.ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY);
+ intent.putExtra(Settings.EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI,
+ new Intent("android.settings.cts.LAUNCH_RIGHT_PANE")
+ .toUri(Intent.URI_INTENT_SCHEME));
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
+ ActivityMonitor am = instrumentation.addMonitor(RightPaneActivity.class.getName(),
+ /* result */ null, /* block */ false);
+
+ // Take the Shell UID permission identity because Shell app has the permission
+ // android.permission.LAUNCH_MULTI_PANE_SETTINGS_DEEP_LINK.
+ instrumentation.getUiAutomation().adoptShellPermissionIdentity();
+ try {
+ instrumentation.getContext()
+ .startActivity(intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ } finally {
+ // Drop the Shell UID permission identity.
+ instrumentation.getUiAutomation().dropShellPermissionIdentity();
+ }
+
+ Activity rightPaneActivity = am.waitForActivityWithTimeout(5000);
+ assertNotNull("The Activity to handle the Intent ACTION_SETTINGS_EMBED_DEEP_LINK_ACTIVITY"
+ + " must start Activity for EXTRA_SETTINGS_EMBEDDED_DEEP_LINK_INTENT_URI",
+ rightPaneActivity);
+ rightPaneActivity.finish();
+ }
+}
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 a594afa..722cdae 100644
--- a/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/cts/TelephonyManagerTest.java
@@ -3333,6 +3333,19 @@
TelephonyManager.SIM_STATE_NOT_READY,
TelephonyManager.SIM_STATE_PERM_DISABLED,
TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+
+ for (int i = 0; i <= mTelephonyManager.getPhoneCount(); i++) {
+ final int slotId = i;
+ simApplicationState = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mTelephonyManager, (tm) -> tm.getSimApplicationState(slotId));
+ assertTrue(Arrays.asList(TelephonyManager.SIM_STATE_UNKNOWN,
+ TelephonyManager.SIM_STATE_PIN_REQUIRED,
+ TelephonyManager.SIM_STATE_PUK_REQUIRED,
+ TelephonyManager.SIM_STATE_NETWORK_LOCKED,
+ TelephonyManager.SIM_STATE_NOT_READY,
+ TelephonyManager.SIM_STATE_PERM_DISABLED,
+ TelephonyManager.SIM_STATE_LOADED).contains(simApplicationState));
+ }
}
@Test
diff --git a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
index 4863f5b..d4386ff 100644
--- a/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
+++ b/tests/tests/telephony/current/src/android/telephony/ims/cts/RcsUceAdapterTest.java
@@ -818,6 +818,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -831,6 +833,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
/*
@@ -854,6 +858,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestAvailability(uceAdapter, sTestNumberUri, callback);
@@ -867,6 +873,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
});
@@ -888,6 +896,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
requestCapabilities(uceAdapter, numbers, callback);
@@ -902,6 +912,8 @@
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
overrideCarrierConfig(null);
@@ -975,22 +987,38 @@
});
requestCapabilities(uceAdapter, contacts, callback);
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1, capability);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, true);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -999,6 +1027,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -1010,16 +1039,34 @@
// Verify the contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -1028,6 +1075,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -1051,17 +1099,35 @@
// Verify the first contact is found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, true);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
// Verify the reset contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -1962,60 +2028,17 @@
} else if (sipCode == sipCodeBadEvent) {
assertTrue(retryAfterMillis > 0L);
}
-
- // Verify the ImsService received the capabilities request.
- assertEquals(1, subscribeRequestCount.get());
} catch (Exception e) {
fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
} finally {
errorQueue.clear();
retryAfterQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
subscribeRequestCount.set(0);
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
}
-
- // Override the network response with the sip code 503 Service Unavailable
- capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
- subscribeRequestCount.incrementAndGet();
- cb.onNetworkResponse(503, "Service Unavailable");
- });
-
- try {
- // Request contact uce capabilities again.
- requestCapabilities(uceAdapter, contacts, callback);
-
- if (sipCode == sipCodeForbidden) {
- // Verify that device can still send the subscribe request. The callback
- // "onError" is called with the Server Unavailable error.
- assertEquals(RcsUceAdapter.ERROR_SERVER_UNAVAILABLE,
- waitForIntResult(errorQueue));
- // Verify the retryAfter value
- assertEquals(0L, waitForLongResult(retryAfterQueue));
- // Verify that the capabilities is not forbidden. The ImsService received the
- // request from the framework.
- assertEquals(1, subscribeRequestCount.get());
- } else if (sipCode == sipCodeBadEvent) {
- // When carrier config Bad Event flag is enabled and the device has received
- // the sip code 489 (bad event) before, the uce request will be forbidden.
-
- // Verify that the callback "onError" is called with the error code FORBIDDEN
- assertEquals(RcsUceAdapter.ERROR_FORBIDDEN, waitForIntResult(errorQueue));
- // Verify the retryAfter value
- long retryAfterMillis = waitForLongResult(retryAfterQueue);
- assertTrue(retryAfterMillis > 0L);
- // Verify that the capabilities won't be send to the ImsService because the
- // uce request is forbidden.
- assertEquals(0, subscribeRequestCount.get());
- }
- } catch (Exception e) {
- fail("testForbiddenResponseToCapabilitiesRequest with command error failed: " + e);
- } finally {
- errorQueue.clear();
- retryAfterQueue.clear();
- subscribeRequestCount.set(0);
- }
-
- // Reset the device status
- removeUceRequestDisallowedStatus();
});
overrideCarrierConfig(null);
@@ -2284,6 +2307,7 @@
completeQueue.clear();
capabilityQueue.clear();
removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
setCapabilitiesRequestTimeout(-1L);
}
@@ -2309,12 +2333,115 @@
completeQueue.clear();
capabilityQueue.clear();
removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
setCapabilitiesRequestTimeout(-1L);
}
overrideCarrierConfig(null);
}
+ @Test
+ public void testRequestTimeoutWithPresenceMechanism() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* OPTIONS */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare the test contact
+ Collection<Uri> contacts = new ArrayList<>();
+ contacts.add(sTestNumberUri);
+
+ // Setup the ImsService doesn't trigger any callbacks.
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ // It won't trigger any callbacks to the framework.
+ });
+
+ // Set the timeout for 3 seconds
+ setCapabilitiesRequestTimeout(3000L);
+
+ // Request capabilities
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ try {
+ // Verify the error code REQUEST_TIMEOUT is received
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+
+ // Verify the capabilities can still be received.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request the capabilities with the same contact again.
+ requestCapabilities(uceAdapter, contacts, callback);
+
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ completeQueue.clear();
+ capabilityQueue.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ subscribeRequestCount.set(0);
+ setCapabilitiesRequestTimeout(-1L);
+ }
+
+ overrideCarrierConfig(null);
+ }
@Test
public void testTimeoutToRequestCapabilitiesWithOptionsMechanism() throws Exception {
@@ -2457,22 +2584,40 @@
requestCapabilities(uceAdapter, contacts, callback);
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
// Verify that all the three contact's capabilities are received
RcsContactUceCapability capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact1SipScheme,
- capability);
- verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received for contact", capability);
+ resultCapList.add(capability);
+
+
+ // Verify the first contact capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability =
+ getContactCapability(resultCapList, contact1SipScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
REQUEST_RESULT_FOUND, true, true);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact2, capability);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- true, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, false);
- capability = waitForResult(capabilityQueue);
- assertNotNull("Capabilities were not received for contact: " + contact3, capability);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_FOUND,
- false, false);
+ // Verify the third contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2481,6 +2626,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -2492,16 +2638,34 @@
// Verify the contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1TelScheme, SOURCE_TYPE_NETWORK,
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1TelScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1TelScheme, SOURCE_TYPE_NETWORK,
REQUEST_RESULT_NOT_FOUND, false, false);
- capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
- capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2510,6 +2674,7 @@
errorRetryQueue.clear();
completeQueue.clear();
capabilityQueue.clear();
+ resultCapList.clear();
removeTestContactFromEab();
// Setup the callback that some of the contacts are terminated.
@@ -2533,17 +2698,35 @@
// Verify the first contact is found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact1SipScheme, SOURCE_TYPE_NETWORK,
- REQUEST_RESULT_FOUND, true, true);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
// Verify the reset contacts are not found.
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact2, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- true, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
capability = waitForResult(capabilityQueue);
- verifyCapabilityResult(capability, contact3, SOURCE_TYPE_NETWORK, REQUEST_RESULT_NOT_FOUND,
- false, false);
+ assertNotNull("Capabilities were not received", capability);
+ resultCapList.add(capability);
+
+ // Verify the first contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact1SipScheme);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact1SipScheme, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact2);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact2, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, true, false);
+
+ // Verify the second contact capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, contact3);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, contact3, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
// Verify the onCompleted is called
waitForResult(completeQueue);
@@ -2678,6 +2861,352 @@
overrideCarrierConfig(null);
}
+ @Test
+ public void testContactInThrottlingState() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+ // Reset the UCE device state.
+ removeUceRequestDisallowedStatus();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // Prepare the test contact
+ Collection<Uri> numbers = new ArrayList<>(1);
+ numbers.add(sTestNumberUri);
+
+ // Setup the network response is 408 Request Timeout.
+ int networkRespCode = 408;
+ String networkRespReason = "Request Timeout";
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode, networkRespReason);
+ });
+
+ // Request contact capabilities
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ // Verify the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verity the ImsService received the request.
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request the capabilities again with the same contact.
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the result.
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ subscribeRequestCount.set(0);
+ // reset the cache and throttling list
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ // Request availability.
+ requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ // Verify the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verity the ImsService received the request.
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("requestAvailability with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request availability again with the same contact.
+ requestAvailability(uceAdapter, sTestNumberUri, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ // Verify that the caller can received the capabilities callback.
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ // Verify the complete callback will be called.
+ waitForResult(completeQueue);
+ // Verify that the ImsService didn't received the request because the capabilities
+ // should be retrieved from the cache.
+ assertEquals(0, subscribeRequestCount.get());
+ } catch (Exception e) {
+ fail("testContactsInThrottlingState with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ subscribeRequestCount.set(0);
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
+ @Test
+ public void testRequestResultInconclusive() throws Exception {
+ if (!ImsUtils.shouldTestImsService()) {
+ return;
+ }
+ ImsManager imsManager = getContext().getSystemService(ImsManager.class);
+ RcsUceAdapter uceAdapter = imsManager.getImsRcsManager(sTestSub).getUceAdapter();
+ assertNotNull("UCE adapter should not be null!", uceAdapter);
+
+ // Remove the test contact capabilities
+ removeTestContactFromEab();
+ // Reset the UCE device state.
+ removeUceRequestDisallowedStatus();
+
+ // Connect to the ImsService
+ setupTestImsService(uceAdapter, true, true /* presence cap */, false /* options */);
+
+ TestRcsCapabilityExchangeImpl capabilityExchangeImpl = sServiceConnector
+ .getCarrierService().getRcsFeature().getRcsCapabilityExchangeImpl();
+
+ BlockingQueue<Integer> errorQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Long> errorRetryQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<Boolean> completeQueue = new LinkedBlockingQueue<>();
+ BlockingQueue<RcsContactUceCapability> capabilityQueue = new LinkedBlockingQueue<>();
+ RcsUceAdapter.CapabilitiesCallback callback = new RcsUceAdapter.CapabilitiesCallback() {
+ @Override
+ public void onCapabilitiesReceived(List<RcsContactUceCapability> capabilities) {
+ capabilities.forEach(c -> capabilityQueue.offer(c));
+ }
+
+ @Override
+ public void onComplete() {
+ completeQueue.offer(true);
+ }
+
+ @Override
+ public void onError(int errorCode, long retryAfterMilliseconds) {
+ errorQueue.offer(errorCode);
+ errorRetryQueue.offer(retryAfterMilliseconds);
+ }
+ };
+
+ // In the first round, prepare the test account
+ Collection<Uri> numbers = new ArrayList<>();
+ numbers.add(sTestNumberUri);
+
+ ArrayList<String> pidfXmlList = new ArrayList<>();
+ pidfXmlList.add(getPidfXmlData(sTestNumberUri, true, true));
+
+ // Setup the network response is 200 OK for the first request
+ final int networkRespCode200 = 200;
+ final String networkRespReasonOK = "OK";
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated("", 0L);
+ });
+
+ // Request contact capabilities
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the contact capability is received and the onCompleted is called.
+ try {
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestNumberUri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+ waitForResult(completeQueue);
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ }
+
+ // Request the second contacts and this time, the network respons is 408 Request Timeout
+ numbers.add(sTestContact2Uri);
+
+ final int networkRespCode408 = 408;
+ final String networkRespReasonTimeout = "Request Timeout";
+ AtomicInteger subscribeRequestCount = new AtomicInteger(0);
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ cb.onNetworkResponse(networkRespCode408, networkRespReasonTimeout);
+ });
+
+ // Request contact capabilities again with different contact
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ // Verify that the callback "onError" is called with the expected error code.
+ try {
+ assertEquals(RcsUceAdapter.ERROR_REQUEST_TIMEOUT, waitForIntResult(errorQueue));
+ assertEquals(0L, waitForLongResult(errorRetryQueue));
+ RcsContactUceCapability capability = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability);
+ verifyCapabilityResult(capability, sTestContact2Uri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+ assertTrue(subscribeRequestCount.get() > 0);
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ subscribeRequestCount.set(0);
+ }
+
+ // Request three contacts at a time in the third round.
+ numbers.add(sTestNumberUri);
+ numbers.add(sTestContact2Uri);
+ numbers.add(sTestContact3Uri);
+
+ // The first two contact capabilities can be retrieved from the cache. However, the third
+ // contact capabilities will be provided by the ImsService
+ pidfXmlList.add(getPidfXmlData(sTestContact3Uri, true, true));
+
+ capabilityExchangeImpl.setSubscribeOperation((uris, cb) -> {
+ subscribeRequestCount.incrementAndGet();
+ assertNotNull("The uris of capabilities request cannot be null", uris);
+ List<Uri> uriList = new ArrayList(uris);
+ // Verify that only uri need to be queried from the network
+ assertEquals(1, uriList.size());
+ assertEquals(sTestContact3Uri, uriList.get(0));
+ cb.onNetworkResponse(networkRespCode200, networkRespReasonOK);
+ cb.onNotifyCapabilitiesUpdate(pidfXmlList);
+ cb.onTerminated("", 0L);
+ });
+
+ requestCapabilities(uceAdapter, numbers, callback);
+
+ List<RcsContactUceCapability> resultCapList = new ArrayList<>();
+
+ // Verify that the contact capability is received and the onCompleted is called.
+ try {
+ RcsContactUceCapability capability1 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability1);
+ resultCapList.add(capability1);
+
+ RcsContactUceCapability capability2 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability2);
+ resultCapList.add(capability2);
+
+ RcsContactUceCapability capability3 = waitForResult(capabilityQueue);
+ assertNotNull("Capabilities were not received", capability3);
+ resultCapList.add(capability3);
+
+ // Verify contact1's capabilities from the received capabilities list
+ RcsContactUceCapability resultCapability =
+ getContactCapability(resultCapList, sTestNumberUri);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, sTestNumberUri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify contact2's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, sTestContact2Uri);
+ assertNotNull("Cannot find the contact", resultCapability);
+ verifyCapabilityResult(resultCapability, sTestContact2Uri, SOURCE_TYPE_CACHED,
+ REQUEST_RESULT_NOT_FOUND, false, false);
+
+ // Verify contact3's capabilities from the received capabilities list
+ resultCapability = getContactCapability(resultCapList, sTestContact3Uri);
+ assertNotNull("Cannot find the contact", sTestContact3Uri);
+ verifyCapabilityResult(resultCapability, sTestContact3Uri, SOURCE_TYPE_NETWORK,
+ REQUEST_RESULT_FOUND, true, true);
+
+ // Verify the onCompleted is called
+ waitForResult(completeQueue);
+
+ } catch (Exception e) {
+ fail("testRequestResultInconclusive with command error failed: " + e);
+ } finally {
+ errorQueue.clear();
+ errorRetryQueue.clear();
+ capabilityQueue.clear();
+ completeQueue.clear();
+ numbers.clear();
+ pidfXmlList.clear();
+ removeTestContactFromEab();
+ removeUceRequestDisallowedStatus();
+ }
+
+ overrideCarrierConfig(null);
+ }
+
private void setupTestImsService(RcsUceAdapter uceAdapter, boolean presencePublishEnabled,
boolean presenceCapExchangeEnabled, boolean sipOptionsEnabled) throws Exception {
// Trigger carrier config changed
diff --git a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
index ecff1a2..2fa4399 100644
--- a/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
+++ b/tests/tests/voiceRecognition/src/android/voicerecognition/cts/RecognitionServiceMicIndicatorTest.java
@@ -249,14 +249,7 @@
}
Log.i(TAG, "Retrieved dialog description " + dialogDescription);
- if (isCar()) {
- // Make sure Voice recognizer's app label is present in dialog.
- assertWithMessage(
- "Voice recognition service can blame the calling app name " + APP_LABEL
- + ", but does not find it.")
- .that(dialogDescription)
- .contains(APP_LABEL);
- } else if (trustVoiceService) {
+ if (trustVoiceService) {
// Check trust recognizer can blame calling apmic permission
assertWithMessage(
"Trusted voice recognition service can blame the calling app name " + APP_LABEL
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
index 4c45564..ec76300 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
@@ -70,6 +70,7 @@
import java.util.List;
import java.util.Map;
+import java.util.Optional;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
@@ -179,11 +180,15 @@
@Test
public void testParcelingAndUnparceling_multiplePackages() {
+ Optional<String> otherPackageName = getAnotherPackageName();
+ if (!otherPackageName.isPresent()) return;
RemoteCollectionItems items = new RemoteCollectionItems.Builder()
.setHasStableIds(true)
.setViewTypeCount(10)
.addItem(3 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline))
- .addItem(5 /* id */, new RemoteViews(getOtherPackage(), R.layout.textview_gravity))
+ .addItem(
+ 5 /* id */,
+ new RemoteViews(otherPackageName.get(), R.layout.textview_gravity))
.build();
RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
@@ -200,7 +205,7 @@
assertNotNull(unparceled.getItemView(0).mApplication);
assertNotNull(unparceled.getItemView(1).mApplication);
assertEquals(PACKAGE_NAME, unparceled.getItemView(0).mApplication.packageName);
- assertEquals(getOtherPackage(), unparceled.getItemView(1).mApplication.packageName);
+ assertEquals(otherPackageName.get(), unparceled.getItemView(1).mApplication.packageName);
}
@Test
@@ -316,8 +321,10 @@
@Test
public void testSerializationSize_largeCollection_multiPackage() {
+ Optional<String> otherPackageName = getAnotherPackageName();
+ if (!otherPackageName.isPresent()) return;
RemoteCollectionItems items =
- createSampleMultiPackageCollectionItems(/* size= */ 100, getOtherPackage());
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackageName.get());
int dataSize = parcelAndRun(items, Parcel::dataSize);
@@ -356,15 +363,16 @@
@Test
public void testSerializationSize_largeCollectionInLandPortRemoteViews_multiPackage() {
- String otherPackage = getOtherPackage();
+ Optional<String> otherPackage = getAnotherPackageName();
+ if (!otherPackage.isPresent()) return;
RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
landscape.setRemoteAdapter(
R.id.listview_default,
- createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage));
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
landscape.setRemoteAdapter(
R.id.listview_default,
- createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage));
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
@@ -399,7 +407,8 @@
@Test
public void testSerializationSize_largeCollectionInSizedRemoteViews_multiPackage() {
- String otherPackage = getOtherPackage();
+ Optional<String> otherPackage = getAnotherPackageName();
+ if (!otherPackage.isPresent()) return;
List<SizeF> sizes =
Lists.newArrayList(
new SizeF(50, 50),
@@ -409,7 +418,8 @@
Map<SizeF, RemoteViews> sizeToRemoteViews =
sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
RemoteCollectionItems items =
- createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage);
+ createSampleMultiPackageCollectionItems(
+ /* size= */ 100, otherPackage.get());
RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
views.setRemoteAdapter(R.id.listview_default, items);
return views;
@@ -899,15 +909,12 @@
* Returns a different package on the device that can be used for testing multi-package
* collections.
*/
- private String getOtherPackage() {
+ private Optional<String> getAnotherPackageName() {
return mActivity.getPackageManager()
.getInstalledApplications(/* flags= */ 0)
.stream()
.filter(info -> !PACKAGE_NAME.equals(info.packageName))
.findFirst()
- .map(info -> info.packageName)
- .orElseThrow(
- () -> new AssertionError("Could not find any other applications to test "
- + "with"));
+ .map(info -> info.packageName);
}
}