diff options
author | Alex Kershaw <alexkershaw@google.com> | 2020-03-26 10:52:39 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2020-03-26 10:52:39 +0000 |
commit | 53aefd975cc0d94ef708fb1d263060ed46f7aec4 (patch) | |
tree | 49557f50c7d5135739cc61049413cd67e4a6a895 | |
parent | fce599eb7193ad8b0b9bf4eb74e0b308d7bd950f (diff) | |
parent | 032359b15d87bd34192d4e4645035e806cf20276 (diff) | |
download | platform_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
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}. * |