Merge "Move adjacent tasks forward together to ensure occluding state" into sc-v2-dev
diff --git a/apps/CtsVerifier/res/values/strings.xml b/apps/CtsVerifier/res/values/strings.xml
index be3bff9..0044efa 100644
--- a/apps/CtsVerifier/res/values/strings.xml
+++ b/apps/CtsVerifier/res/values/strings.xml
@@ -3642,12 +3642,25 @@
Please make sure you can connect to it. The test is successful if the config is editable
and can be connected to.
</string>
+ <string name="device_owner_wifi_config_unlocked_modification_test_info" product="automotive">
+ Please press the button to ensure WiFi config lockdown is NOT in effect. Then go to
+ Settings > WiFi and see if the CTSVerifier created WiFi configuration is editable
+ (it\'s ok if it\'s not editable, but then take note so the next test can be skipped).
+ Please make sure you can connect to it. The test is successful if the config can be
+ connected to.
+ </string>
<string name="device_owner_wifi_config_locked_modification_test">Locked config is not modifiable in Settings</string>
<string name="device_owner_wifi_config_locked_modification_test_info">
Please press the button to ensure WiFi config lockdown is in effect. Then go to
Settings > WiFi and see if the CTSVerifier created WiFi configuration can NOT be edited
or removed. The test is successful if the config is NOT modifiable.
</string>
+ <string name="device_owner_wifi_config_locked_modification_test_info" product="automotive">
+ NOTE: if the WiFi was not editable in the previous step, please skip this test.
+ Please press the button to ensure WiFi config lockdown is in effect. Then go to
+ Settings > WiFi and see if the CTSVerifier created WiFi configuration can NOT be edited
+ or removed. The test is successful if the config is NOT modifiable.
+ </string>
<string name="device_owner_wifi_config_locked_connection_test">Locked config can be connected to</string>
<string name="device_owner_wifi_config_locked_connection_test_info">
Please press the button to ensure WiFi config lockdown is in effect. Then go to
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
index c9f124d..e7bced9 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/features/FeatureUtil.java
@@ -80,6 +80,13 @@
}
/**
+ * Checks whether the device supports file transfer.
+ */
+ public static boolean isUsbFileTransferSupported(Context context) {
+ return !isWatchOrAutomotive(context);
+ }
+
+ /**
* Checks whether the device is watch .
*/
private static boolean isWatch(Context context) {
@@ -118,5 +125,4 @@
public static boolean isKeyguardShownWhenUserDoesntHaveCredentials(Context context) {
return !isAutomotive(context);
}
-
}
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..05230ea 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);
@@ -282,6 +282,8 @@
case COMMAND_SET_GLOBAL_SETTING: {
final String setting = intent.getStringExtra(EXTRA_SETTING);
final String value = intent.getStringExtra(EXTRA_VALUE);
+ Log.d(TAG, "Setting global property '" + setting + "' to '" + value
+ + "' using " + mDpm);
mDpm.setGlobalSetting(mAdmin, setting, value);
} break;
case COMMAND_REMOVE_DEVICE_OWNER: {
@@ -380,6 +382,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 +486,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/DeviceOwnerPositiveTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
index d444b38..44fb73e 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerPositiveTestActivity.java
@@ -34,6 +34,7 @@
import android.view.View;
import com.android.bedstead.dpmwrapper.TestAppSystemServiceFactory;
+import com.android.compatibility.common.util.CddTest;
import com.android.cts.verifier.ArrayTestListAdapter;
import com.android.cts.verifier.IntentDrivenTestActivity.ButtonInfo;
import com.android.cts.verifier.PassFailButtons;
@@ -49,6 +50,7 @@
* adb shell dpm set-device-owner
* 'com.android.cts.verifier/com.android.cts.verifier.managedprovisioning.DeviceAdminTestReceiver'
*/
+@CddTest(requirement="7.7")
public class DeviceOwnerPositiveTestActivity extends PassFailButtons.TestListActivity {
private static final String TAG = "DeviceOwnerPositiveTestActivity";
@@ -353,8 +355,7 @@
}
// DISALLOW_USB_FILE_TRANSFER
- // TODO(b/189282625): replace FEATURE_WATCH with a more specific feature
- if (!packageManager.hasSystemFeature(PackageManager.FEATURE_WATCH)) {
+ if (FeatureUtil.isUsbFileTransferSupported(this)) {
adapter.add(createInteractiveTestItem(this, DISALLOW_USB_FILE_TRANSFER_ID,
R.string.device_owner_disallow_usb_file_transfer_test,
R.string.device_owner_disallow_usb_file_transfer_test_info,
diff --git a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
index 589e261..4a4eae4 100644
--- a/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
+++ b/apps/CtsVerifier/src/com/android/cts/verifier/managedprovisioning/DeviceOwnerRequestingBugreportTestActivity.java
@@ -80,41 +80,52 @@
String action = getIntent().getAction();
Log.d(TAG, "onCreate(): action = " + action);
- switch (action) {
- case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT: {
- DevicePolicyManager dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
- DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
- if (dpm.isDeviceOwnerApp(getPackageName())) {
- TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- null, null);
- } else {
- TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- getString(R.string.device_owner_incorrect_device_owner, myUserId()),
- null);
- }
- finish();
- return;
- } case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT: {
- DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
- if (dpm.isProfileOwnerApp(getPackageName())) {
- TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- null, null);
- } else {
- TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- getString(R.string.device_owner_incorrect_profile_owner, myUserId()),
- null);
- }
- finish();
- return;
- } case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT: {
- DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
- if (dpm.isAffiliatedUser()) {
- TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- null, null);
- } else {
- TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
- getString(R.string.device_owner_user_not_affiliated, myUserId()), null);
- }
+ boolean validAction = true;
+ if (action != null) {
+ DevicePolicyManager dpm = null;
+ switch (action) {
+ case ACTION_CHECK_DEVICE_OWNER_FOR_REQUESTING_BUGREPORT:
+ dpm = TestAppSystemServiceFactory.getDevicePolicyManager(this,
+ DeviceAdminTestReceiver.class, /* forDeviceOwner= */ true);
+ if (dpm.isDeviceOwnerApp(getPackageName())) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_incorrect_device_owner, myUserId()),
+ null);
+ }
+ break;
+ case ACTION_CHECK_PROFILE_OWNER_FOR_REQUESTING_BUGREPORT:
+ dpm = getSystemService(DevicePolicyManager.class);
+ if (dpm.isProfileOwnerApp(getPackageName())) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_incorrect_profile_owner,
+ myUserId()),
+ null);
+ }
+ break;
+ case ACTION_CHECK_CURRENT_USER_AFFILIATED_FOR_REQUESTING_BUGREPORT:
+ dpm = getSystemService(DevicePolicyManager.class);
+ if (dpm.isAffiliatedUser()) {
+ TestResult.setPassedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ null, null);
+ } else {
+ TestResult.setFailedResult(this, getIntent().getStringExtra(EXTRA_TEST_ID),
+ getString(R.string.device_owner_user_not_affiliated, myUserId()),
+ null);
+ }
+ break;
+ default:
+ Log.w(TAG, "invalid action on intent: " + action);
+ validAction = false;
+ break;
+ }
+ if (validAction) {
+ Log.d(TAG, "Finishing activity");
finish();
return;
}
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/activitycontext/src/main/java/com/android/activitycontext/ActivityContext.java b/common/device-side/bedstead/activitycontext/src/main/java/com/android/activitycontext/ActivityContext.java
index 4f63260..d892597 100644
--- a/common/device-side/bedstead/activitycontext/src/main/java/com/android/activitycontext/ActivityContext.java
+++ b/common/device-side/bedstead/activitycontext/src/main/java/com/android/activitycontext/ActivityContext.java
@@ -27,10 +27,14 @@
import androidx.test.platform.app.InstrumentationRegistry;
+import com.android.bedstead.nene.TestApis;
+import com.android.bedstead.nene.exceptions.NeneException;
+import com.android.bedstead.nene.users.UserReference;
import com.android.compatibility.common.util.ShellIdentityUtils.QuadFunction;
import com.android.compatibility.common.util.ShellIdentityUtils.TriFunction;
import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -68,45 +72,58 @@
if (runnable == null) {
throw new NullPointerException();
}
- Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- if (!instrumentation.getContext().getPackageName().equals(
- instrumentation.getTargetContext().getPackageName())) {
- throw new IllegalStateException("ActivityContext can only be used in test apps which"
- + " instrument themselves. Consider ActivityScenario for this case.");
- }
+ // As we show an Activity we must be in the foreground
+ UserReference currentUser = TestApis.users().current();
+ try {
+ TestApis.users().instrumented().switchTo();
- synchronized (ActivityContext.class) {
- sRunnable = runnable;
+ Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- sLatch = new CountDownLatch(1);
- sReturnValue = null;
- sThrowValue = null;
-
- Intent intent = new Intent();
- intent.setClass(sContext, ActivityContext.class);
- intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
- sContext.startActivity(intent);
- }
-
- sLatch.await();
-
- synchronized (ActivityContext.class) {
- sRunnable = null;
-
- if (sThrowValue != null) {
- if (sThrowValue instanceof RuntimeException) {
- throw (RuntimeException) sThrowValue;
- }
-
- if (sThrowValue instanceof Error) {
- throw (Error) sThrowValue;
- }
-
- throw new IllegalStateException("Invalid value for sThrowValue");
+ if (!instrumentation.getContext().getPackageName().equals(
+ instrumentation.getTargetContext().getPackageName())) {
+ throw new IllegalStateException(
+ "ActivityContext can only be used in test apps which instrument themselves."
+ + " Consider ActivityScenario for this case.");
}
- return (E) sReturnValue;
+ synchronized (ActivityContext.class) {
+ sRunnable = runnable;
+
+ sLatch = new CountDownLatch(1);
+ sReturnValue = null;
+ sThrowValue = null;
+
+ Intent intent = new Intent();
+ intent.setClass(sContext, ActivityContext.class);
+ intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
+ sContext.startActivity(intent);
+ }
+
+ if (!sLatch.await(5, TimeUnit.MINUTES)) {
+ throw new NeneException("Timed out while waiting for lambda with context to"
+ + " complete.");
+ }
+
+ synchronized (ActivityContext.class) {
+ sRunnable = null;
+
+ if (sThrowValue != null) {
+ if (sThrowValue instanceof RuntimeException) {
+ throw (RuntimeException) sThrowValue;
+ }
+
+ if (sThrowValue instanceof Error) {
+ throw (Error) sThrowValue;
+ }
+
+ throw new IllegalStateException("Invalid value for sThrowValue");
+ }
+
+ return (E) sReturnValue;
+ }
+ } finally {
+ currentUser.switchTo();
}
}
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 ba6004f..75cf62b 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,7 +60,9 @@
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.EnsureHasNoDelegate;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoProfileOwner;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasProfileOwner;
@@ -85,7 +87,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 +352,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;
@@ -356,6 +373,13 @@
continue;
}
+ if (annotation instanceof EnsureHasNoDelegate) {
+ EnsureHasNoDelegate ensureHasNoDelegateAnnotation =
+ (EnsureHasNoDelegate) annotation;
+ ensureHasNoDelegate(ensureHasNoDelegateAnnotation.admin());
+ continue;
+ }
+
if (annotation instanceof EnsureHasNoDeviceOwner) {
ensureHasNoDeviceOwner();
continue;
@@ -602,6 +626,9 @@
Tags.clearTags();
Tags.addTag(Tags.USES_DEVICESTATE);
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ Tags.addTag(Tags.INSTANT_APP);
+ }
try {
TestApis.users().setStopBgUsersOnSwitch(STOP_USER_ON_SWITCH_FALSE);
@@ -875,7 +902,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<>();
@@ -1288,9 +1315,12 @@
broadcastReceiver.unregisterQuietly();
}
mRegisteredBroadcastReceivers.clear();
- mPrimaryDpc = null;
+ mPrimaryPolicyManager = null;
}
+ private Set<TestAppInstance> mInstalledTestApps = new HashSet<>();
+ private Set<TestAppInstance> mUninstalledTestApps = new HashSet<>();
+
private void teardownShareableState() {
if (mOriginalSwitchedUser != null) {
if (!mOriginalSwitchedUser.exists()) {
@@ -1350,6 +1380,16 @@
}
mRemovedUsers.clear();
+
+ for (TestAppInstance installedTestApp : mInstalledTestApps) {
+ installedTestApp.uninstall();
+ }
+ mInstalledTestApps.clear();
+
+ for (TestAppInstance uninstalledTestApp : mUninstalledTestApps) {
+ uninstalledTestApp.testApp().install(uninstalledTestApp.user());
+ }
+ mUninstalledTestApps.clear();
}
private UserReference createProfile(
@@ -1391,16 +1431,102 @@
}
}
+ 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 void ensureHasNoDelegate(EnsureHasNoDelegate.AdminType adminType) {
+ if (adminType == EnsureHasNoDelegate.AdminType.ANY) {
+ for (UserReference user : TestApis.users().all()) {
+ ensureTestAppNotInstalled(RemoteDelegate.sTestApp, user);
+ }
+ return;
+ }
+ RemotePolicyManager dpc =
+ adminType == EnsureHasNoDelegate.AdminType.PRIMARY ? mPrimaryPolicyManager
+ : adminType == EnsureHasNoDelegate.AdminType.DEVICE_OWNER ? deviceOwner()
+ : adminType == EnsureHasNoDelegate.AdminType.PROFILE_OWNER ? profileOwner() : null;
+ if (dpc == null) {
+ throw new IllegalStateException("Unknown Admin Type " + adminType);
+ }
+
+ ensureTestAppNotInstalled(RemoteDelegate.sTestApp, dpc.user());
+ }
+
+ 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) {
+ if (TestApis.packages().find(testApp.packageName()).installedOnUser(user)) {
+ return;
+ }
+
+ mInstalledTestApps.add(testApp.install(user));
+ }
+
+ private void ensureTestAppNotInstalled(TestApp testApp, UserReference user) {
+ if (!TestApis.packages().find(testApp.packageName()).installedOnUser(user)) {
+ return;
+ }
+
+ TestAppInstance instance = testApp.instance(user);
+
+ if (mInstalledTestApps.contains(instance)) {
+ mInstalledTestApps.remove(instance);
+ } else {
+ mUninstalledTestApps.add(instance);
+ }
+
+ testApp.uninstall(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
@@ -1452,7 +1578,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mDeviceOwner;
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mDeviceOwner);
}
RemoteDpc.forDevicePolicyController(mDeviceOwner)
@@ -1468,7 +1594,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");
}
@@ -1498,7 +1625,7 @@
}
if (isPrimary) {
- mPrimaryDpc = mProfileOwners.get(user);
+ mPrimaryPolicyManager = RemoteDpc.forDevicePolicyController(mProfileOwners.get(user));
}
if (affiliationIds != null) {
@@ -1667,20 +1794,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/RequireRunNotOnSecondaryUser.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireRunNotOnSecondaryUser.java
new file mode 100644
index 0000000..446bb85
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/RequireRunNotOnSecondaryUser.java
@@ -0,0 +1,58 @@
+/*
+ * 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 static com.android.bedstead.harrier.annotations.AnnotationRunPrecedence.EARLY;
+
+import com.android.bedstead.harrier.DeviceState;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Mark that a test method should run on a non-secondary user.
+ *
+ * <p>Your test configuration should be such that this test is only run where a non-secondary user
+ * is created and the test is being run on that user.
+ *
+ * <p>Optionally, you can guarantee that these methods do not run on a secondary user by
+ * using {@link DeviceState}.
+ *
+ * <p>This annotation by default opts a test into multi-user presubmit. New tests should also be
+ * annotated {@link Postsubmit} until they are shown to meet the multi-user presubmit
+ * requirements.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+// To ensure that the test doesn't run on the secondary user we require that the test run on
+// the primary user to ensure consistent behaviour.
+@RequireRunOnPrimaryUser
+public @interface RequireRunNotOnSecondaryUser {
+ /**
+ * 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 EARLY;
+}
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..241a5ca
--- /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 value();
+}
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..c581561
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasDelegate.java
@@ -0,0 +1,77 @@
+/*
+ * 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 {
+
+ int ENSURE_HAS_DELEGATE_WEIGHT = DO_PO_WEIGHT + 1; // Should run after setting DO/PO
+
+ 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 ENSURE_HAS_DELEGATE_WEIGHT;
+}
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/EnsureHasNoDelegate.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDelegate.java
new file mode 100644
index 0000000..c0516f3
--- /dev/null
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/annotations/enterprise/EnsureHasNoDelegate.java
@@ -0,0 +1,68 @@
+/*
+ * 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.EnsureHasDelegate.ENSURE_HAS_DELEGATE_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 does not delegate 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.
+ */
+@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface EnsureHasNoDelegate {
+
+ enum AdminType {
+ DEVICE_OWNER,
+ PROFILE_OWNER,
+ PRIMARY,
+ ANY
+ }
+
+
+ /**
+ * The admin that should not delegate this scope.
+ *
+ * <p>Defaults to any admin
+ *
+ * <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() default AdminType.ANY;
+
+ /**
+ * 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 ENSURE_HAS_DELEGATE_WEIGHT + 1; // Should run after setting delegate
+}
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 f484370..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
@@ -80,8 +80,6 @@
int APPLIES_TO_AFFILIATED_CHILD_PROFILES = 1 << 4;
/** A policy that applies to the parent of the profile of the package which applied the policy. */
int APPLIES_TO_PARENT = 1 << 5;
- /** A policy that applies to the parent of the profile of the package which applied the policy if that profile is a COPE profile. */
- int APPLIES_TO_COPE_PARENT = 1 << 6;
/** A policy that applies to affiliated or unaffiliate profiles of the package which applied the policy. */
int APPLIES_TO_CHILD_PROFILES =
@@ -97,12 +95,16 @@
// Applied by
/** A policy that can be applied by a device owner. */
- int APPLIED_BY_DEVICE_OWNER = 1 << 7;
+ int APPLIED_BY_DEVICE_OWNER = 1 << 6;
/** A policy that can be applied by a profile owner of an unaffiliated profile. */
- int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+ int APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE = 1 << 7;
/** A policy that can be applied by a profile owner of an affiliated profile */
- int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 9;
- /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile. */
+ int APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE = 1 << 8;
+ /** A policy that can be applied by a profile owner of a cope profile */
+ int APPLIED_BY_COPE_PROFILE_OWNER = 1 << 9;
+
+ /** A policy that can be applied by a profile owner of an affiliated or unaffiliated profile.
+ * This does not include cope profiles. */
int APPLIED_BY_PROFILE_OWNER_PROFILE =
APPLIED_BY_UNAFFILIATED_PROFILE_OWNER_PROFILE
| APPLIED_BY_AFFILIATED_PROFILE_OWNER_PROFILE;
@@ -164,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 {};
@@ -184,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/DeprecatedPasswordAPIs.java b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
similarity index 62%
rename from common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
rename to common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
index 5eb0053..379b071 100644
--- a/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/DeprecatedPasswordAPIs.java
+++ b/common/device-side/bedstead/harrier/src/main/java/com/android/bedstead/harrier/policies/ApplicationRestrictionsManagingPackage.java
@@ -18,14 +18,24 @@
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 test cases testing password management APIs that are deprecated and not supported in
- * some platforms.
+ * Policy for application restrictions.
+ *
+ * <p>This is used by the method
+ * {@link DevicePolicyManager#setApplicationRestrictionsManagingPackage(ComponentName, String, Bundle)}
*/
-@EnterprisePolicy(dpc = APPLIED_BY_DEVICE_OWNER | APPLIED_BY_PROFILE_OWNER | APPLIES_TO_OWN_USER)
-public final class DeprecatedPasswordAPIs {
+@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 d4c8eb8..ba3c2ef 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;
@@ -37,6 +41,8 @@
import android.app.ActivityManager;
import android.os.Build;
+import android.os.Bundle;
+import android.platform.test.annotations.AppModeFull;
import com.android.bedstead.harrier.annotations.EnsureDoesNotHavePermission;
import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser;
@@ -59,6 +65,7 @@
import com.android.bedstead.harrier.annotations.RequireNotLowRamDevice;
import com.android.bedstead.harrier.annotations.RequirePackageInstalled;
import com.android.bedstead.harrier.annotations.RequirePackageNotInstalled;
+import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnTvProfile;
@@ -66,6 +73,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;
@@ -81,6 +89,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;
@@ -282,6 +292,7 @@
@Test
@EnsureDoesNotHavePermission(TEST_PERMISSION_1)
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureDoesNotHavePermission_permissionIsDenied() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -289,6 +300,7 @@
@Test
@EnsureDoesNotHavePermission({TEST_PERMISSION_1, TEST_PERMISSION_2})
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureDoesNotHavePermission_multiplePermissions_permissionsAreDenied() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_DENIED);
@@ -301,6 +313,7 @@
@EnsureDoesNotHavePermission(TEST_PERMISSION_2)
@RequireSdkVersion(min = Build.VERSION_CODES.R,
reason = "Used permissions not available prior to R")
+ @AppModeFull // withoutPermission does not work on instant apps
public void ensureHasPermissionAndDoesNotHavePermission_permissionsAreCorrect() {
assertThat(TestApis.context().instrumentedContext()
.checkSelfPermission(TEST_PERMISSION_1)).isEqualTo(PERMISSION_GRANTED);
@@ -585,6 +598,19 @@
}
@Test
+ @RequireRunNotOnSecondaryUser
+ public void requireRunNotOnSecondaryUser_currentUserIsNotSecondary() {
+ assertThat(TestApis.users().current().type().name()).isNotEqualTo(SECONDARY_USER_TYPE_NAME);
+ }
+
+ @Test
+ @RequireRunNotOnSecondaryUser
+ public void requireRunNotOnSecondaryUser_instrumentedUserIsNotSecondary() {
+ assertThat(TestApis.users().instrumented().type().name())
+ .isNotEqualTo(SECONDARY_USER_TYPE_NAME);
+ }
+
+ @Test
@EnsureHasSecondaryUser(switchedToUser = FALSE) // We don't test the default as it's ANY
public void ensureHasUser_specifyIsNotSwitchedToUser_isNotCurrentUser() {
assertThat(TestApis.users().current()).isNotEqualTo(sDeviceState.secondaryUser());
@@ -624,7 +650,7 @@
@IncludeRunOnBackgroundDeviceOwnerUser
public void includeRunOnBackgroundDeviceOwnerUserAnnotation_isRunningOnDeviceOwnerUser() {
assertThat(TestApis.users().instrumented())
- .isEqualTo(sDeviceState.dpc().devicePolicyController().user());
+ .isEqualTo(sDeviceState.dpc().user());
}
@Test
@@ -702,4 +728,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/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
index 0259477..2d8d21d 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/DevicePolicy.java
@@ -209,7 +209,7 @@
*/
private void setDeviceOwnerOnly(DevicePolicyManager devicePolicyManager,
ComponentName component, String name, int deviceOwnerUserId) {
- if (Versions.meetsMinimumSdkVersionRequirement(Versions.S_V2)) {
+ if (Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S_V2)) {
devicePolicyManager.setDeviceOwnerOnly(component, name, deviceOwnerUserId);
} else {
devicePolicyManager.setDeviceOwner(component, name, deviceOwnerUserId);
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
index d8b557f..e475d25 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/devicepolicy/ProfileOwner.java
@@ -47,7 +47,8 @@
@Override
public void remove() {
- if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
+ if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)
+ || TestApis.packages().instrumented().isInstantApp()) {
removePreS();
return;
}
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
index 801a068..3b76374 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Package.java
@@ -516,6 +516,11 @@
PackageInfo packageInfo = packageInfoFromAnyUser(GET_PERMISSIONS);
if (packageInfo == null) {
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ Log.i(LOG_TAG, "Tried to get requestedPermissions for "
+ + mPackageName + " but can't on instant apps");
+ return new HashSet<>();
+ }
throw new NeneException("Error getting requestedPermissions, does not exist");
}
@@ -790,6 +795,25 @@
return (appInfo.flags & FLAG_SYSTEM) > 0;
}
+ @Experimental
+ public boolean isInstantApp() {
+ return sPackageManager.isInstantApp(mPackageName);
+ }
+
+ /**
+ * Gets the shared user id of the package.
+ */
+ @Experimental
+ public String sharedUserId() {
+ PackageInfo packageInfo = packageInfoFromAnyUser(/* flags= */ 0);
+
+ if (packageInfo == null) {
+ throw new NeneException("Error getting sharedUserId, does not exist");
+ }
+
+ return packageInfo.sharedUserId;
+ }
+
private static final class ProcessInfo {
final String mPackageName;
final int mPid;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
index a6ad211..6169224 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/packages/Packages.java
@@ -58,6 +58,8 @@
import com.android.bedstead.nene.utils.Versions;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
+import org.junit.AssumptionViolatedException;
+
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
@@ -196,6 +198,15 @@
throw new NullPointerException();
}
+ if (!Versions.meetsMinimumSdkVersionRequirement(R)
+ || TestApis.packages().instrumented().isInstantApp()) {
+ AdbPackageParser.ParseResult packages = parseDumpsys();
+ return packages.mPackages.values().stream()
+ .filter(p -> p.installedOnUsers().contains(user))
+ .map(p -> find(p.packageName()))
+ .collect(Collectors.toSet());
+ }
+
if (user.equals(TestApis.users().instrumented())) {
return TestApis.context().instrumentedContext().getPackageManager()
.getInstalledPackages(/* flags= */ 0)
@@ -204,14 +215,6 @@
.collect(Collectors.toSet());
}
- if (!Versions.meetsMinimumSdkVersionRequirement(R)) {
- AdbPackageParser.ParseResult packages = parseDumpsys();
- return packages.mPackages.values().stream()
- .filter(p -> p.installedOnUsers().contains(user))
- .map(p -> find(p.packageName()))
- .collect(Collectors.toSet());
- }
-
try (PermissionContext p = TestApis.permissions()
.withPermission(INTERACT_ACROSS_USERS_FULL)) {
return TestApis.context().androidContextAsUser(user).getPackageManager()
@@ -325,8 +328,8 @@
*
* <p>If the package is marked testOnly, it will still be installed.
*
- * <p>On versions of Android prior to Q, this will return null. On other versions it will return
- * the installed package.
+ * <p>On versions of Android prior to Q, or when running as an instant app, this will return
+ * null. On other versions it will return the installed package.
*/
@Nullable
public Package install(UserReference user, byte[] apkFile) {
@@ -343,6 +346,31 @@
+ "(Trying to install into user " + user + ")");
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // We should install using stdin with the byte array
+ try {
+ ShellCommand.builderForUser(user, "pm install")
+ .addOperand("-t") // Allow installing test apks
+ .addOperand("-r") // Replace existing apps
+ .addOption("-S", apkFile.length) // Install from stdin
+ .writeToStdIn(apkFile)
+ .validate(ShellCommandUtils::startsWithSuccess)
+ .execute();
+ } catch (AdbException e) {
+ throw new NeneException("Error installing from instant app", e);
+ }
+
+ // Arbitrary sleep because the shell command doesn't block and we can't listen for
+ // the broadcast (instant app)
+ try {
+ Thread.sleep(10_000);
+ } catch (InterruptedException e) {
+ throw new NeneException("Interrupted while waiting for install", e);
+ }
+
+ return null;
+ }
+
// This is not inside the try because if the install is unsuccessful we don't want to await
// the broadcast
BlockingBroadcastReceiver broadcastReceiver =
@@ -371,7 +399,8 @@
try (BlockingIntentSender intentSender = BlockingIntentSender.create()) {
try (PermissionContext p =
- TestApis.permissions().withPermission(INSTALL_PACKAGES)) {
+ TestApis.permissions().withPermission(
+ INSTALL_PACKAGES, INSTALL_TEST_ONLY_PACKAGE)) {
session.commit(intentSender.intentSender());
session.close();
@@ -387,7 +416,6 @@
}
}
}
-
return waitForPackageAddedBroadcast(broadcastReceiver);
} catch (IOException e) {
throw new NeneException("Could not install package", e);
@@ -404,6 +432,11 @@
File outputDir = Environment.getExternalStorageDirectory();
File outputFile = null;
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // We can't manage files as an instant app, so we must skip this test
+ throw new AssumptionViolatedException("Cannot install packages as instant app");
+ }
+
try (PermissionContext p =
TestApis.permissions().withPermissionOnVersion(R, MANAGE_EXTERNAL_STORAGE)) {
// TODO(b/202705721): Replace this with fixed name
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
index 3442035..2336fd0 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/PermissionContextImpl.java
@@ -16,6 +16,7 @@
package com.android.bedstead.nene.permissions;
+import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.utils.Versions;
@@ -97,6 +98,11 @@
}
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ throw new NeneException(
+ "Tests which use withoutPermission must not run as instant apps");
+ }
+
mDeniedPermissions.addAll(Arrays.asList(permissions));
mPermissions.applyPermissions();
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
index 2806d25..fa797bb 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/permissions/Permissions.java
@@ -214,6 +214,15 @@
return;
}
+ if (TestApis.packages().instrumented().isInstantApp()) {
+ // Instant Apps aren't able to know the permissions of shell so we can't know if we can
+ // adopt it - we'll assume we can adopt and log
+ Log.i(LOG_TAG,
+ "Adopting all shell permissions as can't check shell: " + mPermissionContexts);
+ ShellCommandUtils.uiAutomation().adoptShellPermissionIdentity();
+ return;
+ }
+
if (SUPPORTS_ADOPT_SHELL_PERMISSIONS) {
ShellCommandUtils.uiAutomation().dropShellPermissionIdentity();
}
@@ -344,6 +353,16 @@
applyPermissions();
}
+ /**
+ * Returns all of the permissions which are currently able to be used.
+ */
+ public Set<String> usablePermissions() {
+ Set<String> usablePermissions = new HashSet<>();
+ usablePermissions.addAll(mShellPermissions);
+ usablePermissions.addAll(mInstrumentedRequestedPermissions);
+ return usablePermissions;
+ }
+
private void removePermissionContextsUntilCanApply() {
try {
mPermissionContexts.remove(mPermissionContexts.size() - 1);
@@ -373,6 +392,7 @@
mExistingPermissions = ShellCommandUtils.uiAutomation().getAdoptedShellPermissions();
}
+ @SuppressWarnings("NewApi")
private void restoreExistingPermissions() {
if (!Versions.meetsMinimumSdkVersionRequirement(Build.VERSION_CODES.S)) {
return;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/UserReference.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/UserReference.java
index c5b5b89..4dcd12f 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/UserReference.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/UserReference.java
@@ -161,7 +161,7 @@
Poll.forValue("User running", this::isRunning)
.toBeEqualTo(false)
// TODO(b/203630556): Replace stopping with something faster
- .timeout(Duration.ofMinutes(4))
+ .timeout(Duration.ofMinutes(10))
.errorOnFail()
.await();
} catch (AdbException e) {
@@ -175,6 +175,11 @@
* Make the user the foreground user.
*/
public UserReference switchTo() {
+ if (TestApis.users().current().equals(this)) {
+ // Already switched to
+ return this;
+ }
+
// This is created outside of the try because we don't want to wait for the broadcast
// on versions less than R
BlockingBroadcastReceiver broadcastReceiver =
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
index 0b11f7a..8813a46 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/users/Users.java
@@ -21,12 +21,12 @@
import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
import static android.os.Build.VERSION.SDK_INT;
import static android.os.Build.VERSION_CODES.S;
+import static android.os.Build.VERSION_CODES.S_V2;
import static android.os.Process.myUserHandle;
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;
-import static com.android.bedstead.nene.utils.Versions.S_V2;
import android.app.ActivityManager;
import android.content.Context;
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
index 901d586..5d80cec 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Tags.java
@@ -27,6 +27,7 @@
public static final String USES_DEVICESTATE = "uses_devicestate";
public static final String USES_NOTIFICATIONS = "uses_notifications";
+ public static final String INSTANT_APP = "instant_app";
private Tags() {
diff --git a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
index 0047245..4feb6b6 100644
--- a/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
+++ b/common/device-side/bedstead/nene/src/main/java/com/android/bedstead/nene/utils/Versions.java
@@ -28,7 +28,7 @@
/** SDK Version checks. */
public final class Versions {
- public static final int S_V2 = CUR_DEVELOPMENT;
+ public static final int T = CUR_DEVELOPMENT;
/** Any version. */
public static final int ANY = -1;
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
index 6b0620f..bf2e881 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/packages/PackageTest.java
@@ -31,7 +31,7 @@
import com.android.bedstead.harrier.annotations.AfterClass;
import com.android.bedstead.harrier.annotations.BeforeClass;
import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
-import com.android.bedstead.harrier.annotations.RequireRunOnSystemUser;
+import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.permissions.PermissionContext;
@@ -119,7 +119,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO: this actually should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void installExisting_alreadyInstalled_installsInUser() {
sInstrumentedPackage.installExisting(sDeviceState.secondaryUser());
@@ -132,7 +132,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void uninstallForAllUsers_isUninstalledForAllUsers() throws Exception {
Package pkg = TestApis.packages().install(sTestAppApkFile);
pkg.installExisting(sDeviceState.secondaryUser());
@@ -144,7 +144,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void uninstall_packageIsInstalledForDifferentUser_isUninstalledForUser()
throws Exception {
Package pkg = TestApis.packages().install(sTestAppApkFile);
@@ -173,7 +173,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void uninstall_packageNotInstalledForUser_doesNotThrowException() {
TestApis.packages().install(sTestAppApkFile);
@@ -217,7 +217,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void grantPermission_permissionIsUserSpecific_permissionIsGrantedOnlyForThatUser() {
try (TestAppInstance instance1 = sTestApp.install();
TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
@@ -329,7 +329,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(201319776): Just needs to be not the secondary user
+ @RequireRunNotOnSecondaryUser
public void denyPermission_permissionIsUserSpecific_permissionIsDeniedOnlyForThatUser() {
try (TestAppInstance instance1 = sTestApp.install();
TestAppInstance instance2 = sTestApp.install(sDeviceState.secondaryUser())) {
@@ -358,7 +358,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnSystemUser // TODO(b/201319776): this should be anything but secondary user
+ @RequireRunNotOnSecondaryUser
public void installedOnUsers_doesNotIncludeUserWithoutPackageInstalled() throws Exception {
Package pkg = TestApis.packages().install(sTestAppApkFile);
pkg.uninstall(sDeviceState.secondaryUser());
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UserReferenceTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UserReferenceTest.java
index 6c3fd37..209e36c 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UserReferenceTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UserReferenceTest.java
@@ -37,6 +37,7 @@
import com.android.bedstead.harrier.annotations.EnsureHasPermission;
import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile;
+import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.RequireSdkVersion;
import com.android.bedstead.nene.TestApis;
@@ -135,7 +136,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnPrimaryUser // TODO(201319776): Use @RequireRunNotOnSecondaryUser
+ @RequireRunNotOnSecondaryUser
public void stop_userStarted_userIsStopped() {
sDeviceState.secondaryUser().stop();
@@ -144,7 +145,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnPrimaryUser // TODO(201319776): Use @RequireRunNotOnSecondaryUser
+ @RequireRunNotOnSecondaryUser
public void stop_userNotStarted_doesNothing() {
sDeviceState.secondaryUser().stop();
@@ -155,7 +156,7 @@
@Test
@EnsureHasSecondaryUser
- @RequireRunOnPrimaryUser // TODO(201319776): Use @RequireRunNotOnSecondaryUser
+ @RequireRunNotOnSecondaryUser
@RequireSdkVersion(min = Q)
public void switchTo_userIsSwitched() {
try (PermissionContext p =
diff --git a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
index f683175..1769a01 100644
--- a/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
+++ b/common/device-side/bedstead/nene/src/test/java/com/android/bedstead/nene/users/UsersTest.java
@@ -42,6 +42,7 @@
import com.android.bedstead.harrier.annotations.EnsureHasSecondaryUser;
import com.android.bedstead.harrier.annotations.EnsureHasWorkProfile;
import com.android.bedstead.harrier.annotations.RequireHeadlessSystemUserMode;
+import com.android.bedstead.harrier.annotations.RequireRunNotOnSecondaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
import com.android.bedstead.harrier.annotations.RequireRunOnSecondaryUser;
import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDeviceOwner;
@@ -486,7 +487,7 @@
}
@Test
- @RequireRunOnPrimaryUser // TODO(201319776): Use @RequireRunNotOnSecondaryUser
+ @RequireRunNotOnSecondaryUser
@EnsureHasSecondaryUser
@RequireHeadlessSystemUserMode
public void switch_hasSetStopBgUsersOnSwitch_stopsUser() throws Exception {
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NullableQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NullableQuery.java
new file mode 100644
index 0000000..90be710
--- /dev/null
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/NullableQuery.java
@@ -0,0 +1,42 @@
+/*
+ * 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.queryable.queries;
+
+/**
+ * A {@link Query} for a nullable type.
+ *
+ *
+ * @param <E> Type of query
+ * @param <F> Type of object being queried
+ */
+public interface NullableQuery<E, F> extends Query<F> {
+ /** Require the {@link F} is equal to {@code string}. */
+ E isEqualTo(F value);
+
+ /** Require the {@link F} is not equal to {@code string}. */
+ E isNotEqualTo(F value);
+
+ /** Require the {@link F} is null. */
+ default E isNull() {
+ return isEqualTo(null);
+ }
+
+ /** Require the {@link F} is not null. */
+ default E isNotNull() {
+ return isNotEqualTo(null);
+ }
+}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
index a659887..089a508 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/SetQueryHelper.java
@@ -190,21 +190,27 @@
public String describeQuery(String fieldName) {
List<String> queryStrings = new ArrayList<>();
queryStrings.add(mSizeQuery.describeQuery(fieldName + ".size"));
- if (!mContainsByQuery.isEmpty() && !mContainsByType.isEmpty()) {
+ if (!mContainsByQuery.isEmpty()) {
queryStrings.add(fieldName + " contains matches of ["
+ mContainsByQuery.stream().map(t -> "{" + t.describeQuery("")
- + "}").collect(Collectors.joining(", ")) + "]"
- + mContainsByType.stream().map(t -> "{" + t.toString()
+ "}").collect(Collectors.joining(", ")) + "]");
}
- if (!mDoesNotContainByQuery.isEmpty() && !mDoesNotContainByType.isEmpty()) {
- queryStrings.add(fieldName + " does not contain anything matching any of ["
- + mDoesNotContainByQuery.stream().map(t -> "{" + t.describeQuery("")
- + "}").collect(Collectors.joining(", ")) + "]"
- + mDoesNotContainByType.stream().map(t -> "{" + t.toString()
- + "}").collect(Collectors.joining(", ")) + "]");
+ if (!mContainsByType.isEmpty()) {
+ queryStrings.add(fieldName + " contains ["
+ + mContainsByType.stream().map(Object::toString)
+ .collect(Collectors.joining(", ")) + "]");
}
+ if (!mDoesNotContainByQuery.isEmpty()) {
+ queryStrings.add(fieldName + " does not contain anything matching any of ["
+ + mDoesNotContainByQuery.stream().map(t -> "{" + t.describeQuery("")
+ + "}").collect(Collectors.joining(", ")) + "]");
+ }
+ if (!mDoesNotContainByType.isEmpty()) {
+ queryStrings.add(fieldName + " does not contain ["
+ + mDoesNotContainByType.stream().map(Object::toString)
+ .collect(Collectors.joining(", ")) + "]");
+ }
return Queryable.joinQueryStrings(queryStrings);
}
}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQuery.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQuery.java
index 03c32b9..2db0fa5 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQuery.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQuery.java
@@ -18,15 +18,14 @@
import com.android.queryable.Queryable;
-import java.io.Serializable;
-
-/** Query for a {@link String}. */
-public interface StringQuery<E extends Queryable> extends Query<String> {
+/**
+ * Query for a {@link String}.
+ *
+ * @param <E> Type of query
+ */
+public interface StringQuery<E extends Queryable> extends NullableQuery<E, String> {
static StringQuery<StringQuery<?>> string() {
return new StringQueryHelper<>();
}
-
- /** Require the {@link String} is equal to {@code string}. */
- E isEqualTo(String string);
}
diff --git a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
index b7406d8..05ef5ae 100644
--- a/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
+++ b/common/device-side/bedstead/queryable/src/main/java/com/android/queryable/queries/StringQueryHelper.java
@@ -20,7 +20,9 @@
import java.io.Serializable;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
/** Implementation of {@link StringQuery}. */
public final class StringQueryHelper<E extends Queryable>
@@ -30,6 +32,7 @@
private final transient E mQuery;
private String mEqualsValue;
+ private Set<String> mNotEqualsValues = new HashSet<>();
StringQueryHelper() {
mQuery = (E) this;
@@ -41,7 +44,13 @@
@Override
public E isEqualTo(String string) {
- this.mEqualsValue = string;
+ mEqualsValue = string;
+ return mQuery;
+ }
+
+ @Override
+ public E isNotEqualTo(String string) {
+ mNotEqualsValues.add(string);
return mQuery;
}
@@ -50,6 +59,9 @@
if (mEqualsValue != null && !mEqualsValue.equals(value)) {
return false;
}
+ if (mNotEqualsValues.contains(value)) {
+ return false;
+ }
return true;
}
@@ -59,6 +71,13 @@
}
/**
+ * True if this query has not been configured.
+ */
+ public boolean isEmpty() {
+ return mEqualsValue == null && mNotEqualsValues.isEmpty();
+ }
+
+ /**
* True if this query is for an exact string match.
*/
public boolean isQueryingForExactMatch() {
@@ -72,6 +91,10 @@
queryStrings.add(fieldName + "=\"" + mEqualsValue + "\"");
}
+ for (String notEquals : mNotEqualsValues) {
+ queryStrings.add(fieldName + "!=\"" + notEquals + "\"");
+ }
+
return Queryable.joinQueryStrings(queryStrings);
}
}
diff --git a/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/queries/StringQueryHelperTest.java b/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/queries/StringQueryHelperTest.java
index 9797b8c..dcfb4d1 100644
--- a/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/queries/StringQueryHelperTest.java
+++ b/common/device-side/bedstead/queryable/src/test/java/com/android/queryable/queries/StringQueryHelperTest.java
@@ -58,4 +58,55 @@
assertThat(stringQueryHelper.matches(STRING_VALUE)).isFalse();
}
+
+ @Test
+ public void matches_isNotEqualTo_meetsRestriction_returnsTrue() {
+ StringQueryHelper<Queryable> stringQueryHelper =
+ new StringQueryHelper<>(mQuery);
+
+ stringQueryHelper.isNotEqualTo(DIFFERENT_STRING_VALUE);
+
+ assertThat(stringQueryHelper.matches(STRING_VALUE)).isTrue();
+ }
+
+ @Test
+ public void matches_isNotEqualTo_doesNotMeetRestriction_returnsFalse() {
+ StringQueryHelper<Queryable> stringQueryHelper =
+ new StringQueryHelper<>(mQuery);
+
+ stringQueryHelper.isNotEqualTo(DIFFERENT_STRING_VALUE);
+
+ assertThat(stringQueryHelper.matches(DIFFERENT_STRING_VALUE)).isFalse();
+ }
+
+ @Test
+ public void matches_isNotEqualTo_multipleRestrictions_doesNotMeetRestriction_returnsFalse() {
+ StringQueryHelper<Queryable> stringQueryHelper =
+ new StringQueryHelper<>(mQuery);
+
+ stringQueryHelper.isNotEqualTo(DIFFERENT_STRING_VALUE);
+ stringQueryHelper.isNotEqualTo(STRING_VALUE);
+
+ assertThat(stringQueryHelper.matches(DIFFERENT_STRING_VALUE)).isFalse();
+ }
+
+ @Test
+ public void matches_isNull_meetsRestriction_returnsTrue() {
+ StringQueryHelper<Queryable> stringQueryHelper =
+ new StringQueryHelper<>(mQuery);
+
+ stringQueryHelper.isNull();
+
+ assertThat(stringQueryHelper.matches(null)).isTrue();
+ }
+
+ @Test
+ public void matches_isNotNull_doesNotMeetRestriction_returnsFalse() {
+ StringQueryHelper<Queryable> stringQueryHelper =
+ new StringQueryHelper<>(mQuery);
+
+ stringQueryHelper.isNotNull();
+
+ assertThat(stringQueryHelper.matches(null)).isFalse();
+ }
}
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/NotFoundException.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/NotFoundException.java
index 669bb13..55e5831e 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/NotFoundException.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/NotFoundException.java
@@ -19,6 +19,6 @@
/** {@link Exception} thrown when a query doesn't match any test apps. */
public class NotFoundException extends RuntimeException {
public NotFoundException(TestAppQueryBuilder query) {
-
+ super("Could not find testapp matching query: " + query.describeQuery(null));
}
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
index 102e8da..ac75967 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestApp.java
@@ -22,6 +22,8 @@
import android.os.Bundle;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
+
import com.android.bedstead.nene.TestApis;
import com.android.bedstead.nene.exceptions.NeneException;
import com.android.bedstead.nene.packages.Package;
@@ -34,11 +36,12 @@
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Objects;
import java.util.Set;
/** Represents a single test app which can be installed and interacted with. */
@TestAppSender
-public class TestApp {
+public final class TestApp {
// Must be instrumentation context to access resources
private static final Context sContext = TestApis.context().instrumentationContext();
private final TestAppDetails mDetails;
@@ -208,4 +211,23 @@
+ ", details=" + mDetails
+ "}";
}
+
+ /** The shared user id of the test app, if any. */
+ @Nullable
+ public String sharedUserId() {
+ return mDetails.sharedUserId();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TestApp)) return false;
+ TestApp testApp = (TestApp) o;
+ return mDetails.mApp.getPackageName().equals(testApp.mDetails.mApp.getPackageName());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mDetails.mApp.getPackageName());
+ }
}
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/TestAppDetails.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppDetails.java
index 71dab7b..b9b34ec 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppDetails.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppDetails.java
@@ -18,6 +18,8 @@
import android.os.Bundle;
+import androidx.annotation.Nullable;
+
import com.android.queryable.info.ActivityInfo;
import com.android.queryable.info.ServiceInfo;
@@ -33,6 +35,18 @@
final Set<ActivityInfo> mActivities = new HashSet<>();
final Set<ServiceInfo> mServices = new HashSet<>();
+ /**
+ * Get the shared user ID of the test app, or {@code Null} if none.
+ */
+ @Nullable
+ public String sharedUserId() {
+ if (mApp.getSharedUserId().isEmpty()) {
+ return null;
+ }
+
+ return mApp.getSharedUserId();
+ }
+
@Override
public String toString() {
return "TestAppDetails{"
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..68cf755 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
@@ -58,6 +58,7 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.Objects;
import java.util.UUID;
import javax.annotation.Nullable;
@@ -115,6 +116,13 @@
}
/**
+ * See {@link TestApp#packageName()}.
+ */
+ public String packageName() {
+ return testApp().packageName();
+ }
+
+ /**
* The {@link UserReference} this instance refers to.
*/
public UserReference user() {
@@ -375,4 +383,17 @@
+ ", keepAliveManually=" + mKeepAliveManually
+ '}';
}
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof TestAppInstance)) return false;
+ TestAppInstance that = (TestAppInstance) o;
+ return mTestApp.equals(that.mTestApp) && mUser.equals(that.mUser);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mTestApp, mUser);
+ }
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppQueryBuilder.java b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppQueryBuilder.java
index 6699a6d..5afc802 100644
--- a/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppQueryBuilder.java
+++ b/common/device-side/bedstead/testapp/src/library/main/java/com/android/bedstead/testapp/TestAppQueryBuilder.java
@@ -48,6 +48,7 @@
new SetQueryHelper<>(this);
SetQueryHelper<TestAppQueryBuilder, ServiceInfo, ServiceQuery<?>> mServices =
new SetQueryHelper<>(this);
+ StringQueryHelper<TestAppQueryBuilder> mSharedUserId = new StringQueryHelper<>(this);
TestAppQueryBuilder(TestAppProvider provider) {
if (provider == null) {
@@ -110,6 +111,13 @@
}
/**
+ * Query for a {@link TestApp} by its sharedUserId;
+ */
+ public StringQuery<TestAppQueryBuilder> whereSharedUserId() {
+ return mSharedUserId;
+ }
+
+ /**
* Query for a {@link TestApp} by its activities.
*/
public SetQuery<TestAppQueryBuilder, ActivityInfo, ActivityQuery<?>> whereActivities() {
@@ -186,6 +194,16 @@
return false;
}
+ if (mSharedUserId.isEmpty()) {
+ if (details.sharedUserId() != null) {
+ return false;
+ }
+ } else {
+ if (!StringQueryHelper.matches(mSharedUserId, details.sharedUserId())) {
+ return false;
+ }
+ }
+
if (details.mMetadata.getString("testapp-package-query-only", "false")
.equals("true")) {
if (!mPackageName.isQueryingForExactMatch()) {
@@ -207,6 +225,7 @@
mActivities.describeQuery("activities"),
mServices.describeQuery("services"),
mPermissions.describeQuery("permissions"),
+ mSharedUserId.describeQuery("sharedUserId"),
mTestOnly.describeQuery("testOnly")
) + "}";
}
diff --git a/common/device-side/bedstead/testapp/src/library/main/proto/testapp_protos.proto b/common/device-side/bedstead/testapp/src/library/main/proto/testapp_protos.proto
index 80b13ec..3f5c84d 100644
--- a/common/device-side/bedstead/testapp/src/library/main/proto/testapp_protos.proto
+++ b/common/device-side/bedstead/testapp/src/library/main/proto/testapp_protos.proto
@@ -15,6 +15,7 @@
repeated Service services = 6;
bool test_only = 7;
repeated Metadata metadata = 8;
+ string sharedUserId = 9;
}
message UsesSdk {
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/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
index 9e7dcac..45fcd98 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppInstanceTest.java
@@ -88,14 +88,14 @@
@Test
public void activities_any_returnsActivity() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.activities().any()).isNotNull();
}
}
@Test
public void uninstall_uninstalls() {
- TestAppInstance testAppInstance = sTestApp.install(sUser);
+ TestAppInstance testAppInstance = sTestApp.install();
testAppInstance.uninstall();
@@ -105,7 +105,7 @@
@Test
public void autoclose_uninstalls() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Intentionally empty
}
@@ -123,7 +123,7 @@
@Test
@Ignore("b/203758521 Need to re-add support for killing processes")
public void killProcess_keepAlive_processIsRunningAgain() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.keepAlive();
// testAppInstance.process().kill();
@@ -141,7 +141,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_processIsNotRunning() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.activities().any().start();
// testAppInstance.stop();
@@ -153,7 +153,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_previouslyCalledKeepAlive_processDoesNotRestart() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.activities().any().start();
testAppInstance.keepAlive();
@@ -165,14 +165,14 @@
@Test
public void process_isNotRunning_returnsNull() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.process()).isNull();
}
}
@Test
public void process_isRunning_isNotNull() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.activities().any().start();
Poll.forValue("TestApp process", testAppInstance::process)
@@ -184,7 +184,7 @@
@Test
public void registerReceiver_receivesBroadcast() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
sContext.sendBroadcast(INTENT);
@@ -197,7 +197,7 @@
@Test
public void registerReceiver_multipleIntentFilters_receivesAllMatchingBroadcasts() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.registerReceiver(INTENT_FILTER_2);
@@ -215,7 +215,7 @@
@Test
public void registerReceiver_processIsRunning() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
@@ -226,7 +226,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void stop_registeredReceiver_doesNotReceiveBroadcast() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
// testAppInstance.stop();
@@ -241,7 +241,7 @@
@Test
public void unregisterReceiver_registeredReceiver_doesNotReceiveBroadcast() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.unregisterReceiver(INTENT_FILTER);
@@ -256,7 +256,7 @@
@Test
public void unregisterReceiver_doesNotUnregisterOtherReceivers() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
testAppInstance.registerReceiver(INTENT_FILTER_2);
@@ -277,7 +277,7 @@
@Test
public void keepAlive_processIsRunning() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.keepAlive();
@@ -288,7 +288,7 @@
@Test
@Ignore("b/203758521 need to re-add support for killing processes")
public void registerReceiver_appIsKilled_stillReceivesBroadcast() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
testAppInstance.registerReceiver(INTENT_FILTER);
// testApp.pkg().runningProcess(sUser).kill();
Poll.forValue("running process", () -> sTestApp.pkg().runningProcess(sUser))
@@ -308,7 +308,7 @@
@Test
@RequireSdkVersion(min = S, reason = "isSafeOperation only available on S+")
public void devicePolicyManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.devicePolicyManager()
.isSafeOperation(OPERATION_SAFETY_REASON_DRIVING_DISTRACTION);
@@ -317,7 +317,7 @@
@Test
public void userManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.userManager().getUserProfiles();
}
@@ -326,7 +326,7 @@
@Test
@RequireSdkVersion(min = Q, reason = "Wifimanager API only available on Q+")
public void wifiManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call which does not require specific permissions to confirm no crash
testAppInstance.wifiManager().getMaxNumberOfNetworkSuggestionsPerApp();
}
@@ -334,7 +334,7 @@
@Test
public void hardwarePropertiesManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call - there are no methods on this service which don't require permissions
assertThrows(SecurityException.class, () -> {
testAppInstance.hardwarePropertiesManager().getCpuUsages();
@@ -344,28 +344,28 @@
@Test
public void packageManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.packageManager().hasSystemFeature("")).isFalse();
}
}
@Test
public void crossProfileApps_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.crossProfileApps().getTargetUserProfiles()).isEmpty();
}
}
@Test
public void launcherApps_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.launcherApps().hasShortcutHostPermission()).isFalse();
}
}
@Test
public void accountManager_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call which does not require specific permissions to confirm no crash
assertThat(testAppInstance.accountManager().getAccounts()).isNotNull();
}
@@ -373,7 +373,7 @@
@Test
public void context_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.context().getSystemServiceName(DevicePolicyManager.class))
.isEqualTo(Context.DEVICE_POLICY_SERVICE);
}
@@ -381,7 +381,7 @@
@Test
public void context_getContentResolver_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
// Arbitrary call which does not require specific permissions to confirm no crash
assertThat(testAppInstance.context().getContentResolver().getPersistedUriPermissions())
.isNotNull();
@@ -390,7 +390,7 @@
@Test
public void keyChain_returnsUsableInstance() {
- try (TestAppInstance testAppInstance = sTestApp.install(sUser)) {
+ try (TestAppInstance testAppInstance = sTestApp.install()) {
assertThat(testAppInstance.keyChain().isKeyAlgorithmSupported("A")).isFalse();
}
}
diff --git a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppProviderTest.java b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppProviderTest.java
index 7d80b57..bc270b4 100644
--- a/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppProviderTest.java
+++ b/common/device-side/bedstead/testapp/src/test/java/com/android/bedstead/testapp/TestAppProviderTest.java
@@ -23,6 +23,7 @@
import static org.testng.Assert.assertThrows;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -231,4 +232,31 @@
assertThat(testApp.activities()).isEmpty();
}
+
+ @Test
+ public void query_doesNotSpecifySharedUserId_sharedUserIdIsNull() {
+ TestApp testApp = mTestAppProvider.query()
+ .get();
+
+ assertThat(testApp.sharedUserId()).isNull();
+ }
+
+ @Test
+ @Ignore("re-enable when we have a test app which has a shareuserid")
+ public void query_doesSpecifySharedUserId_matches() {
+ TestApp testApp = mTestAppProvider.query()
+ .whereSharedUserId().isEqualTo("com.android.bedstead")
+ .get();
+
+ assertThat(testApp.sharedUserId()).isEqualTo("com.android.bedstead");
+ }
+
+ @Test
+ public void query_specifiesNullSharedUserId_matches() {
+ TestApp testApp = mTestAppProvider.query()
+ .whereSharedUserId().isNull()
+ .get();
+
+ assertThat(testApp.sharedUserId()).isNull();
+ }
}
diff --git a/common/device-side/bedstead/testapp/tools/index/index_testapps.py b/common/device-side/bedstead/testapp/tools/index/index_testapps.py
index b4aee78..163e35a 100644
--- a/common/device-side/bedstead/testapp/tools/index/index_testapps.py
+++ b/common/device-side/bedstead/testapp/tools/index/index_testapps.py
@@ -133,6 +133,7 @@
android_app = AndroidApp()
android_app.apk_name = file_name
android_app.package_name = root.attributes["package"]
+ android_app.sharedUserId = root.attributes.get("sharedUserId", "")
parse_uses_sdk(root, android_app)
parse_permissions(root, android_app)
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
index 49208b1..0cbd2a9 100644
--- a/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/BaseDefaultPermissionGrantPolicyTest.java
@@ -465,7 +465,7 @@
Context context = getInstrumentation().getTargetContext();
for (PackageInfo pkg : packageInfos.values()) {
- int targetSdk = pkg.applicationInfo.targetSandboxVersion;
+ int targetSdk = pkg.applicationInfo.targetSdkVersion;
int uid = pkg.applicationInfo.uid;
for (String permission : pkg.requestedPermissions) {
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/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
index 4b8d874..eebc2bd 100755
--- a/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
+++ b/hostsidetests/devicepolicy/app/DeviceAndProfileOwner/src/com/android/cts/deviceandprofileowner/KeyManagementTest.java
@@ -422,6 +422,9 @@
*/
// TODO(b/198408853): Migrate
public void testCanGenerateKeyPairWithKeyAttestation() throws Exception {
+ if (!isAttestationSupported()) {
+ return;
+ }
for (SupportedKeyAlgorithm supportedKey : SUPPORTED_KEY_ALGORITHMS) {
assertThat(
generateKeyAndCheckAttestation(
@@ -831,4 +834,8 @@
boolean isUniqueDeviceAttestationSupported() {
return mDevicePolicyManager.isUniqueDeviceAttestationSupported();
}
+
+ private boolean isAttestationSupported() {
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+ }
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
index 992f6f1..c30543b 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/BaseDevicePolicyTest.java
@@ -186,6 +186,8 @@
/** Users we shouldn't delete in the tests */
private ArrayList<Integer> mFixedUsers;
+ protected boolean mHasAttestation;
+
private static final String VERIFY_CREDENTIAL_CONFIRMATION = "Lock credential verified";
@Rule
@@ -205,6 +207,10 @@
mFixedPackages = getDevice().getInstalledPackageNames();
mBuildHelper = new CompatibilityBuildHelper(getBuild());
+ String propertyValue = getDevice().getProperty("ro.product.first_api_level");
+ if (propertyValue != null && !propertyValue.isEmpty()) {
+ mHasAttestation = Integer.parseInt(propertyValue) >= 26;
+ }
if (hasDeviceFeature(FEATURE_SECURE_LOCK_SCREEN)) {
ensurePrimaryUserHasNoPassword();
}
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceAndProfileOwnerTest.java
index bd46a07..075d422 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
@@ -288,7 +241,6 @@
*/
private Map<String, DevicePolicyEventWrapper[]> getDelegationTests() {
final Map<String, DevicePolicyEventWrapper[]> result = new HashMap<>();
- result.put(".AppRestrictionsDelegateTest", null);
result.put(".CertInstallDelegateTest", null);
result.put(".BlockUninstallDelegateTest", null);
result.put(".PermissionGrantDelegateTest", null);
@@ -753,6 +705,8 @@
reason = "Will be migrated to new test infra")
@Test
public void testDelegatedCertInstallerDirectly() throws Exception {
+ assumeTrue(mHasAttestation);
+
setUpDelegatedCertInstallerAndRunTests(() ->
runDeviceTestsAsUser("com.android.cts.certinstaller",
".DirectDelegatedCertInstallerTest", mUserId));
@@ -764,6 +718,8 @@
reason = "Will be migrated to new test infra")
@Test
public void testSetKeyGrant() throws Exception {
+ assumeTrue(mHasAttestation);
+
// Install an app
installAppAsUser(CERT_INSTALLER_APK, mUserId);
@@ -1292,6 +1248,8 @@
@Test
// TODO(b/198408853): Migrate
public void testGenerateKeyPairLogged() throws Exception {
+ assumeTrue(mHasAttestation);
+
assertMetricsLogged(getDevice(), () -> {
executeDeviceTestMethod(
".KeyManagementTest", "testCanGenerateKeyPairWithKeyAttestation");
diff --git a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
index fc638aa..17c2d48 100644
--- a/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
+++ b/hostsidetests/devicepolicy/src/com/android/cts/devicepolicy/DeviceOwnerTest.java
@@ -832,6 +832,7 @@
}
@Test
+ @Ignore("b/204508654")
public void testSetUserControlDisabledPackages_multiUser_reboot_verifyPackageNotStopped()
throws Exception {
assumeCanCreateAdditionalUsers(1);
@@ -879,7 +880,7 @@
// done in tear down.
}
} finally {
- setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
+ setStopBgUsersOnSwitchProperty(stopBgUsersOnSwitchValue);
}
}
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/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java b/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java
index 4c05fd1..3203793 100644
--- a/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java
+++ b/hostsidetests/settings/app/DeviceOwnerApp/src/com/google/android/cts/deviceowner/DeviceOwnerTest.java
@@ -31,6 +31,9 @@
import android.server.wm.WindowManagerStateHelper;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.support.test.uiautomator.UiScrollable;
+import android.support.test.uiautomator.UiSelector;
import android.support.test.uiautomator.Until;
import android.test.InstrumentationTestCase;
import android.util.Log;
@@ -53,6 +56,8 @@
public static final int TIMEOUT_MS = 2_000;
+ public static final double DEADZONE_PCT = 0.2;
+
protected Context mContext;
protected UiDevice mDevice;
@@ -140,6 +145,16 @@
boolean found = null != mDevice.wait(Until.findObject(By.text(mWorkPolicyInfoText)),
TIMEOUT_MS);
+ // Try to scroll the list to find the item
+ if (!found) {
+ UiScrollable scroller = new UiScrollable(new UiSelector().scrollable(true));
+ try {
+ // Swipe far away from the edges to avoid triggering navigation gestures
+ scroller.setSwipeDeadZonePercentage(DEADZONE_PCT);
+ found = scroller.scrollTextIntoView(mWorkPolicyInfoText);
+ } catch (UiObjectNotFoundException e) { }
+ }
+
Log.d(TAG, "Message found: " + found);
return found;
}
diff --git a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
index 8b628cf..d547c0d 100644
--- a/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
+++ b/hostsidetests/statsdatom/src/android/cts/statsdatom/statsd/AtomTestCase.java
@@ -79,6 +79,7 @@
import java.util.Queue;
import java.util.Random;
import java.util.Set;
+import java.util.StringTokenizer;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -926,7 +927,16 @@
*/
protected boolean hasFeature(String featureName, boolean requiredAnswer) throws Exception {
final String features = getDevice().executeShellCommand("pm list features");
- boolean hasIt = features.contains(featureName);
+ StringTokenizer featureToken = new StringTokenizer(features, "\n");
+ boolean hasIt = false;
+
+ while (featureToken.hasMoreTokens()) {
+ if (("feature:" + featureName).equals(featureToken.nextToken())) {
+ hasIt = true;
+ break;
+ }
+ }
+
if (hasIt != requiredAnswer) {
LogUtil.CLog.w("Device does " + (requiredAnswer ? "not " : "") + "have feature "
+ featureName);
diff --git a/tests/app/app/AndroidManifest.xml b/tests/app/app/AndroidManifest.xml
index 1adf9b4..737dfaa 100644
--- a/tests/app/app/AndroidManifest.xml
+++ b/tests/app/app/AndroidManifest.xml
@@ -536,7 +536,22 @@
android:resource="@xml/shortcuts"/>
</activity>
- <service android:name="android.app.stubs.TrimMemService"
+ <!-- Disable home activities by default or it may disturb other tests by
+ showing ResolverActivity when start home activity.
+ Set the task affinity to empty not to group with the other Activities in this app. -->
+ <activity
+ android:name="android.app.stubs.TestHomeActivity"
+ android:enabled="false"
+ android:taskAffinity=""
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.HOME" />
+ <category android:name="android.intent.category.DEFAULT" />
+ </intent-filter>
+ </activity>
+
+ <service android:name="android.app.stubs.TrimMemService"
android:exported="true"
android:isolatedProcess="true">
</service>
diff --git a/tests/app/app/src/android/app/stubs/TestHomeActivity.java b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
new file mode 100644
index 0000000..340494a
--- /dev/null
+++ b/tests/app/app/src/android/app/stubs/TestHomeActivity.java
@@ -0,0 +1,22 @@
+/*
+ * 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.app.stubs;
+
+import android.app.Activity;
+
+public class TestHomeActivity extends Activity {
+}
diff --git a/tests/app/src/android/app/cts/ActivityManagerTest.java b/tests/app/src/android/app/cts/ActivityManagerTest.java
index 428eb34..770d305 100644
--- a/tests/app/src/android/app/cts/ActivityManagerTest.java
+++ b/tests/app/src/android/app/cts/ActivityManagerTest.java
@@ -21,6 +21,13 @@
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE;
import static android.content.ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN;
+import static android.content.Intent.ACTION_MAIN;
+import static android.content.Intent.CATEGORY_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+import static android.content.pm.PackageManager.DONT_KILL_APP;
+import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY;
import static org.junit.Assert.assertArrayEquals;
@@ -45,8 +52,10 @@
import android.app.stubs.MockApplicationActivity;
import android.app.stubs.MockService;
import android.app.stubs.ScreenOnActivity;
+import android.app.stubs.TestHomeActivity;
import android.app.stubs.TrimMemService;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -54,6 +63,7 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.ConfigurationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.os.Binder;
import android.os.Bundle;
@@ -144,6 +154,7 @@
private List<Activity> mStartedActivityList;
private int mErrorProcessID;
private Instrumentation mInstrumentation;
+ private HomeActivitySession mTestHomeSession;
@Override
protected void setUp() throws Exception {
@@ -161,6 +172,9 @@
@Override
protected void tearDown() throws Exception {
super.tearDown();
+ if (mTestHomeSession != null) {
+ mTestHomeSession.close();
+ }
if (mIntent != null) {
mInstrumentation.getContext().stopService(mIntent);
}
@@ -593,6 +607,7 @@
* Verify that the TimeTrackingAPI works properly when starting and ending an activity.
*/
public void testTimeTrackingAPI_SimpleStartExit() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -679,6 +694,7 @@
* Verify that the TimeTrackingAPI works properly when switching away from the monitored task.
*/
public void testTimeTrackingAPI_SwitchAwayTriggers() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
@@ -727,6 +743,7 @@
* and ended.
*/
public void testTimeTrackingAPI_ChainedActivityExit() throws Exception {
+ createManagedHomeActivitySession();
launchHome();
// Prepare to start an activity from another APK.
Intent intent = new Intent(Intent.ACTION_MAIN);
@@ -1766,4 +1783,63 @@
} while (!(result = supplier.get()) && SystemClock.uptimeMillis() < deadLine);
return result;
}
+
+ private void createManagedHomeActivitySession()
+ throws Exception {
+ if (noHomeScreen()) return;
+ ComponentName homeActivity = new ComponentName(
+ STUB_PACKAGE_NAME, TestHomeActivity.class.getName());
+ mTestHomeSession = new HomeActivitySession(homeActivity);
+ }
+
+ /**
+ * HomeActivitySession is used to replace the default home component, so that you can use
+ * your preferred home for testing within the session. The original default home will be
+ * restored automatically afterward.
+ */
+ private class HomeActivitySession {
+ private PackageManager mPackageManager;
+ private ComponentName mOrigHome;
+ private ComponentName mSessionHome;
+
+ HomeActivitySession(ComponentName sessionHome) throws Exception {
+ mSessionHome = sessionHome;
+ mPackageManager = mInstrumentation.getContext().getPackageManager();
+ mOrigHome = getDefaultHomeComponent();
+
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+ COMPONENT_ENABLED_STATE_ENABLED, DONT_KILL_APP));
+ setDefaultHome(mSessionHome);
+ }
+
+ public void close() throws Exception {
+ SystemUtil.runWithShellPermissionIdentity(
+ () -> mPackageManager.setComponentEnabledSetting(mSessionHome,
+ COMPONENT_ENABLED_STATE_DISABLED, DONT_KILL_APP));
+ if (mOrigHome != null) {
+ setDefaultHome(mOrigHome);
+ mOrigHome = null;
+ }
+ }
+
+ private void setDefaultHome(ComponentName componentName) throws Exception {
+ executeShellCommand("cmd package set-home-activity --user "
+ + android.os.Process.myUserHandle().getIdentifier() + " "
+ + componentName.flattenToString());
+ }
+
+ private ComponentName getDefaultHomeComponent() {
+ final Intent intent = new Intent(ACTION_MAIN);
+ intent.addCategory(CATEGORY_HOME);
+ intent.addFlags(FLAG_ACTIVITY_NEW_TASK);
+ final ResolveInfo resolveInfo = mInstrumentation.getContext()
+ .getPackageManager().resolveActivity(intent, MATCH_DEFAULT_ONLY);
+ if (resolveInfo == null) {
+ throw new AssertionError("Home activity not found");
+ }
+ return new ComponentName(resolveInfo.activityInfo.packageName,
+ resolveInfo.activityInfo.name);
+ }
+ }
}
diff --git a/tests/camera/src/android/hardware/cts/CameraGLTest.java b/tests/camera/src/android/hardware/cts/CameraGLTest.java
index 7478e79..030b5ab 100644
--- a/tests/camera/src/android/hardware/cts/CameraGLTest.java
+++ b/tests/camera/src/android/hardware/cts/CameraGLTest.java
@@ -39,6 +39,8 @@
import androidx.test.rule.ActivityTestRule;
+import com.android.compatibility.common.util.WindowUtil;
+
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
@@ -104,6 +106,11 @@
public void setUp() throws Exception {
// Start CameraCtsActivity.
GLSurfaceViewCtsActivity ctsActivity = mActivityRule.getActivity();
+ // Some of the tests run on the UI thread. In case some of the operations take a long time
+ // to complete, wait for window to receive focus. This ensure that the focus event from
+ // input flinger has been handled, and avoids getting ANR.
+ WindowUtil.waitForFocus(ctsActivity);
+
// Store a link to the view so we can redraw it when needed
mGLView = ctsActivity.getView();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/AccountManagementTest.java
index 3ed02e8..9c5938e 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;
@@ -57,7 +57,7 @@
import java.io.IOException;
@RunWith(BedsteadJUnit4.class)
-public class AccountManagementTest {
+public final class AccountManagementTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
@@ -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/AdminPermissionControlParamsTests.java b/tests/devicepolicy/src/android/devicepolicy/cts/AdminPermissionControlParamsTests.java
index 22a64bf..27dbf44 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/AdminPermissionControlParamsTests.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/AdminPermissionControlParamsTests.java
@@ -29,7 +29,7 @@
import org.junit.runner.RunWith;
@RunWith(BedsteadJUnit4.class)
-public class AdminPermissionControlParamsTests {
+public final class AdminPermissionControlParamsTests {
private static final String PKG = "somePackage";
private static final String PERMISSION = "somePackage";
private static final int GRANT_STATE = DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
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/CaCertManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
index ada4b40..9fe4b36 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CaCertManagementTest.java
@@ -57,7 +57,7 @@
// the <application> element in the manifest.
// TODO(b/205261115): Use a testapp and query for it rather than relying on the Manifest content
@RunWith(BedsteadJUnit4.class)
-public class CaCertManagementTest {
+public final class CaCertManagementTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CameraPolicyTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CameraPolicyTest.java
index 86d2857..cbeeaad 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CameraPolicyTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CameraPolicyTest.java
@@ -55,7 +55,7 @@
import java.util.concurrent.atomic.AtomicBoolean;
@RunWith(BedsteadJUnit4.class)
-public class CameraPolicyTest {
+public final class CameraPolicyTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CreateAndManageUserTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CreateAndManageUserTest.java
index b329718..0da2988 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CreateAndManageUserTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CreateAndManageUserTest.java
@@ -43,7 +43,7 @@
import org.junit.runner.RunWith;
@RunWith(BedsteadJUnit4.class)
-public class CreateAndManageUserTest {
+public final class CreateAndManageUserTest {
private static final String TAG = "CreateAndManageUserTest";
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
index baabdc7..ced2600 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CredentialManagementAppTest.java
@@ -23,9 +23,7 @@
import static com.android.bedstead.nene.appops.AppOps.AppOpsMode.DEFAULT;
import static com.google.common.truth.Truth.assertThat;
-
-import static junit.framework.Assert.assertFalse;
-import static junit.framework.Assert.assertTrue;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.testng.Assert.assertThrows;
@@ -66,14 +64,16 @@
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.Arrays;
import java.util.List;
+import java.util.concurrent.TimeUnit;
@RunWith(BedsteadJUnit4.class)
-public class CredentialManagementAppTest {
+public final class CredentialManagementAppTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
+ private static final int KEYCHAIN_CALLBACK_TIMEOUT_SECONDS = 300;
private static final PrivateKey PRIVATE_KEY =
getPrivateKey(FakeKeys.FAKE_RSA_1.privateKey, "RSA");
private static final Certificate CERTIFICATE =
@@ -291,7 +291,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);
@@ -304,14 +305,14 @@
throws Exception {
removeCredentialManagementApp();
- assertFalse(KeyChain.isCredentialManagementApp(sContext));
+ assertThat(KeyChain.isCredentialManagementApp(sContext)).isFalse();
}
@Test
public void isCredentialManagementApp_isCredentialManagementApp_returnTrue() throws Exception {
setCredentialManagementApp();
try {
- assertTrue(KeyChain.isCredentialManagementApp(sContext));
+ assertThat(KeyChain.isCredentialManagementApp(sContext)).isTrue();
} finally {
removeCredentialManagementApp();
}
@@ -343,9 +344,10 @@
setCredentialManagementApp();
try {
- assertTrue(KeyChain.removeCredentialManagementApp(sContext));
+ boolean wasRemoved = KeyChain.removeCredentialManagementApp(sContext);
- assertFalse(KeyChain.isCredentialManagementApp(sContext));
+ assertThat(wasRemoved).isTrue();
+ assertThat(KeyChain.isCredentialManagementApp(sContext)).isFalse();
} catch (Exception e) {
removeCredentialManagementApp();
}
@@ -355,12 +357,13 @@
private void setCredentialManagementApp() {
try (PermissionContext p = TestApis.permissions().withPermission(
MANAGE_CREDENTIAL_MANAGEMENT_APP)) {
+ boolean wasSet = KeyChain.setCredentialManagementApp(
+ sContext, sContext.getPackageName(), AUTHENTICATION_POLICY);
- assertTrue("Unable to set credential management app",
- KeyChain.setCredentialManagementApp(sContext, sContext.getPackageName(),
- AUTHENTICATION_POLICY));
+ assertWithMessage("Unable to set credential management app").that(wasSet).isTrue();
}
+ assertThat(KeyChain.isCredentialManagementApp(sContext)).isTrue();
assertThat(TestApis.packages().instrumented().appOps().get(MANAGE_CREDENTIALS))
.isEqualTo(ALLOWED);
}
@@ -369,8 +372,9 @@
private void removeCredentialManagementApp() {
try (PermissionContext p = TestApis.permissions().withPermission(
MANAGE_CREDENTIAL_MANAGEMENT_APP)) {
- assertTrue("Unable to remove credential management app",
- KeyChain.removeCredentialManagementApp(sContext));
+ boolean wasRemoved = KeyChain.removeCredentialManagementApp(sContext);
+ assertWithMessage("Unable to remove credential management app")
+ .that(wasRemoved).isTrue();
}
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
index 72e33c0..3aaee38 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/CrossProfileSharingTest.java
@@ -58,7 +58,7 @@
import java.util.List;
@RunWith(BedsteadJUnit4.class)
-public class CrossProfileSharingTest {
+public final class CrossProfileSharingTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DefaultSmsApplicationTest.java
index 473c60e..99c539c 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;
@@ -50,7 +50,7 @@
// TODO(b/198442101): Add tests for the COPE case when we can sideload system apps
@RunWith(BedsteadJUnit4.class)
-public class DefaultSmsApplicationTest {
+public final class DefaultSmsApplicationTest {
@ClassRule
@Rule
public static DeviceState sDeviceState = new DeviceState();
@@ -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/DelegationScopesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
index 68e9558..77530c8 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DelegationScopesTest.java
@@ -24,8 +24,6 @@
import static android.app.admin.DevicePolicyManager.DELEGATION_SECURITY_LOGGING;
import static android.app.admin.DevicePolicyManager.EXTRA_DELEGATION_SCOPES;
-import static com.android.queryable.queries.StringQuery.string;
-
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
@@ -39,6 +37,7 @@
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.CannotSetPolicyTest;
+import com.android.bedstead.harrier.annotations.enterprise.EnsureHasNoDelegate;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.Delegation;
import com.android.bedstead.harrier.policies.NetworkLoggingDelegation;
@@ -68,7 +67,8 @@
@Postsubmit(reason = "new test")
// TODO(b/198584060): clean up the TestApp install API surface and remove the
// requirement to manually uninstall or use the 'try' block.
-public class DelegationScopesTest {
+@EnsureHasNoDelegate
+public final class DelegationScopesTest {
private static final String TEST_SCOPE = DELEGATION_CERT_INSTALL;
private static final String TEST_SCOPE_2 = DELEGATION_APP_RESTRICTIONS;
@@ -79,14 +79,15 @@
private static final TestApis sTestApis = new TestApis();
private static final UserReference sUser = sTestApis.users().instrumented();
- private static final TestApp sTestAppProvider =
- new TestAppProvider().query().whereActivities().isNotEmpty().get();
- private static final TestApp sTestAppProvider2 = new TestAppProvider().any();
+ private static final TestAppProvider sTestAppProvider = new TestAppProvider();
+ private static final TestApp sTestApp = sTestAppProvider
+ .query().whereActivities().isNotEmpty().get();
+ private static final TestApp sTestApp2 = sTestAppProvider.any();
@Test
@PositivePolicyTest(policy = Delegation.class)
public void getDelegatedScopes_returnsFromSetDelegatedScopes() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
sDeviceState.dpc().componentName(),
@@ -104,9 +105,9 @@
}
@Test
- @CannotSetPolicyTest(policy = Delegation.class)
+ @CannotSetPolicyTest(policy = Delegation.class, includeNonDeviceAdminStates = false)
public void setDelegatedScopes_invalidAdmin_throwsSecurityException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
assertThrows(SecurityException.class, () ->
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
sDeviceState.dpc().componentName(),
@@ -118,7 +119,7 @@
@Test
@CannotSetPolicyTest(policy = Delegation.class)
public void getDelegatedScopes_invalidAdmin_throwsSecurityException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
assertThrows(SecurityException.class, () ->
sDeviceState.dpc().devicePolicyManager().getDelegatedScopes(
sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
@@ -128,7 +129,7 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void getDelegatedScopes_returnsLatestFromSetDelegatedScopes() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -171,7 +172,7 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void getDelegatePackages_oneApp_twoScopes_returnsFromSetDelegatedScopes() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -193,9 +194,9 @@
}
@Test
- @CannotSetPolicyTest(policy = Delegation.class)
+ @CannotSetPolicyTest(policy = Delegation.class, includeNonDeviceAdminStates = false)
public void getDelegatePackages_invalidAdmin_throwsSecurityException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
assertThrows(SecurityException.class, () ->
sDeviceState.dpc().devicePolicyManager().getDelegatePackages(
sDeviceState.dpc().componentName(), testApp.testApp().packageName()));
@@ -205,8 +206,8 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void getDelegatePackages_twoApps_differentScopes_returnsFromSetDelegatedScopes() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser);
- TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser);
+ TestAppInstance testApp2 = sTestApp2.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -235,8 +236,8 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void getDelegatePackages_twoApps_sameScope_returnsFromSetDelegatedScopes() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser);
- TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser);
+ TestAppInstance testApp2 = sTestApp2.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -264,7 +265,7 @@
@Test
@PositivePolicyTest(policy = NetworkLoggingDelegation.class)
public void setDelegatedScopes_networkLogging_validAdminType_noException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
sDeviceState.dpc().componentName(),
@@ -277,9 +278,10 @@
}
@Test
- @CannotSetPolicyTest(policy = NetworkLoggingDelegation.class)
+ @CannotSetPolicyTest(
+ policy = NetworkLoggingDelegation.class, includeNonDeviceAdminStates = false)
public void setDelegatedScopes_networkLogging_invalidAdminType_throwsSecurityException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
assertThrows(SecurityException.class, () ->
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -297,7 +299,7 @@
// TODO(b/198774281): add a negative policy test (in line with all the others here) once we can
// correctly mark security logging delegation as possible for COPE profile POs.
public void setDelegatedScopes_securityLogging_validAdminType_noException() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
sDeviceState.dpc().componentName(),
@@ -312,8 +314,8 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void setDelegatedScopes_certSelection_settingSecondApp_revokesFirstApp() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser);
- TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser);
+ TestAppInstance testApp2 = sTestApp2.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -346,8 +348,8 @@
@Test
@PositivePolicyTest(policy = NetworkLoggingDelegation.class)
public void setDelegatedScopes_networkLogging_settingSecondApp_revokesFirstApp() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser);
- TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser);
+ TestAppInstance testApp2 = sTestApp2.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -380,8 +382,8 @@
@Test
@PositivePolicyTest(policy = SecurityLoggingDelegation.class)
public void setDelegatedScopes_securityLogging_settingSecondApp_revokesFirstApp() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser);
- TestAppInstance testApp2 = sTestAppProvider2.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser);
+ TestAppInstance testApp2 = sTestApp2.install(sUser)) {
try {
sDeviceState.dpc().devicePolicyManager().setDelegatedScopes(
@@ -414,7 +416,7 @@
@Test
@PositivePolicyTest(policy = Delegation.class)
public void setDelegatedScopes_delegatedPackageReceivesScopesFromBroadcast() {
- try (TestAppInstance testApp = sTestAppProvider.install(sUser)) {
+ try (TestAppInstance testApp = sTestApp.install(sUser)) {
// TODO(b/198769413): we should not need to start (or query for) an activity, but the
// event is not received for some reason without it.
testApp.activities().any().start();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
deleted file mode 100644
index 2579f14..0000000
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeprecatedPasswordAPIsTest.java
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * 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.devicepolicy.cts;
-
-import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
-
-import static com.google.common.truth.Truth.assertWithMessage;
-
-import android.app.admin.DevicePolicyManager;
-import android.app.admin.RemoteDevicePolicyManager;
-import android.content.ComponentName;
-import android.content.Context;
-
-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.RequireDoesNotHaveFeature;
-import com.android.bedstead.harrier.annotations.RequireFeature;
-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 org.junit.Before;
-import org.junit.ClassRule;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-/**
- * Test cases for password management APIs that are deprecated and not supported in some platforms.
- */
-@RunWith(BedsteadJUnit4.class)
-public final class DeprecatedPasswordAPIsTest {
-
- @ClassRule
- @Rule
- public static final DeviceState sDeviceState = new DeviceState();
-
- private static final Context sContext = TestApis.context().instrumentedContext();
-
- private ComponentName mAdmin;
- private RemoteDevicePolicyManager mDpm;
-
- @Before
- public void setUp() {
- RemoteDpc dpc = sDeviceState.dpc();
- mAdmin = dpc.devicePolicyController().componentName();
- mDpm = dpc.devicePolicyManager();
- }
-
- @Test
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- @RequireFeature(FEATURE_AUTOMOTIVE)
- public void testPasswordQuality_featureUnsupported_returnsUnspecified() {
- mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
-
- assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
- .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordQuality_featureSupported_returnsValueSet() {
- mDpm.setPasswordQuality(mAdmin, DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
-
- assertWithMessage("getPasswordQuality()").that(mDpm.getPasswordQuality(mAdmin))
- .isEqualTo(DevicePolicyManager.PASSWORD_QUALITY_ALPHABETIC);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLength_featureUnsupported_ignored() {
- int valueBefore = mDpm.getPasswordMinimumLength(mAdmin);
-
- mDpm.setPasswordMinimumLength(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLength()")
- .that(mDpm.getPasswordMinimumLength(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLength_featureSupported_returnsValueSet() {
- mDpm.setPasswordMinimumLength(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLength()")
- .that(mDpm.getPasswordMinimumLength(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumNumeric_ignored() {
- int valueBefore = mDpm.getPasswordMinimumNumeric(mAdmin);
-
- mDpm.setPasswordMinimumNumeric(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumNumeric()")
- .that(mDpm.getPasswordMinimumNumeric(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumNumeric_returnsValueSet() {
- mDpm.setPasswordMinimumNumeric(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumNumeric()")
- .that(mDpm.getPasswordMinimumNumeric(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLowerCase_ignored() {
- int valueBefore = mDpm.getPasswordMinimumLowerCase(mAdmin);
-
- mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLowerCase()")
- .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLowerCase_returnsValueSet() {
- mDpm.setPasswordMinimumLowerCase(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLowerCase()")
- .that(mDpm.getPasswordMinimumLowerCase(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumUpperCase_ignored() {
- int valueBefore = mDpm.getPasswordMinimumUpperCase(mAdmin);
-
- mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumUpperCase()")
- .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumUpperCase_returnsValueSet() {
- mDpm.setPasswordMinimumUpperCase(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumUpperCase()")
- .that(mDpm.getPasswordMinimumUpperCase(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLetters_ignored() {
- int valueBefore = mDpm.getPasswordMinimumLetters(mAdmin);
-
- mDpm.setPasswordMinimumLetters(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLetters()")
- .that(mDpm.getPasswordMinimumLetters(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumLetters_returnsValueSet() {
- mDpm.setPasswordMinimumLetters(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumLetters()")
- .that(mDpm.getPasswordMinimumLetters(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumSymbols_ignored() {
- int valueBefore = mDpm.getPasswordMinimumSymbols(mAdmin);
-
- mDpm.setPasswordMinimumSymbols(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumSymbols()")
- .that(mDpm.getPasswordMinimumSymbols(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumSymbols_returnsValueSet() {
- mDpm.setPasswordMinimumSymbols(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumSymbols()")
- .that(mDpm.getPasswordMinimumSymbols(mAdmin))
- .isEqualTo(42);
- }
-
- @Test
- @RequireFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumNonLetter_ignored() {
- int valueBefore = mDpm.getPasswordMinimumNonLetter(mAdmin);
-
- mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumNonLetter()")
- .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
- .isEqualTo(valueBefore);
- }
-
- @Test
- @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
- @PositivePolicyTest(policy = DeprecatedPasswordAPIs.class)
- @Postsubmit(reason = "new test")
- public void testPasswordMinimumNonLetter_returnsValueSet() {
- mDpm.setPasswordMinimumNonLetter(mAdmin, 42);
-
- assertWithMessage("getPasswordMinimumNonLetter()")
- .that(mDpm.getPasswordMinimumNonLetter(mAdmin))
- .isEqualTo(42);
- }
-}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
index 00aea6f..264dd12 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/DeviceOwnerPrerequisitesTest.java
@@ -48,7 +48,7 @@
import org.junit.runner.RunWith;
@RunWith(BedsteadJUnit4.class)
-public class DeviceOwnerPrerequisitesTest {
+public final class DeviceOwnerPrerequisitesTest {
@ClassRule
@Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
index 0b65080..16a7733 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/KeyManagementTest.java
@@ -62,6 +62,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
@@ -69,11 +70,12 @@
* keys by requesting access to them and retrieving them via KeyChain APIs.
*/
@RunWith(BedsteadJUnit4.class)
-public class KeyManagementTest {
+public final class KeyManagementTest {
@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 =
@@ -279,7 +281,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);
@@ -299,7 +302,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);
@@ -317,7 +321,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/LockTaskTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
index 758d794..6f9128d 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/LockTaskTest.java
@@ -79,7 +79,7 @@
import java.util.Set;
@RunWith(BedsteadJUnit4.class)
-public class LockTaskTest {
+public final class LockTaskTest {
@ClassRule
@Rule
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
index 7b3ff7e..d3b7087 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NegativeCallAuthorizationTest.java
@@ -43,7 +43,7 @@
*/
@SmallTest
@RunWith(BedsteadJUnit4.class)
-public class NegativeCallAuthorizationTest {
+public final class NegativeCallAuthorizationTest {
private static final String ALIAS = "some-alias";
private static final Context sContext = ApplicationProvider.getApplicationContext();
private static final DevicePolicyManager sDpm =
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NetworkResetTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkResetTest.java
index 1e10db7..5bad1c7 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NetworkResetTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NetworkResetTest.java
@@ -49,7 +49,7 @@
// TODO(b/189280629): Move this test to to net test folder to live with other network reset tests.
@RunWith(BedsteadJUnit4.class)
-public class NetworkResetTest {
+public final class NetworkResetTest {
@ClassRule @Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NonExportedActivity.java b/tests/devicepolicy/src/android/devicepolicy/cts/NonExportedActivity.java
index a76f4ee..25ba6f7 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NonExportedActivity.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NonExportedActivity.java
@@ -19,5 +19,5 @@
import android.app.Activity;
/** Activity used for Cross Profile Apps Tests */
-public class NonExportedActivity extends Activity {
+public final class NonExportedActivity extends Activity {
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/NonMainActivity.java b/tests/devicepolicy/src/android/devicepolicy/cts/NonMainActivity.java
index 7ef5f8a..98b8b11 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/NonMainActivity.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/NonMainActivity.java
@@ -19,5 +19,5 @@
import android.app.Activity;
/** Activity used for Cross Profile Apps Tests */
-public class NonMainActivity extends Activity {
+public final class NonMainActivity extends Activity {
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PermissionGrantTest.java
index a56b9ac..4545f94 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;
@@ -61,7 +63,7 @@
import org.junit.runner.RunWith;
@RunWith(BedsteadJUnit4.class)
-public class PermissionGrantTest {
+public final class PermissionGrantTest {
@ClassRule
@Rule
@@ -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, includeDeviceAdminStates = 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/PreferentialNetworkServiceTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
index 3d5f7ef..51f672c 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/PreferentialNetworkServiceTest.java
@@ -55,7 +55,7 @@
// TODO(b/190797743): Move this test to to net test folder.
@RunWith(BedsteadJUnit4.class)
-public class PreferentialNetworkServiceTest {
+public final class PreferentialNetworkServiceTest {
@ClassRule @Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
index 5614255..4a27ae9 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ResetPasswordWithTokenTest.java
@@ -26,11 +26,13 @@
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_NUMERIC;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_SOMETHING;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED;
+import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static com.android.bedstead.metricsrecorder.truth.MetricQueryBuilderSubject.assertThat;
import static com.android.bedstead.remotedpc.RemoteDpc.DPC_COMPONENT_NAME;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static org.junit.Assume.assumeTrue;
@@ -42,6 +44,8 @@
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.RequireDoesNotHaveFeature;
+import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.enterprise.CanSetPolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
import com.android.bedstead.harrier.policies.ResetPasswordWithToken;
@@ -55,7 +59,7 @@
// TODO(b/191640667): Parameterize the length limit tests with multiple limits
@RunWith(BedsteadJUnit4.class)
-public class ResetPasswordWithTokenTest {
+public final class ResetPasswordWithTokenTest {
private static final String NOT_COMPLEX_PASSWORD = "1234";
private static final String VALID_PASSWORD = NOT_COMPLEX_PASSWORD;
@@ -154,6 +158,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void resetPasswordWithToken_passwordDoesNotSatisfyRestriction_failure() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -180,6 +186,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void resetPasswordWithToken_passwordSatisfiesRestriction_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -225,6 +233,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void isActivePasswordSufficient_passwordDoesNotSatisfyRestriction_false() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -253,6 +263,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void isActivePasswordSufficient_passwordSatisfiesRestriction_true() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -281,6 +293,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void isActivePasswordSufficient_passwordNoLongerSatisfiesRestriction_false() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -311,6 +325,8 @@
@Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -327,6 +343,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_something_passwordWithAMinLengthOfFourRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -347,6 +365,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_numeric_passwordWithAtLeastOneNumberOrLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -366,6 +386,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_alphabetic_passwordWithAtLeastOneLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -384,6 +406,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_alphanumeric_passwordWithBothALetterAndANumberRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -402,6 +426,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_complex_passwordWithAMinLengthOfFourRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -427,6 +453,8 @@
@Test
@Postsubmit(reason = "new test")
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordMinimumLength is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumLength_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -444,6 +472,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumLength_six_passwordWithAMinLengthOfSixRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -468,6 +498,8 @@
@Test
@Postsubmit(reason = "new test")
+ // setPasswordMinimumUpperCase is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumUpperCase_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
@@ -486,6 +518,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumUpperCase_one_passwordWithAtLeastOneUpperCaseLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -510,6 +544,8 @@
@Test
@Postsubmit(reason = "new test")
+ // setPasswordMinimumLowerCase is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumLowerCase_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
@@ -528,6 +564,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumLowerCase_one_passwordWithAtLeaseOneLowerCaseLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -570,6 +608,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumLetters_one_passwordWithAtLeastOneLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -612,6 +652,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumNumeric_one_passwordWithAtLeastOneNumberRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -654,6 +696,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumSymbols_one_passwordWithAtLeastOneSymbolRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -679,6 +723,8 @@
@Test
@Postsubmit(reason = "new test")
+ // setPasswordMinimumNonLetter is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
@CanSetPolicyTest(policy = ResetPasswordWithToken.class)
public void setPasswordMinimumNonLetter_success() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
@@ -697,6 +743,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordMinimumNonLetter_one_passwordWithAtLeastOneNonLetterRequired() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -723,6 +771,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setRequiredPasswordComplexity_passwordQualityAlreadySet_clearsPasswordQuality() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -743,6 +793,8 @@
@Test
@Postsubmit(reason = "new test")
@PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ // setPasswordQuality is unsupported on automotive
+ @RequireDoesNotHaveFeature(FEATURE_AUTOMOTIVE)
public void setPasswordQuality_passwordComplexityAlreadySet_clearsPasswordComplexity() {
assumeTrue(RESET_PASSWORD_TOKEN_DISABLED, canSetResetPasswordToken(TOKEN));
try {
@@ -894,6 +946,121 @@
}
}
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLength_featureUnsupported_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLength(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumLength(DPC_COMPONENT_NAME, 42);
+
+ assertWithMessage("getPasswordMinimumLength()")
+ .that(sDeviceState.dpc().devicePolicyManager()
+ .getPasswordMinimumLength(DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNumeric_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNumeric(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumNumeric(DPC_COMPONENT_NAME, 42);
+
+ assertWithMessage("getPasswordMinimumNumeric()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNumeric(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLowerCase_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLowerCase(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumLowerCase(DPC_COMPONENT_NAME,
+ 42);
+
+ assertWithMessage("getPasswordMinimumLowerCase()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLowerCase(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumUpperCase_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumUpperCase(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumUpperCase(DPC_COMPONENT_NAME,
+ 42);
+
+ assertWithMessage("getPasswordMinimumUpperCase()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumUpperCase(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumLetters_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLetters(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumLetters(DPC_COMPONENT_NAME, 42);
+
+ assertWithMessage("getPasswordMinimumLetters()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumLetters(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumSymbols_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumSymbols(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumSymbols(DPC_COMPONENT_NAME, 42);
+
+ assertWithMessage("getPasswordMinimumSymbols()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumSymbols(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
+ @Test
+ @RequireFeature(FEATURE_AUTOMOTIVE)
+ @PositivePolicyTest(policy = ResetPasswordWithToken.class)
+ @Postsubmit(reason = "new test")
+ public void testPasswordMinimumNonLetter_ignored() {
+ int valueBefore = sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNonLetter(
+ DPC_COMPONENT_NAME);
+
+ sDeviceState.dpc().devicePolicyManager().setPasswordMinimumNonLetter(DPC_COMPONENT_NAME,
+ 42);
+
+ assertWithMessage("getPasswordMinimumNonLetter()")
+ .that(sDeviceState.dpc().devicePolicyManager().getPasswordMinimumNonLetter(
+ DPC_COMPONENT_NAME))
+ .isEqualTo(valueBefore);
+ }
+
private void assertPasswordSucceeds(String password) {
assertThat(sDeviceState.dpc().devicePolicyManager().resetPasswordWithToken(
DPC_COMPONENT_NAME, password, TOKEN, /* flags = */ 0)).isTrue();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
index f7ef7b2..f49fd9a 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/RingtoneTest.java
@@ -41,7 +41,7 @@
@RunWith(BedsteadJUnit4.class)
@Postsubmit(reason = "New tests")
-public class RingtoneTest {
+public final class RingtoneTest {
@ClassRule @Rule
public static final DeviceState sDeviceState = new DeviceState();
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
index 37c9bdb..c6558e8 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/ScreenCaptureDisabledTest.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.NegativePolicyTest;
import com.android.bedstead.harrier.annotations.enterprise.PositivePolicyTest;
@@ -55,7 +56,7 @@
@RunWith(BedsteadJUnit4.class)
-public class ScreenCaptureDisabledTest {
+public final class ScreenCaptureDisabledTest {
@ClassRule
@Rule
@@ -141,6 +142,7 @@
@Test
@PositivePolicyTest(policy = ScreenCaptureDisabled.class)
@Postsubmit(reason = "new test")
+ @SlowApiTest("Screenshot policy can take minutes to propagate")
public void setScreenCaptureDisabled_true_screenCaptureFails() {
mDevicePolicyManager.setScreenCaptureDisabled(mAdmin, true);
@@ -188,7 +190,7 @@
try (TestAppInstance testApp = sTestApp.install()) {
testApp.activities().any().start();
return Poll.forValue(mUiAutomation::takeScreenshot)
- .timeout(Duration.ofSeconds(60))
+ .timeout(Duration.ofMinutes(5))
.toBeNull()
.await();
}
diff --git a/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
index c6fcd6b..5d8c421 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/StartProfilesTest.java
@@ -43,6 +43,7 @@
import com.android.bedstead.harrier.annotations.Postsubmit;
import com.android.bedstead.harrier.annotations.RequireFeature;
import com.android.bedstead.harrier.annotations.RequireRunOnPrimaryUser;
+import com.android.bedstead.harrier.annotations.SlowApiTest;
import com.android.bedstead.nene.users.UserReference;
import com.android.compatibility.common.util.BlockingBroadcastReceiver;
@@ -60,6 +61,8 @@
private static final ActivityManager sActivityManager =
sContext.getSystemService(ActivityManager.class);
+ private static final int START_PROFILE_BROADCAST_TIMEOUT = 480_000; // 8 minutes
+
@ClassRule @Rule
public static final DeviceState sDeviceState = new DeviceState();
@@ -83,6 +86,7 @@
@RequireRunOnPrimaryUser
@EnsureHasWorkProfile
@EnsureHasPermission({INTERACT_ACROSS_USERS_FULL, INTERACT_ACROSS_USERS, CREATE_USERS})
+ @SlowApiTest("Start profile broadcasts can take a long time")
public void startProfile_broadcastIsReceived_profileIsStarted() {
sDeviceState.workProfile().stop();
BlockingBroadcastReceiver broadcastReceiver = sDeviceState.registerBroadcastReceiver(
@@ -90,7 +94,7 @@
userIsEqual(sDeviceState.workProfile()));
sActivityManager.startProfile(sDeviceState.workProfile().userHandle());
- broadcastReceiver.awaitForBroadcastOrFail();
+ broadcastReceiver.awaitForBroadcastOrFail(START_PROFILE_BROADCAST_TIMEOUT);
assertThat(sUserManager.isUserRunning(sDeviceState.workProfile().userHandle())).isTrue();
}
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/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
index c636a4f..131f7d0 100644
--- a/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
+++ b/tests/devicepolicy/src/android/devicepolicy/cts/UserControlDisabledPackagesTest.java
@@ -59,7 +59,7 @@
import java.util.List;
@RunWith(BedsteadJUnit4.class)
-public class UserControlDisabledPackagesTest {
+public final class UserControlDisabledPackagesTest {
private static final String TAG = "UserControlDisabledPackagesTest";
private static final TestAppProvider sTestAppProvider = new TestAppProvider();
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/ActivityVisibilityTests.java b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
index 2b425c9..401ebaf 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/ActivityVisibilityTests.java
@@ -337,6 +337,44 @@
mWmState.assertHomeActivityVisible(true);
}
+ /**
+ * This test case tests behavior of activity launched with FLAG_ACTIVITY_TASK_ON_HOME in lock
+ * task mode. The home task do not move to the front of the launched task if the home task
+ * is violated with the lock-task mode.
+ */
+ @Test
+ public void testLaunchTaskOnHomeInLockTaskMode() {
+ if (!hasHomeScreen()) {
+ return;
+ }
+ // Start LaunchingActivity and BroadcastReceiverActivity in two separate tasks.
+ getLaunchActivityBuilder().setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+ .setIntentFlags(FLAG_ACTIVITY_NEW_TASK).execute();
+ waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+ final int taskId1 = mWmState.getTaskByActivity(LAUNCHING_ACTIVITY).mTaskId;
+ final int taskId2 = mWmState.getTaskByActivity(BROADCAST_RECEIVER_ACTIVITY).mTaskId;
+
+ try {
+ runWithShellPermission(() -> {
+ mAtm.startSystemLockTaskMode(taskId1);
+ mAtm.startSystemLockTaskMode(taskId2);
+ });
+ getLaunchActivityBuilder()
+ .setUseInstrumentation()
+ .setTargetActivity(BROADCAST_RECEIVER_ACTIVITY)
+ .setIntentFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME).execute();
+ waitAndAssertResumedActivity(BROADCAST_RECEIVER_ACTIVITY,"Activity must be resumed");
+ mBroadcastActionTrigger.finishBroadcastReceiverActivity();
+ mWmState.waitAndAssertActivityRemoved(BROADCAST_RECEIVER_ACTIVITY);
+
+ mWmState.assertHomeActivityVisible(false);
+ } finally {
+ runWithShellPermission(() -> {
+ mAtm.stopSystemLockTaskMode();
+ });
+ }
+ }
+
@Test
public void testFinishActivityWithMoveTaskToBackAfterPause() {
performFinishActivityWithMoveTaskToBack(FINISH_POINT_ON_PAUSE);
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/src/android/server/wm/DisplayAreaPolicyTests.java b/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
index 4f9b023..7dd3d2b 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/DisplayAreaPolicyTests.java
@@ -24,6 +24,7 @@
import android.platform.test.annotations.Presubmit;
import android.server.wm.WindowManagerState.DisplayArea;
import android.server.wm.WindowManagerState.DisplayContent;
+import android.view.Display;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +53,10 @@
mDisplays = mWmState.getDisplays();
}
+ private boolean isTrustedDisplay(DisplayContent displayContent) {
+ return (displayContent.getFlags() & Display.FLAG_TRUSTED) != 0;
+ }
+
/**
* DisplayContent should have feature id of FEATURE_ROOT. It should be organized.
*/
@@ -59,7 +64,10 @@
public void testDisplayContent() {
for (DisplayContent displayContent : mDisplays) {
assertThat(displayContent.getFeatureId()).isEqualTo(FEATURE_ROOT);
- assertThat(displayContent.isOrganized()).isTrue();
+ // DisplayAreaOrganizerController registers the organizer for the trusted displays only.
+ if (isTrustedDisplay(displayContent)) {
+ assertThat(displayContent.isOrganized()).isTrue();
+ }
}
}
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/PinnedStackTests.java b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
index aa3689f..4a4f6b4 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/PinnedStackTests.java
@@ -1300,6 +1300,19 @@
}
@Test
+ public void testAutoPipOnLaunchingAnotherActivity() {
+ // Launch the PIP activity and set its pip params to allow auto-pip.
+ launchActivity(PIP_ACTIVITY, extraString(EXTRA_ALLOW_AUTO_PIP, "true"));
+ assertPinnedStackDoesNotExist();
+
+ // Launch another and ensure that there is a pinned stack.
+ launchActivity(TEST_ACTIVITY);
+ waitForEnterPip(PIP_ACTIVITY);
+ assertPinnedStackExists();
+ waitAndAssertActivityState(PIP_ACTIVITY, STATE_PAUSED, "activity must be paused");
+ }
+
+ @Test
public void testMaxNumberOfActions() {
final int maxNumberActions = ActivityTaskManager.getMaxNumPictureInPictureActions(mContext);
assertThat(maxNumberActions, greaterThanOrEqualTo(3));
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/UnsupportedErrorDialogTests.java b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
index de323ac..6b8be2d 100644
--- a/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
+++ b/tests/framework/base/windowmanager/src/android/server/wm/UnsupportedErrorDialogTests.java
@@ -165,9 +165,13 @@
mWmState.waitAndAssertAppFocus(Components.UNRESPONSIVE_ACTIVITY.getPackageName(),
2_000 /* waitTime */);
// queue up enough key events to trigger an ANR
- for (int i = 0; i < 14; i++) {
+ for (int i = 0; i < 20; i++) {
injectKey(KeyEvent.KEYCODE_TAB, false /* longPress */, false /* sync */);
SystemClock.sleep(500);
+ mWmState.computeState();
+ if (!mWmState.isActivityVisible(Components.UNRESPONSIVE_ACTIVITY)) {
+ break;
+ }
}
ensureNoCrashDialog(Components.UNRESPONSIVE_ACTIVITY);
ensureActivityNotFocused(Components.UNRESPONSIVE_ACTIVITY);
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/location/common/src/android/location/cts/common/OpActiveChangedCapture.java b/tests/location/common/src/android/location/cts/common/OpActiveChangedCapture.java
new file mode 100644
index 0000000..bc69bcb
--- /dev/null
+++ b/tests/location/common/src/android/location/cts/common/OpActiveChangedCapture.java
@@ -0,0 +1,57 @@
+/*
+ * 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.location.cts.common;
+
+import android.app.AppOpsManager;
+import android.os.Looper;
+
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.TimeUnit;
+
+public class OpActiveChangedCapture implements AppOpsManager.OnOpActiveChangedListener,
+ AutoCloseable {
+
+ private final AppOpsManager mAppOps;
+ private final String mOp;
+ private final LinkedBlockingQueue<Boolean> mActives;
+
+ public OpActiveChangedCapture(AppOpsManager appOps, String op) {
+ mAppOps = appOps;
+ mOp = op;
+ mActives = new LinkedBlockingQueue<>();
+ }
+
+ public Boolean getNextActive(long timeoutMs) throws InterruptedException {
+ if (Looper.myLooper() == Looper.getMainLooper()) {
+ throw new AssertionError("getNextActive() called from main thread");
+ }
+
+ return mActives.poll(timeoutMs, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public void close() {
+ mAppOps.stopWatchingActive(this);
+ }
+
+ @Override
+ public void onOpActiveChanged(String op, int uid, String packageName, boolean active) {
+ if (op.equals(mOp)) {
+ mActives.add(active);
+ }
+ }
+}
diff --git a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
index 1be37c3..fffe877 100644
--- a/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
+++ b/tests/location/location_fine/src/android/location/cts/fine/LocationManagerFineTest.java
@@ -17,6 +17,8 @@
package android.location.cts.fine;
import static android.Manifest.permission.WRITE_SECURE_SETTINGS;
+import static android.app.AppOpsManager.OPSTR_MONITOR_HIGH_POWER_LOCATION;
+import static android.app.AppOpsManager.OPSTR_MONITOR_LOCATION;
import static android.content.pm.PackageManager.FEATURE_AUTOMOTIVE;
import static android.content.pm.PackageManager.FEATURE_TELEVISION;
import static android.location.LocationManager.EXTRA_PROVIDER_ENABLED;
@@ -27,6 +29,7 @@
import static android.location.LocationManager.PASSIVE_PROVIDER;
import static android.location.LocationManager.PROVIDERS_CHANGED_ACTION;
import static android.location.LocationRequest.PASSIVE_INTERVAL;
+import static android.location.LocationRequest.QUALITY_HIGH_ACCURACY;
import static android.os.PowerManager.LOCATION_MODE_ALL_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_GPS_DISABLED_WHEN_SCREEN_OFF;
import static android.os.PowerManager.LOCATION_MODE_THROTTLE_REQUESTS_WHEN_SCREEN_OFF;
@@ -52,7 +55,6 @@
import android.app.UiAutomation;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
import android.location.Criteria;
import android.location.GnssMeasurementsEvent;
import android.location.GnssNavigationMessage;
@@ -67,6 +69,7 @@
import android.location.cts.common.GetCurrentLocationCapture;
import android.location.cts.common.LocationListenerCapture;
import android.location.cts.common.LocationPendingIntentCapture;
+import android.location.cts.common.OpActiveChangedCapture;
import android.location.cts.common.ProviderRequestChangedListenerCapture;
import android.location.cts.common.gnss.GnssAntennaInfoCapture;
import android.location.cts.common.gnss.GnssMeasurementsCapture;
@@ -144,15 +147,11 @@
}
mManager.addTestProvider(TEST_PROVIDER,
- true,
- false,
- true,
- false,
- false,
- false,
- false,
- Criteria.POWER_MEDIUM,
- Criteria.ACCURACY_FINE);
+ new ProviderProperties.Builder()
+ .setHasNetworkRequirement(true)
+ .setHasCellRequirement(true)
+ .setPowerUsage(ProviderProperties.POWER_USAGE_HIGH)
+ .setAccuracy(ProviderProperties.ACCURACY_FINE).build());
mManager.setTestProviderEnabled(TEST_PROVIDER, true);
}
@@ -844,6 +843,57 @@
}
@Test
+ public void testMonitoring() throws Exception {
+ AppOpsManager appOps = Objects.requireNonNull(
+ mContext.getSystemService(AppOpsManager.class));
+
+ try (OpActiveChangedCapture opCapture = new OpActiveChangedCapture(appOps,
+ OPSTR_MONITOR_LOCATION);
+ OpActiveChangedCapture opHighPowerCapture = new OpActiveChangedCapture(appOps,
+ OPSTR_MONITOR_HIGH_POWER_LOCATION);
+ LocationListenerCapture capture1 = new LocationListenerCapture(mContext);
+ LocationListenerCapture capture2 = new LocationListenerCapture(mContext);
+ LocationListenerCapture capture3 = new LocationListenerCapture(mContext)) {
+ appOps.startWatchingActive(new String[]{OPSTR_MONITOR_LOCATION}, Runnable::run,
+ opCapture);
+ appOps.startWatchingActive(new String[]{OPSTR_MONITOR_HIGH_POWER_LOCATION},
+ Runnable::run, opHighPowerCapture);
+
+ mManager.requestLocationUpdates(TEST_PROVIDER,
+ new LocationRequest.Builder(Long.MAX_VALUE - 1).build(),
+ Executors.newSingleThreadExecutor(), capture1);
+ assertThat(opCapture.getNextActive(TIMEOUT_MS)).isTrue();
+ assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+
+ mManager.requestLocationUpdates(TEST_PROVIDER, new LocationRequest.Builder(
+ 0).setQuality(
+ QUALITY_HIGH_ACCURACY).build(),
+ Executors.newSingleThreadExecutor(), capture2);
+ assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+ assertThat(opHighPowerCapture.getNextActive(TIMEOUT_MS)).isTrue();
+
+ mManager.requestLocationUpdates(TEST_PROVIDER, new LocationRequest.Builder(
+ 0).setQuality(
+ QUALITY_HIGH_ACCURACY).build(),
+ Executors.newSingleThreadExecutor(), capture3);
+ assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+ assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+
+ mManager.removeUpdates(capture2);
+ assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+ assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+
+ mManager.removeUpdates(capture3);
+ assertThat(opCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+ assertThat(opHighPowerCapture.getNextActive(TIMEOUT_MS)).isFalse();
+
+ mManager.removeUpdates(capture1);
+ assertThat(opCapture.getNextActive(TIMEOUT_MS)).isFalse();
+ assertThat(opHighPowerCapture.getNextActive(FAILURE_TIMEOUT_MS)).isNull();
+ }
+ }
+
+ @Test
public void testAddProviderRequestListener() throws Exception {
InstrumentationRegistry.getInstrumentation().getUiAutomation()
.adoptShellPermissionIdentity(Manifest.permission.LOCATION_HARDWARE);
diff --git a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
index bc813aa..b6ee78c 100644
--- a/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
+++ b/tests/tests/carrierapi/src/android/carrierapi/cts/CarrierApiTest.java
@@ -1086,7 +1086,8 @@
try {
// Get all active subscriptions.
List<SubscriptionInfo> activeSubInfos =
- mSubscriptionManager.getActiveSubscriptionInfoList();
+ ShellIdentityUtils.invokeMethodWithShellPermissions(mSubscriptionManager,
+ (sm) -> sm.getActiveSubscriptionInfoList());
List<Integer> activeSubGroup = getSubscriptionIdList(activeSubInfos);
activeSubGroup.removeIf(id -> id == subId);
@@ -1262,13 +1263,17 @@
}
private void removeSubscriptionsFromGroup(ParcelUuid uuid) {
- List<SubscriptionInfo> infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+ List<SubscriptionInfo> infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager,
+ (sm) -> (sm.getSubscriptionsInGroup(uuid)));
if (!infoList.isEmpty()) {
List<Integer> subscriptionIdList = getSubscriptionIdList(infoList);
ShellIdentityUtils.invokeMethodWithShellPermissionsNoReturn(mSubscriptionManager,
(sm) -> sm.removeSubscriptionsFromGroup(subscriptionIdList, uuid));
}
- infoList = mSubscriptionManager.getSubscriptionsInGroup(uuid);
+ infoList = ShellIdentityUtils.invokeMethodWithShellPermissions(
+ mSubscriptionManager,
+ (sm) -> (sm.getSubscriptionsInGroup(uuid)));
assertThat(infoList).isEmpty();
}
diff --git a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
index ba34269..6149732 100644
--- a/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
+++ b/tests/tests/graphics/src/android/graphics/cts/SystemPaletteTest.java
@@ -26,6 +26,7 @@
import android.graphics.cts.utils.Cam;
import android.util.Pair;
+
import androidx.annotation.ColorInt;
import androidx.core.graphics.ColorUtils;
import androidx.test.filters.SmallTest;
@@ -35,15 +36,18 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class SystemPaletteTest {
// Hue goes from 0 to 360
- private static final int MAX_HUE_DISTANCE = 30;
+ private static final int MAX_HUE_DISTANCE = 12;
@Test
public void testShades0and1000() {
@@ -72,16 +76,56 @@
getAllAccent2Colors(context), getAllAccent3Colors(context),
getAllNeutral1Colors(context), getAllNeutral2Colors(context));
+ final float[] tones = {100, 99, 95, 90, 80, 70, 60, 49, 40, 30, 20, 10, 0};
for (int[] palette : allPalettes) {
- for (int i = 3; i < palette.length - 1; i++) {
- assertWithMessage("Color " + Integer.toHexString((palette[i - 1]))
- + " has different hue compared to " + Integer.toHexString(palette[i])
- + " for palette: " + Arrays.toString(palette))
- .that(similarHue(palette[i - 1], palette[i])).isTrue();
+ // Determine the median hue of the palette. Each color in the palette colors will have
+ // its hue measured against the median hue. If the difference is too large, the test
+ // fails.
+ List<Float> hues = new ArrayList<>();
+ for (int i = 0; i < palette.length - 1; i++) {
+ // Avoid measuring hue of colors above 90 or below 10 in tone.
+ //
+ // Converting from HCT to sRGB from display quantizes colors - i.e. not every
+ // HCT color can be expressed in sRGB. As colors approach the extreme tones, white
+ // at 100 and black at 0, hues begin overlapping overlay - made up example: hues
+ // 110 to 128 at tone 95, when mapped to sRGB for display, all end up being measured
+ // as hue 114.
+ final float tone = tones[i];
+ if (tone < 10.0 || tone > 90.0) {
+ continue;
+ }
+ final Cam cam = Cam.fromInt(palette[i]);
+ hues.add(cam.getHue());
+ }
+ Collections.sort(hues);
+ final float medianHue = hues.get(hues.size() / 2);
+
+ // Measure the hue of each color in the palette against the median hue.
+ for (int i = 0; i < palette.length - 1; i++) {
+ final float tone = tones[i];
+ // Skip testing hue of extreme tones, due to overlap due to quantization that occurs
+ // when converting from HCT to sRGB for display.
+ if (tone < 10.0 || tone > 90.0) {
+ continue;
+ }
+ final Cam cam = Cam.fromInt(palette[i]);
+ final float hue = cam.getHue();
+ final boolean hueWithinTolerance = deltaHueWithinTolerance(hue, medianHue);
+ assertWithMessage("Color " + toHctString(cam)
+ + " has different hue compared to median hue " + Math.round(medianHue)
+ + " of palette: " + Arrays.toString(palette))
+ .that(hueWithinTolerance).isTrue();
}
}
}
+ private static String toHctString(Cam cam) {
+ final double[] labColor = new double[3];
+ ColorUtils.colorToLAB(cam.viewedInSrgb(), labColor);
+ return "H" + Math.round(cam.getHue()) + " C" + Math.round(cam.getChroma()) + " T"
+ + Math.round(labColor[0]);
+ }
+
/**
* Compare if color A and B have similar hue, in gCAM space.
*
@@ -89,12 +133,10 @@
* @param colorB Color 2
* @return True when colors have similar hue.
*/
- private boolean similarHue(@ColorInt int colorA, @ColorInt int colorB) {
- final Cam camA = Cam.fromInt(colorA);
- final Cam camB = Cam.fromInt(colorB);
+ private boolean deltaHueWithinTolerance(float hueA, float hueB) {
- float hue1 = Math.max(camA.getHue(), camB.getHue());
- float hue2 = Math.min(camA.getHue(), camB.getHue());
+ float hue1 = Math.max(hueA, hueB);
+ float hue2 = Math.min(hueA, hueB);
float diffDegrees = 180.0f - Math.abs(Math.abs(hue1 - hue2) - 180.0f);
return diffDegrees < MAX_HUE_DISTANCE;
diff --git a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
index 010773f..9b414ff 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AndroidKeyStoreTest.java
@@ -18,6 +18,7 @@
import android.content.pm.PackageManager;
import android.security.KeyPairGeneratorSpec;
+import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.test.AndroidTestCase;
@@ -25,6 +26,8 @@
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import org.junit.Assert;
+
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
@@ -61,6 +64,7 @@
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.security.auth.x500.X500Principal;
@@ -1775,6 +1779,43 @@
mKeyStore.setEntry(TEST_ALIAS_1, entry, null);
}
+ /*
+ * Replacing an existing secret key with itself should be a no-op.
+ */
+ public void testKeyStore_SetKeyEntry_ReplacedWithSameGeneratedSecretKey()
+ throws Exception {
+ final String plaintext = "My awesome plaintext message!";
+ final String algorithm = "AES/GCM/NoPadding";
+
+ final KeyGenerator generator = KeyGenerator.getInstance("AES", "AndroidKeyStore");
+ final KeyGenParameterSpec spec = new KeyGenParameterSpec.Builder(TEST_ALIAS_1,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setKeySize(256)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build();
+ generator.init(spec);
+ final SecretKey key = generator.generateKey();
+
+ Cipher cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ AlgorithmParameters params = cipher.getParameters();
+ final byte[] ciphertext = cipher.doFinal(plaintext.getBytes());
+
+ mKeyStore.load(null, null);
+
+ // This should succeed.
+ mKeyStore.setKeyEntry(TEST_ALIAS_1, key, null, null);
+ // And it should not change the key under TEST_ALIAS_1. And what better way to test
+ // then to use it on some cipher text generated with that key.
+ final Key key2 = mKeyStore.getKey(TEST_ALIAS_1, null);
+ cipher = Cipher.getInstance(algorithm);
+ cipher.init(Cipher.DECRYPT_MODE, key2, params);
+ byte[] plaintext2 = cipher.doFinal(ciphertext);
+ Assert.assertArrayEquals("The plaintext2 should match the original plaintext.",
+ plaintext2, plaintext.getBytes());
+ }
+
public void testKeyStore_Size_Unencrypted_Success() throws Exception {
mKeyStore.load(null, null);
diff --git a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
index 9101f3b..caa18a0 100644
--- a/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/AttestationPerformanceTest.java
@@ -35,6 +35,10 @@
};
public void testRsaKeyAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
for (byte[] challenge : ATTESTATION_CHALLENGES) {
for (int keySize : RSA_KEY_SIZES) {
measure(new KeystoreAttestationMeasurable(
@@ -45,6 +49,10 @@
}
public void testEcKeyAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
for (byte[] challenge : ATTESTATION_CHALLENGES) {
for (int curve : EC_CURVES) {
measure(new KeystoreAttestationMeasurable(
diff --git a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
index 5a3b712..85de847 100644
--- a/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
+++ b/tests/tests/keystore/src/android/keystore/cts/KeyAttestationTest.java
@@ -159,6 +159,10 @@
@RequiresDevice
public void testEcAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -212,6 +216,10 @@
}
public void testEcAttestation_TooLargeChallenge() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
boolean[] devicePropertiesAttestationValues = {true, false};
for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
try {
@@ -266,6 +274,10 @@
@RestrictedBuildTest
@RequiresDevice
public void testEcAttestation_DeviceLocked() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -426,6 +438,10 @@
@RequiresDevice
public void testRsaAttestation() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
@@ -488,6 +504,10 @@
}
public void testRsaAttestation_TooLargeChallenge() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
boolean[] devicePropertiesAttestationValues = {true, false};
for (boolean devicePropertiesAttestation : devicePropertiesAttestationValues) {
try {
@@ -542,6 +562,10 @@
@RestrictedBuildTest
@RequiresDevice // Emulators have no place to store the needed key
public void testRsaAttestation_DeviceLocked() throws Exception {
+ if (!TestUtils.isAttestationSupported()) {
+ return;
+ }
+
if (getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC))
return;
diff --git a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
index aeb3ad6..4efa171 100644
--- a/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
+++ b/tests/tests/keystore/src/android/keystore/cts/TestUtils.java
@@ -19,6 +19,7 @@
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.FeatureInfo;
+import android.os.Build;
import android.os.SystemProperties;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyInfo;
@@ -1080,4 +1081,8 @@
new SecureRandom().nextBytes(message);
return message;
}
+
+ public static boolean isAttestationSupported() {
+ return Build.VERSION.DEVICE_INITIAL_SDK_INT >= Build.VERSION_CODES.O;
+ }
}
diff --git a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
index 634ec56..178b426 100644
--- a/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
+++ b/tests/tests/libthermalndk/src/android/thermal/cts/NativeThermalTest.java
@@ -21,6 +21,7 @@
import android.support.test.uiautomator.UiDevice;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.compatibility.common.util.CddTest;
import com.google.common.base.Strings;
import org.junit.After;
@@ -126,6 +127,7 @@
*
* @throws Exception
*/
+ @CddTest(requirement="7.3.6")
@Test
public void testGetThermalHeadroom() throws Exception {
final String failureMessage = nativeTestGetThermalHeadroom();
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/mediatranscoding/OWNERS b/tests/tests/mediatranscoding/OWNERS
index e653979..a4393a7 100644
--- a/tests/tests/mediatranscoding/OWNERS
+++ b/tests/tests/mediatranscoding/OWNERS
@@ -1,4 +1,4 @@
# Bug component: 761430
-hkuang@google.com
-chz@google.com
-lnilsson@google.com
+
+# go/android-fwk-media-solutions for info on areas of ownership.
+include platform/frameworks/av:/media/janitors/media_solutions_OWNERS
diff --git a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
index 932cbaf..598996c 100644
--- a/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
+++ b/tests/tests/os/src/android/os/cts/PowerManager_ThermalTest.java
@@ -32,6 +32,7 @@
import androidx.test.InstrumentationRegistry;
+import com.android.compatibility.common.util.CddTest;
import com.android.compatibility.common.util.ThermalUtils;
import org.junit.After;
@@ -126,6 +127,12 @@
.times(1)).onThermalStatusChanged(status);
}
+ /**
+ * Test that getThermalHeadroom works
+ *
+ * @throws Exception
+ */
+ @CddTest(requirement="7.3.6")
@Test
public void testGetThermalHeadroom() throws Exception {
float headroom = mPowerManager.getThermalHeadroom(0);
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/vcn/src/android/net/vcn/cts/VcnManagerTest.java b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
index 33df595..9670611 100644
--- a/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
+++ b/tests/tests/vcn/src/android/net/vcn/cts/VcnManagerTest.java
@@ -442,8 +442,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -563,8 +565,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
@@ -662,8 +666,10 @@
// Get current cell Network then wait for it to drop (due to losing NOT_VCN_MANAGED) before
// waiting for VCN Network.
- final NetworkRequest cellNetworkReq =
- new NetworkRequest.Builder().addTransportType(TRANSPORT_CELLULAR).build();
+ final NetworkRequest cellNetworkReq = new NetworkRequest.Builder()
+ .addTransportType(TRANSPORT_CELLULAR)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .build();
final VcnTestNetworkCallback cellNetworkCb = new VcnTestNetworkCallback();
mConnectivityManager.requestNetwork(cellNetworkReq, cellNetworkCb);
final Network cellNetwork = cellNetworkCb.waitForAvailable();
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 ad351a7..ec76300 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsFixedCollectionAdapterTest.java
@@ -21,6 +21,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertThrows;
@@ -36,6 +37,8 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SizeF;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -58,13 +61,20 @@
import com.android.compatibility.common.util.WidgetTestUtils;
+import com.google.common.collect.Lists;
+
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+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;
+import java.util.stream.Collectors;
@MediumTest
@RunWith(AndroidJUnit4.class)
@@ -116,11 +126,7 @@
.addItem(5 /* id */, new RemoteViews(PACKAGE_NAME, R.layout.textview_gravity))
.build();
- Parcel parcel = Parcel.obtain();
- items.writeToParcel(parcel, 0 /* flags */);
- parcel.setDataPosition(0);
-
- RemoteCollectionItems unparceled = RemoteCollectionItems.CREATOR.createFromParcel(parcel);
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
assertEquals(2, unparceled.getItemCount());
assertEquals(3, unparceled.getItemId(0));
assertEquals(5, unparceled.getItemId(1));
@@ -128,8 +134,78 @@
assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
assertTrue(unparceled.hasStableIds());
assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
- parcel.recycle();
+ // Parcel and unparcel the RemoteViews and test again to ensure that the parent child
+ // relationship is correctly established from the Parcel constructor.
+ unparceled = parcelAndUnparcel(unparceled);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+ }
+
+ @Test
+ public void testParcelingAndUnparceling_afterAttaching() {
+ 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(PACKAGE_NAME, R.layout.textview_gravity))
+ .build();
+
+ RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ parent.setRemoteAdapter(R.id.listview_default, items);
+
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertSame(
+ unparceled.getItemView(0).mApplication, unparceled.getItemView(1).mApplication);
+ }
+
+ @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(otherPackageName.get(), R.layout.textview_gravity))
+ .build();
+
+ RemoteViews parent = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ parent.setRemoteAdapter(R.id.listview_default, items);
+
+ RemoteCollectionItems unparceled = parcelAndUnparcel(items);
+ assertEquals(2, unparceled.getItemCount());
+ assertEquals(3, unparceled.getItemId(0));
+ assertEquals(5, unparceled.getItemId(1));
+ assertEquals(R.layout.textview_singleline, unparceled.getItemView(0).getLayoutId());
+ assertEquals(R.layout.textview_gravity, unparceled.getItemView(1).getLayoutId());
+ assertTrue(unparceled.hasStableIds());
+ assertEquals(10, unparceled.getViewTypeCount());
+ assertNotNull(unparceled.getItemView(0).mApplication);
+ assertNotNull(unparceled.getItemView(1).mApplication);
+ assertEquals(PACKAGE_NAME, unparceled.getItemView(0).mApplication.packageName);
+ assertEquals(otherPackageName.get(), unparceled.getItemView(1).mApplication.packageName);
}
@Test
@@ -234,6 +310,129 @@
}
@Test
+ public void testSerializationSize_largeCollection() {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 7,408 when test was written.
+ assertLessThan(10_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollection_multiPackage() {
+ Optional<String> otherPackageName = getAnotherPackageName();
+ if (!otherPackageName.isPresent()) return;
+ RemoteCollectionItems items =
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackageName.get());
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 9,140 when test was written.
+ assertLessThan(12_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_extraLargeCollection() {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 1000);
+
+ int dataSize = parcelAndRun(items, Parcel::dataSize);
+
+ // 50,608 when test was written.
+ assertLessThan(70_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInLandPortRemoteViews() {
+ RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleCollectionItems(/* size= */ 100));
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleCollectionItems(/* size= */ 100));
+
+ RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 12,336 when test was written.
+ assertLessThan(15_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInLandPortRemoteViews_multiPackage() {
+ 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.get()));
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ landscape.setRemoteAdapter(
+ R.id.listview_default,
+ createSampleMultiPackageCollectionItems(/* size= */ 100, otherPackage.get()));
+
+ RemoteViews joinedRemoteViews = new RemoteViews(landscape, portrait);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 14,068 when test was written.
+ assertLessThan(20_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInSizedRemoteViews() {
+ List<SizeF> sizes =
+ Lists.newArrayList(
+ new SizeF(50, 50),
+ new SizeF(50, 100),
+ new SizeF(100, 100),
+ new SizeF(200, 100));
+ Map<SizeF, RemoteViews> sizeToRemoteViews =
+ sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+ RemoteCollectionItems items = createSampleCollectionItems(/* size= */ 100);
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ views.setRemoteAdapter(R.id.listview_default, items);
+ return views;
+ }));
+ RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 22,100 when test was written.
+ assertLessThan(30_000, dataSize);
+ }
+
+ @Test
+ public void testSerializationSize_largeCollectionInSizedRemoteViews_multiPackage() {
+ Optional<String> otherPackage = getAnotherPackageName();
+ if (!otherPackage.isPresent()) return;
+ List<SizeF> sizes =
+ Lists.newArrayList(
+ new SizeF(50, 50),
+ new SizeF(50, 100),
+ new SizeF(100, 100),
+ new SizeF(200, 100));
+ Map<SizeF, RemoteViews> sizeToRemoteViews =
+ sizes.stream().collect(Collectors.toMap(Function.identity(), ignored -> {
+ RemoteCollectionItems items =
+ createSampleMultiPackageCollectionItems(
+ /* size= */ 100, otherPackage.get());
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.listview_layout);
+ views.setRemoteAdapter(R.id.listview_default, items);
+ return views;
+ }));
+ RemoteViews joinedRemoteViews = new RemoteViews(sizeToRemoteViews);
+
+ int dataSize = parcelAndRun(joinedRemoteViews, Parcel::dataSize);
+
+ // 23,832 when test was written.
+ assertLessThan(30_000, dataSize);
+ }
+
+ @Test
public void testSetRemoteAdapter_emptyCollection() {
RemoteCollectionItems items = new RemoteCollectionItems.Builder().build();
mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
@@ -316,7 +515,7 @@
.addItem(12 /* id= */, item2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
WidgetTestUtils.runOnMainAndLayoutSync(mActivityRule,
() -> mRemoteViews.reapply(mActivity, mView), true);
@@ -458,7 +657,7 @@
.setViewTypeCount(2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
Adapter initialAdapter = listView.getAdapter();
@@ -469,7 +668,7 @@
.addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
.setViewTypeCount(2)
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
// The adapter should have been kept, and the second item should have maintained its view
@@ -489,7 +688,7 @@
.addItem(10 /* id= */, new RemoteViews(PACKAGE_NAME, R.layout.listitemfixed_layout))
.build();
- mRemoteViews.setRemoteAdapter(R.id.remoteView_list, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_list, parcelAndUnparcel(items));
runOnMainAndDrawSync(mActivityRule, listView, () -> mRemoteViews.reapply(mActivity, mView));
Adapter initialAdapter = listView.getAdapter();
@@ -540,7 +739,7 @@
mGridView, () -> {
mListView.setVisibility(View.GONE);
mGridView.setVisibility(View.VISIBLE);
- mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, items);
+ mRemoteViews.setRemoteAdapter(R.id.remoteView_grid, parcelAndUnparcel(items));
mRemoteViews.reapply(mActivity, mView);
});
@@ -624,6 +823,27 @@
assertEquals(11, adapter.getItemId(1));
}
+ private static RemoteCollectionItems parcelAndUnparcel(RemoteCollectionItems items) {
+ return parcelAndRun(items, RemoteCollectionItems.CREATOR::createFromParcel);
+ }
+
+ private static <T> T parcelAndRun(Parcelable parcelable, Function<Parcel, T> function) {
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, /* flags= */ 0);
+ parcel.setDataPosition(0);
+ try {
+ return function.apply(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static void assertLessThan(int expected, int actual) {
+ if (actual >= expected) {
+ fail("Expected to be less than " + expected + ", but was " + actual);
+ }
+ }
+
private static final class MockBroadcastReceiver extends BroadcastReceiver {
Intent mIntent;
@@ -666,4 +886,35 @@
}
}
+ private static RemoteCollectionItems createSampleCollectionItems(int size) {
+ RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+ for (int i = 0; i < size; i++) {
+ builder.addItem(i,
+ new RemoteViews(PACKAGE_NAME, R.layout.textview_singleline));
+ }
+ return builder.build();
+ }
+
+ private static RemoteCollectionItems createSampleMultiPackageCollectionItems(
+ int size, String otherPackage) {
+ RemoteCollectionItems.Builder builder = new RemoteCollectionItems.Builder();
+ for (int i = 0; i < size; i++) {
+ String packageName = i % 2 == 0 ? PACKAGE_NAME : otherPackage;
+ builder.addItem(i, new RemoteViews(packageName, R.layout.textview_singleline));
+ }
+ return builder.build();
+ }
+
+ /**
+ * Returns a different package on the device that can be used for testing multi-package
+ * collections.
+ */
+ private Optional<String> getAnotherPackageName() {
+ return mActivity.getPackageManager()
+ .getInstalledApplications(/* flags= */ 0)
+ .stream()
+ .filter(info -> !PACKAGE_NAME.equals(info.packageName))
+ .findFirst()
+ .map(info -> info.packageName);
+ }
}
diff --git a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
index fdbd6b4..0cadd73 100644
--- a/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
+++ b/tests/tests/widget/src/android/widget/cts/RemoteViewsTest.java
@@ -55,8 +55,11 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
+import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.DisplayMetrics;
+import android.util.SizeF;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@@ -101,6 +104,7 @@
import com.android.compatibility.common.util.WidgetTestUtils;
import org.junit.After;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -112,6 +116,10 @@
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
/**
* Test {@link RemoteViews}.
@@ -499,12 +507,9 @@
public void testWriteToParcel() {
mRemoteViews.setTextViewText(R.id.remoteView_text, "This is content");
mRemoteViews.setViewVisibility(R.id.remoteView_frame, View.GONE);
- Parcel p = Parcel.obtain();
- mRemoteViews.writeToParcel(p, 0);
- p.setDataPosition(0);
// the package and layout are successfully written into parcel
- mRemoteViews = RemoteViews.CREATOR.createFromParcel(p);
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
View result = mRemoteViews.apply(mContext, null);
assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
assertEquals(R.layout.remoteviews_good, mRemoteViews.getLayoutId());
@@ -512,12 +517,8 @@
.getText().toString());
assertEquals(View.GONE, result.findViewById(R.id.remoteView_frame).getVisibility());
- p = Parcel.obtain();
-
// currently the flag is not used
- mRemoteViews.writeToParcel(p, -1);
-
- p.recycle();
+ parcelAndUnparcel(mRemoteViews, /* flags= */ -1);
RemoteViews[] remote = RemoteViews.CREATOR.newArray(1);
assertNotNull(remote);
@@ -529,6 +530,51 @@
mRemoteViews.writeToParcel(null, 0);
}
+ @Test
+ public void testWriteToParcel_landscapePortrait() {
+ RemoteViews landscape = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ landscape.setTextViewText(R.id.remoteView_text, "Hello world");
+ RemoteViews portrait = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ portrait.setTextViewText(R.id.remoteView_text, "Hello world");
+ int landscapeParcelledSize = getParcelledSize(landscape);
+ mRemoteViews = new RemoteViews(landscape, portrait);
+
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
+ assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+ View result = mRemoteViews.apply(mContext, null);
+ assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+ .getText().toString());
+
+ // The ApplicationInfo should only have been written once, so this should be much smaller
+ // than twice the size of parcelling one RemoteViews.
+ assertLessThan(landscapeParcelledSize * 2, getParcelledSize(mRemoteViews));
+ }
+
+ @Test
+ public void testWriteToParcel_sizeMap() {
+ List<SizeF> sizes =
+ Arrays.asList(new SizeF(50, 50), new SizeF(100, 100), new SizeF(100, 200));
+ Map<SizeF, RemoteViews> sizeMap = new ArrayMap<>();
+ int singelParcelledSize = 0;
+ for (SizeF size : sizes) {
+ RemoteViews views = new RemoteViews(PACKAGE_NAME, R.layout.remoteviews_good);
+ views.setTextViewText(R.id.remoteView_text, "Hello world");
+ sizeMap.put(size, views);
+ singelParcelledSize = getParcelledSize(views);
+ }
+ mRemoteViews = new RemoteViews(sizeMap);
+
+ mRemoteViews = parcelAndUnparcel(mRemoteViews);
+ assertEquals(PACKAGE_NAME, mRemoteViews.getPackage());
+ View result = mRemoteViews.apply(mContext, null);
+ assertEquals("Hello world", ((TextView) result.findViewById(R.id.remoteView_text))
+ .getText().toString());
+
+ // The ApplicationInfo should only have been written once, so this should be much smaller
+ // than thrice the size of parcelling one RemoteViews.
+ assertLessThan(singelParcelledSize * 3, getParcelledSize(mRemoteViews));
+ }
+
@Test(expected=NegativeArraySizeException.class)
public void testCreateNegativeSizedArray() {
RemoteViews.CREATOR.newArray(-1);
@@ -1940,4 +1986,41 @@
runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
return previousMode;
}
+
+ private static RemoteViews parcelAndUnparcel(RemoteViews views) {
+ return parcelAndUnparcel(views, /* flags= */ 0);
+ }
+
+ /**
+ * Returns the result of writing {@code views} to a {@link Parcel} and then creating a new
+ * {@link RemoteViews} from the parcel.
+ */
+ private static RemoteViews parcelAndUnparcel(RemoteViews views, int flags) {
+ return parcelAndRun(views, flags, RemoteViews.CREATOR::createFromParcel);
+ }
+
+ /** Returns the data size from writing {@code parcelable} to a {@link Parcel}. */
+ private static int getParcelledSize(Parcelable parcelable) {
+ return parcelAndRun(parcelable, /* flags= */ 0, Parcel::dataSize);
+ }
+
+ private static <T> T parcelAndRun(
+ Parcelable parcelable,
+ int flags,
+ Function<Parcel, T> function) {
+ Parcel parcel = Parcel.obtain();
+ parcelable.writeToParcel(parcel, flags);
+ parcel.setDataPosition(0);
+ try {
+ return function.apply(parcel);
+ } finally {
+ parcel.recycle();
+ }
+ }
+
+ private static void assertLessThan(int expected, int actual) {
+ if (actual >= expected) {
+ Assert.fail("Expected to be less than " + expected + ", but was " + actual);
+ }
+ }
}
diff --git a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
index 30d07ff..d4f548c 100644
--- a/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
+++ b/tools/cts-tradefed/res/config/cts-on-gsi-exclude.xml
@@ -95,4 +95,8 @@
<!-- b/183653612: CtsTransitionTestCases -->
<option name="compatibility:exclude-filter" value="CtsTransitionTestCases" />
+
+ <!-- b/198226244 -->
+ <option name="compatibility:exclude-filter" value="CtsVideoTestCases android.video.cts.CodecEncoderPerformanceTest#testPerformanceOfHardwareVideoEncoders" />
+
</configuration>