Merge "Do not allow work profile apps to access main profile app."
diff --git a/api/current.txt b/api/current.txt
index 02dee34..e7c628a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -9818,6 +9818,7 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
diff --git a/api/system-current.txt b/api/system-current.txt
index a044e26..e79ebdc 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -10251,6 +10251,7 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
diff --git a/api/test-current.txt b/api/test-current.txt
index 72eb006..f1144e9 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -9846,6 +9846,7 @@
     method public java.util.List<android.content.pm.LauncherActivityInfo> getActivityList(java.lang.String, android.os.UserHandle);
     method public android.content.pm.ApplicationInfo getApplicationInfo(java.lang.String, int, android.os.UserHandle);
     method public android.content.pm.LauncherApps.PinItemRequest getPinItemRequest(android.content.Intent);
+    method public java.util.List<android.os.UserHandle> getProfiles();
     method public android.graphics.drawable.Drawable getShortcutBadgedIconDrawable(android.content.pm.ShortcutInfo, int);
     method public android.content.IntentSender getShortcutConfigActivityIntent(android.content.pm.LauncherActivityInfo);
     method public java.util.List<android.content.pm.LauncherActivityInfo> getShortcutConfigActivityList(java.lang.String, android.os.UserHandle);
diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java
index cfe6eee..c6a8674 100644
--- a/core/java/android/content/pm/LauncherApps.java
+++ b/core/java/android/content/pm/LauncherApps.java
@@ -61,15 +61,18 @@
 
 /**
  * Class for retrieving a list of launchable activities for the current user and any associated
- * managed profiles. This is mainly for use by launchers. Apps can be queried for each user profile.
+ * managed profiles that are visible to the current user, which can be retrieved with
+ * {@link #getProfiles}. This is mainly for use by launchers.
+ *
+ * Apps can be queried for each user profile.
  * Since the PackageManager will not deliver package broadcasts for other profiles, you can register
  * for package changes here.
  * <p>
  * To watch for managed profiles being added or removed, register for the following broadcasts:
  * {@link Intent#ACTION_MANAGED_PROFILE_ADDED} and {@link Intent#ACTION_MANAGED_PROFILE_REMOVED}.
  * <p>
- * You can retrieve the list of profiles associated with this user with
- * {@link UserManager#getUserProfiles()}.
+ * Note as of Android O, apps on a managed profile are no longer allowed to access apps on the
+ * main profile.  Apps can only access profiles returned by {@link #getProfiles()}.
  */
 public class LauncherApps {
 
@@ -376,6 +379,24 @@
     }
 
     /**
+     * Return a list of profiles that the caller can access via the {@link LauncherApps} APIs.
+     *
+     * <p>If the caller is running on a managed profile, it'll return only the current profile.
+     * Otherwise it'll return the same list as {@link UserManager#getUserProfiles()} would.
+     */
+    public List<UserHandle> getProfiles() {
+        final UserManager um = mContext.getSystemService(UserManager.class);
+        if (um.isManagedProfile()) {
+            // If it's a managed profile, only return the current profile.
+            final List result =  new ArrayList(1);
+            result.add(android.os.Process.myUserHandle());
+            return result;
+        } else {
+            return um.getUserProfiles();
+        }
+    }
+
+    /**
      * Retrieves a list of launchable activities that match {@link Intent#ACTION_MAIN} and
      * {@link Intent#CATEGORY_LAUNCHER}, for a specified user.
      *
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 2ddf6db..a74e141 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -231,11 +231,15 @@
             long ident = injectClearCallingIdentity();
             try {
                 UserInfo callingUserInfo = mUm.getUserInfo(callingUserId);
+                if (callingUserInfo.isManagedProfile()) {
+                    throw new SecurityException(message + " for another profile " + targetUserId);
+                }
+
                 UserInfo targetUserInfo = mUm.getUserInfo(targetUserId);
                 if (targetUserInfo == null
                         || targetUserInfo.profileGroupId == UserInfo.NO_PROFILE_GROUP_ID
                         || targetUserInfo.profileGroupId != callingUserInfo.profileGroupId) {
-                    throw new SecurityException(message);
+                    throw new SecurityException(message + " for unrelated profile " + targetUserId);
                 }
             } finally {
                 injectRestoreCallingIdentity(ident);
@@ -289,7 +293,7 @@
         @Override
         public ActivityInfo resolveActivity(ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot resolve activity for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot resolve activity");
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -315,7 +319,7 @@
 
         private ParceledListSlice<ResolveInfo> queryActivitiesForUser(Intent intent,
                 UserHandle user) {
-            ensureInUserProfiles(user, "Cannot retrieve activities for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot retrieve activities");
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -356,7 +360,7 @@
         @Override
         public boolean isPackageEnabled(String packageName, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check package");
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -377,7 +381,7 @@
         @Override
         public ApplicationInfo getApplicationInfo(String packageName, int flags, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check package for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check package");
             if (!isUserEnabled(user)) {
                 return null;
             }
@@ -399,7 +403,7 @@
 
         private void ensureShortcutPermission(@NonNull String callingPackage, int userId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(userId, "Cannot access shortcuts for unrelated profile " + userId);
+            ensureInUserProfiles(userId, "Cannot access shortcuts");
 
             if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(),
                     callingPackage)) {
@@ -475,7 +479,7 @@
         public boolean startShortcut(String callingPackage, String packageName, String shortcutId,
                 Rect sourceBounds, Bundle startActivityOptions, int userId) {
             verifyCallingPackage(callingPackage);
-            ensureInUserProfiles(userId, "Cannot start activity for unrelated profile " + userId);
+            ensureInUserProfiles(userId, "Cannot start activity");
 
             if (!isUserEnabled(userId)) {
                 throw new IllegalStateException("Cannot start a shortcut for disabled profile "
@@ -528,7 +532,7 @@
         @Override
         public boolean isActivityEnabled(ComponentName component, UserHandle user)
                 throws RemoteException {
-            ensureInUserProfiles(user, "Cannot check component for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot check component");
             if (!isUserEnabled(user)) {
                 return false;
             }
@@ -549,7 +553,7 @@
         @Override
         public void startActivityAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(user, "Cannot start activity for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot start activity");
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot start activity for disabled profile "  + user);
             }
@@ -602,7 +606,7 @@
         @Override
         public void showAppDetailsAsUser(ComponentName component, Rect sourceBounds,
                 Bundle opts, UserHandle user) throws RemoteException {
-            ensureInUserProfiles(user, "Cannot show app details for unrelated profile " + user);
+            ensureInUserProfiles(user, "Cannot show app details");
             if (!isUserEnabled(user)) {
                 throw new IllegalStateException("Cannot show app details for disabled profile "
                         + user);
diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
index 228b8e0..167b33a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java
@@ -618,9 +618,16 @@
     protected static final UserInfo USER_INFO_11 =
             new UserInfo(USER_11, "user11", UserInfo.FLAG_INITIALIZED);
 
+    /*
+     * Cheat: USER_P0 is a sub profile of USER_0, but it doesn't have the MANAGED_PROFILE flag set.
+     * Due to a change made to LauncherApps (b/34340531), work profile apps a no longer able
+     * to see the main profile, which would break tons of unit tests.  We avoid it by not setting
+     * MANAGED_PROFILE for P0.
+     * We cover this negative case in CTS. (i.e. CTS has tests to make sure maanged profile
+     * can't access main profile's shortcuts.)
+     */
     protected static final UserInfo USER_INFO_P0 = withProfileGroupId(
-            new UserInfo(USER_P0, "userP0",
-                    UserInfo.FLAG_MANAGED_PROFILE), 0);
+            new UserInfo(USER_P0, "userP0", UserInfo.FLAG_INITIALIZED), 0);
 
     protected BiPredicate<String, Integer> mDefaultLauncherChecker =
             (callingPackage, userId) ->