aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlex Kershaw <alexkershaw@google.com>2020-03-26 10:52:39 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2020-03-26 10:52:39 +0000
commit53aefd975cc0d94ef708fb1d263060ed46f7aec4 (patch)
tree49557f50c7d5135739cc61049413cd67e4a6a895
parentfce599eb7193ad8b0b9bf4eb74e0b308d7bd950f (diff)
parent032359b15d87bd34192d4e4645035e806cf20276 (diff)
downloadplatform_external_robolectric-shadows-53aefd975cc0d94ef708fb1d263060ed46f7aec4.tar.gz
platform_external_robolectric-shadows-53aefd975cc0d94ef708fb1d263060ed46f7aec4.tar.bz2
platform_external_robolectric-shadows-53aefd975cc0d94ef708fb1d263060ed46f7aec4.zip
Merge "Add shadow methods for clearing cross-profile app-ops" into rvc-dev
-rw-r--r--robolectric/src/test/java/org/robolectric/shadows/ShadowCrossProfileAppsTest.java38
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java12
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java2
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowCrossProfileApps.java17
-rw-r--r--shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java27
5 files changed, 95 insertions, 1 deletions
diff --git a/robolectric/src/test/java/org/robolectric/shadows/ShadowCrossProfileAppsTest.java b/robolectric/src/test/java/org/robolectric/shadows/ShadowCrossProfileAppsTest.java
index 6bc47c335..cae91513a 100644
--- a/robolectric/src/test/java/org/robolectric/shadows/ShadowCrossProfileAppsTest.java
+++ b/robolectric/src/test/java/org/robolectric/shadows/ShadowCrossProfileAppsTest.java
@@ -1,15 +1,23 @@
package org.robolectric.shadows;
import static android.Manifest.permission.INTERACT_ACROSS_PROFILES;
+import static android.app.AppOpsManager.MODE_ALLOWED;
+import static android.app.AppOpsManager.MODE_DEFAULT;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
+import static android.os.Build.VERSION_CODES.R;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.fail;
import static org.robolectric.Shadows.shadowOf;
import android.app.Application;
+import android.app.AppOpsManager;
import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
import android.content.pm.CrossProfileApps;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
@@ -28,6 +36,7 @@ public class ShadowCrossProfileAppsTest {
private final Application application = ApplicationProvider.getApplicationContext();
private final CrossProfileApps crossProfileApps =
application.getSystemService(CrossProfileApps.class);
+ private final PackageManager packageManager = ((Context) application).getPackageManager();
private final UserHandle userHandle1 = UserHandle.of(10);
private final UserHandle userHandle2 = UserHandle.of(11);
@@ -339,6 +348,35 @@ public class ShadowCrossProfileAppsTest {
assertThat(shadowOf(crossProfileApps).peekNextStartedActivity()).isNull();
}
+ // BEGIN-INTERNAL
+ @Test
+ @Config(minSdk = R)
+ public void clearInteractAcrossProfilesAppOps_clearsAppOps() {
+ String testPackage1 = "com.example.testpackage1";
+ String testPackage2 = "com.example.testpackage2";
+ shadowOf(packageManager).installPackage(buildTestPackageInfo(testPackage1));
+ shadowOf(packageManager).installPackage(buildTestPackageInfo(testPackage2));
+ shadowOf(crossProfileApps).setInteractAcrossProfilesAppOp(testPackage1, MODE_ALLOWED);
+ shadowOf(crossProfileApps).setInteractAcrossProfilesAppOp(testPackage2, MODE_ALLOWED);
+
+ shadowOf(crossProfileApps).clearInteractAcrossProfilesAppOps();
+
+ assertThat(shadowOf(crossProfileApps).getInteractAcrossProfilesAppOp(testPackage1))
+ .isEqualTo(MODE_DEFAULT);
+ assertThat(shadowOf(crossProfileApps).getInteractAcrossProfilesAppOp(testPackage2))
+ .isEqualTo(MODE_DEFAULT);
+ }
+
+ private PackageInfo buildTestPackageInfo(String packageName) {
+ PackageInfo packageInfo = new PackageInfo();
+ packageInfo.packageName = packageName;
+ packageInfo.applicationInfo = new ApplicationInfo();
+ packageInfo.applicationInfo.packageName = packageName;
+ packageInfo.applicationInfo.name = "test";
+ return packageInfo;
+ }
+ // END-INTERNAL
+
private static void assertThrowsSecurityException(Runnable runnable) {
assertThrows(SecurityException.class, runnable);
}
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
index 932f78d40..f41493e1a 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowActivityThread.java
@@ -6,7 +6,10 @@ import android.app.ActivityThread;
import android.content.ComponentName;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
import android.os.RemoteException;
+import android.os.UserHandle;
+
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
@@ -74,6 +77,15 @@ public class ShadowActivityThread {
} catch (PackageManager.NameNotFoundException e) {
throw new RemoteException(e.getMessage());
}
+ } else if (method.getName().equals("getInstalledApplications")) {
+ int flags = (Integer) args[0];
+ int userId = (Integer) args[1];
+ return new ParceledListSlice<>(
+ RuntimeEnvironment.application
+ .getApplicationContext()
+ .createContextAsUser(UserHandle.of(userId), /* flags= */ 0)
+ .getPackageManager()
+ .getInstalledApplications(flags));
} else if (method.getName().equals("notifyPackageUse")) {
return null;
} else if (method.getName().equals("getPackageInstaller")) {
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java
index 9b7d36da6..118d2f64e 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowApplicationPackageManager.java
@@ -1107,7 +1107,7 @@ public class ShadowApplicationPackageManager extends ShadowPackageManager {
@Implementation(minSdk = N)
protected PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
throws NameNotFoundException {
- return null;
+ return getPackageInfo(packageName, flags);
}
@Implementation
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCrossProfileApps.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCrossProfileApps.java
index f54ca7126..7eb738839 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCrossProfileApps.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowCrossProfileApps.java
@@ -320,6 +320,23 @@ public class ShadowCrossProfileApps {
}
}
+ // BEGIN-INTERNAL
+ @Implementation(minSdk = R)
+ protected void clearInteractAcrossProfilesAppOps() {
+ findAllPackageNames().forEach(
+ packageName -> setInteractAcrossProfilesAppOp(
+ packageName, AppOpsManager.opToDefaultMode(INTERACT_ACROSS_PROFILES_APPOP)));
+ }
+
+ private List<String> findAllPackageNames() {
+ return context.getPackageManager()
+ .getInstalledApplications(/* flags= */ 0)
+ .stream()
+ .map(applicationInfo -> applicationInfo.packageName)
+ .collect(Collectors.toList());
+ }
+ // END-INTERNAL
+
@Implementation
protected boolean canConfigureInteractAcrossProfiles(@NonNull String packageName) {
return configurableInteractAcrossProfilePackages.contains(packageName);
diff --git a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
index 9464c2f77..2d8bfeedd 100644
--- a/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
+++ b/shadows/framework/src/main/java/org/robolectric/shadows/ShadowUserManager.java
@@ -10,6 +10,7 @@ import static android.os.Build.VERSION_CODES.R;
import static org.robolectric.shadow.api.Shadow.directlyOn;
import android.Manifest.permission;
+import android.annotation.NonNull;
import android.annotation.UserIdInt;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -23,9 +24,12 @@ import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
+
import org.robolectric.annotation.Implementation;
import org.robolectric.annotation.Implements;
import org.robolectric.annotation.RealObject;
@@ -522,6 +526,29 @@ public class ShadowUserManager {
return true;
}
+ // BEGIN-INTERNAL
+ @Implementation(minSdk = R)
+ protected UserInfo createProfileForUserEvenWhenDisallowed(String name,
+ @NonNull String userType, @UserInfo.UserInfoFlag int flags, @UserIdInt int userId,
+ String[] disallowedPackages) throws UserManager.UserOperationException {
+ List<UserInfo> userIdProfiles = profiles.computeIfAbsent(userId, ignored -> new ArrayList<>());
+ int profileUserId = userIdProfiles.isEmpty() ? 10 : findMaxProfileId(userIdProfiles) + 1;
+ UserInfo profileUserInfo = new UserInfo(profileUserId, name, flags);
+ userIdProfiles.add(profileUserInfo);
+ profileToParent.put(profileUserId, userId);
+ addUserProfile(UserHandle.of(profileUserId));
+ return profileUserInfo;
+ }
+
+ /** Assumes the given list of profile infos is non-empty. */
+ private int findMaxProfileId(List<UserInfo> userIdProfiles) {
+ return Collections.max(
+ userIdProfiles.stream()
+ .map(userInfo -> userInfo.id)
+ .collect(Collectors.toList()));
+ }
+ // END-INTERNAL
+
/**
* Switches the current user to {@code userHandle}.
*