Merge "Introducing crossProfileIntentFilters that skip the current profile."
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index de0396e..5e17e1a 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -1457,10 +1457,10 @@
      * @hide
      */
     @Override
-    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
-            int sourceUserId, int targetUserId) {
+    public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
+            int flags) {
         try {
-            mPM.addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
+            mPM.addCrossProfileIntentFilter(filter, sourceUserId, targetUserId, flags);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1470,15 +1470,6 @@
      * @hide
      */
     @Override
-    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int sourceUserId,
-            int targetUserId) {
-        addCrossProfileIntentFilter(filter, removable, sourceUserId, targetUserId);
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public void clearCrossProfileIntentFilters(int sourceUserId) {
         try {
             mPM.clearCrossProfileIntentFilters(sourceUserId);
@@ -1487,14 +1478,6 @@
         }
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void clearForwardingIntentFilters(int sourceUserId) {
-        clearCrossProfileIntentFilters(sourceUserId);
-    }
-
     private final ContextImpl mContext;
     private final IPackageManager mPM;
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 70668e1..00e7918 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -248,8 +248,8 @@
 
     void clearPackagePersistentPreferredActivities(String packageName, int userId);
 
-    void addCrossProfileIntentFilter(in IntentFilter filter, boolean removable, int sourceUserId,
-            int targetUserId);
+    void addCrossProfileIntentFilter(in IntentFilter intentFilter, int sourceUserId, int targetUserId,
+            int flags);
 
     void clearCrossProfileIntentFilters(int sourceUserId);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 5d55b0a1..b5ceebe 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -196,6 +196,22 @@
      */
     public static final int MATCH_DEFAULT_ONLY   = 0x00010000;
 
+    /**
+     * Flag for {@link addCrossProfileIntentFilter}: if the cross-profile intent has been set by the
+     * profile owner.
+     * @hide
+     */
+    public static final int SET_BY_PROFILE_OWNER= 0x00000001;
+
+    /**
+     * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
+     * when resolving an intent that matches the {@link CrossProfileIntentFilter}, the current
+     * profile will be skipped.
+     * Only activities in the target user can respond to the intent.
+     * @hide
+     */
+    public static final int SKIP_CURRENT_PROFILE = 0x00000002;
+
     /** @hide */
     @IntDef({PERMISSION_GRANTED, PERMISSION_DENIED})
     @Retention(RetentionPolicy.SOURCE)
@@ -3583,30 +3599,14 @@
      * {@link CrossProfileIntentFilter}
      * @hide
      */
-    public abstract void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
-            int sourceUserId, int targetUserId);
+    public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
+            int targetUserId, int flags);
 
     /**
-     * @hide
-     * @deprecated
-     * TODO: remove it as soon as the code of ManagedProvisionning is updated
-    */
-    public abstract void addForwardingIntentFilter(IntentFilter filter, boolean removable,
-            int sourceUserId, int targetUserId);
-
-    /**
-     * Clearing removable {@link CrossProfileIntentFilter}s which have the specified user as their
-     * source
+     * Clearing {@link CrossProfileIntentFilter}s which have the specified user as their
+     * source, and have been set by the profile owner
      * @param sourceUserId
-     * be cleared.
      * @hide
      */
     public abstract void clearCrossProfileIntentFilters(int sourceUserId);
-
-    /**
-     * @hide
-     * @deprecated
-     * TODO: remove it as soon as the code of ManagedProvisionning is updated
-    */
-    public abstract void clearForwardingIntentFilters(int sourceUserId);
 }
diff --git a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
index 3d432dc..3ce19c1f 100644
--- a/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
+++ b/services/core/java/com/android/server/pm/CrossProfileIntentFilter.java
@@ -32,36 +32,32 @@
  */
 class CrossProfileIntentFilter extends IntentFilter {
     private static final String ATTR_TARGET_USER_ID = "targetUserId";
-    private static final String ATTR_USER_ID_DEST = "userIdDest";//Old name. Kept for compatibility.
-    private static final String ATTR_REMOVABLE = "removable";
+    private static final String ATTR_FLAGS = "flags";
     private static final String ATTR_FILTER = "filter";
 
     private static final String TAG = "CrossProfileIntentFilter";
 
     // If the intent matches the IntentFilter, then it can be forwarded to this userId.
     final int mTargetUserId;
-    boolean mRemovable;
+    final int mFlags;
 
-    CrossProfileIntentFilter(IntentFilter filter, boolean removable, int targetUserId) {
+    CrossProfileIntentFilter(IntentFilter filter, int targetUserId, int flags) {
         super(filter);
         mTargetUserId = targetUserId;
-        mRemovable = removable;
+        mFlags = flags;
     }
 
     public int getTargetUserId() {
         return mTargetUserId;
     }
 
-    public boolean isRemovable() {
-        return mRemovable;
+    public int getFlags() {
+        return mFlags;
     }
 
     CrossProfileIntentFilter(XmlPullParser parser) throws XmlPullParserException, IOException {
         String targetUserIdString = parser.getAttributeValue(null, ATTR_TARGET_USER_ID);
         if (targetUserIdString == null) {
-            targetUserIdString = parser.getAttributeValue(null, ATTR_USER_ID_DEST);
-        }
-        if (targetUserIdString == null) {
             String msg = "Missing element under " + TAG +": " + ATTR_TARGET_USER_ID + " at " +
                     parser.getPositionDescription();
             PackageManagerService.reportSettingsProblem(Log.WARN, msg);
@@ -69,9 +65,14 @@
         } else {
             mTargetUserId = Integer.parseInt(targetUserIdString);
         }
-        String removableString = parser.getAttributeValue(null, ATTR_REMOVABLE);
-        if (removableString != null) {
-            mRemovable = Boolean.parseBoolean(removableString);
+        String flagsString = parser.getAttributeValue(null, ATTR_FLAGS);
+        if (flagsString == null) {
+            String msg = "Missing element under " + TAG +": " + ATTR_FLAGS + " at " +
+                    parser.getPositionDescription();
+            PackageManagerService.reportSettingsProblem(Log.WARN, msg);
+            mFlags = 0;
+        } else {
+            mFlags = Integer.parseInt(flagsString);
         }
         int outerDepth = parser.getDepth();
         String tagName = parser.getName();
@@ -104,7 +105,7 @@
 
     public void writeToXml(XmlSerializer serializer) throws IOException {
         serializer.attribute(null, ATTR_TARGET_USER_ID, Integer.toString(mTargetUserId));
-        serializer.attribute(null, ATTR_REMOVABLE, Boolean.toString(mRemovable));
+        serializer.attribute(null, ATTR_FLAGS, Integer.toString(mFlags));
         serializer.startTag(null, ATTR_FILTER);
             super.writeToXml(serializer);
         serializer.endTag(null, ATTR_FILTER);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 2f40f2a..a7fc7eb 100755
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -147,6 +147,7 @@
 import android.util.PrintStreamPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.Xml;
 import android.view.Display;
 
@@ -3347,7 +3348,7 @@
     }
 
     /*
-     * Returns if intent can be forwarded from the userId from to dest
+     * Returns if intent can be forwarded from the sourceUserId to the targetUserId
      */
     @Override
     public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId,
@@ -3367,9 +3368,9 @@
 
     private List<CrossProfileIntentFilter> getMatchingCrossProfileIntentFilters(Intent intent,
             String resolvedType, int userId) {
-        CrossProfileIntentResolver cpir = mSettings.mCrossProfileIntentResolvers.get(userId);
-        if (cpir != null) {
-            return cpir.queryIntent(intent, resolvedType, false, userId);
+        CrossProfileIntentResolver resolver = mSettings.mCrossProfileIntentResolvers.get(userId);
+        if (resolver != null) {
+            return resolver.queryIntent(intent, resolvedType, false, userId);
         }
         return null;
     }
@@ -3402,36 +3403,24 @@
         synchronized (mPackages) {
             final String pkgName = intent.getPackage();
             if (pkgName == null) {
-                List<ResolveInfo> result =
-                        mActivities.queryIntent(intent, resolvedType, flags, userId);
-                // Checking if we can forward the intent to another user
-                List<CrossProfileIntentFilter> cpifs =
+                List<ResolveInfo> result;
+                List<CrossProfileIntentFilter> matchingFilters =
                         getMatchingCrossProfileIntentFilters(intent, resolvedType, userId);
-                if (cpifs != null) {
-                    CrossProfileIntentFilter crossProfileIntentFilterWithResult = null;
-                    HashSet<Integer> alreadyTriedUserIds = new HashSet<Integer>();
-                    for (CrossProfileIntentFilter cpif : cpifs) {
-                        int targetUserId = cpif.getTargetUserId();
-                        // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
-                        // match the same an intent. For performance reasons, it is better not to
-                        // run queryIntent twice for the same userId
-                        if (!alreadyTriedUserIds.contains(targetUserId)) {
-                            List<ResolveInfo> resultUser = mActivities.queryIntent(intent,
-                                    resolvedType, flags, targetUserId);
-                            if (resultUser != null) {
-                                crossProfileIntentFilterWithResult = cpif;
-                                // As soon as there is a match in another user, we add the
-                                // intentForwarderActivity to the list of ResolveInfo.
-                                break;
-                            }
-                            alreadyTriedUserIds.add(targetUserId);
-                        }
-                    }
-                    if (crossProfileIntentFilterWithResult != null) {
-                        ResolveInfo forwardingResolveInfo = createForwardingResolveInfo(
-                                crossProfileIntentFilterWithResult, userId);
-                        result.add(forwardingResolveInfo);
-                    }
+                // Check for results that need to skip the current profile.
+                ResolveInfo resolveInfo = querySkipCurrentProfileIntents(matchingFilters, intent,
+                        resolvedType, flags, userId);
+                if (resolveInfo != null) {
+                    result = new ArrayList<ResolveInfo>(1);
+                    result.add(resolveInfo);
+                    return result;
+                }
+                // Check for results in the current profile.
+                result = mActivities.queryIntent(intent, resolvedType, flags, userId);
+                // Check for cross profile results.
+                resolveInfo = queryCrossProfileIntents(
+                        matchingFilters, intent, resolvedType, flags, userId);
+                if (resolveInfo != null) {
+                    result.add(resolveInfo);
                 }
                 return result;
             }
@@ -3444,10 +3433,68 @@
         }
     }
 
-    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter cpif,
+    private ResolveInfo querySkipCurrentProfileIntents(
+            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
+            int flags, int sourceUserId) {
+        if (matchingFilters != null) {
+            int size = matchingFilters.size();
+            for (int i = 0; i < size; i ++) {
+                CrossProfileIntentFilter filter = matchingFilters.get(i);
+                if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) != 0) {
+                    // Checking if there are activities in the target user that can handle the
+                    // intent.
+                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
+                            flags, sourceUserId);
+                    if (resolveInfo != null) {
+                        return createForwardingResolveInfo(filter, sourceUserId);
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    // Return matching ResolveInfo if any for skip current profile intent filters.
+    private ResolveInfo queryCrossProfileIntents(
+            List<CrossProfileIntentFilter> matchingFilters, Intent intent, String resolvedType,
+            int flags, int sourceUserId) {
+        if (matchingFilters != null) {
+            // Two {@link CrossProfileIntentFilter}s can have the same targetUserId and
+            // match the same intent. For performance reasons, it is better not to
+            // run queryIntent twice for the same userId
+            SparseBooleanArray alreadyTriedUserIds = new SparseBooleanArray();
+            int size = matchingFilters.size();
+            for (int i = 0; i < size; i++) {
+                CrossProfileIntentFilter filter = matchingFilters.get(i);
+                int targetUserId = filter.getTargetUserId();
+                if ((filter.getFlags() & PackageManager.SKIP_CURRENT_PROFILE) == 0
+                        && !alreadyTriedUserIds.get(targetUserId)) {
+                    // Checking if there are activities in the target user that can handle the
+                    // intent.
+                    ResolveInfo resolveInfo = checkTargetCanHandle(filter, intent, resolvedType,
+                            flags, sourceUserId);
+                    if (resolveInfo != null) return resolveInfo;
+                    alreadyTriedUserIds.put(targetUserId, true);
+                }
+            }
+        }
+        return null;
+    }
+
+    private ResolveInfo checkTargetCanHandle(CrossProfileIntentFilter filter, Intent intent,
+            String resolvedType, int flags, int sourceUserId) {
+        List<ResolveInfo> resultTargetUser = mActivities.queryIntent(intent,
+                resolvedType, flags, filter.getTargetUserId());
+        if (resultTargetUser != null) {
+            return createForwardingResolveInfo(filter, sourceUserId);
+        }
+        return null;
+    }
+
+    private ResolveInfo createForwardingResolveInfo(CrossProfileIntentFilter filter,
             int sourceUserId) {
         String className;
-        int targetUserId = cpif.getTargetUserId();
+        int targetUserId = filter.getTargetUserId();
         if (targetUserId == UserHandle.USER_OWNER) {
             className = FORWARD_INTENT_TO_USER_OWNER;
         } else {
@@ -3463,7 +3510,7 @@
         forwardingResolveInfo.preferredOrder = 0;
         forwardingResolveInfo.match = 0;
         forwardingResolveInfo.isDefault = true;
-        forwardingResolveInfo.filter = cpif;
+        forwardingResolveInfo.filter = filter;
         return forwardingResolveInfo;
     }
 
@@ -11539,17 +11586,18 @@
     }
 
     @Override
-    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
-            int sourceUserId, int targetUserId) {
+    public void addCrossProfileIntentFilter(IntentFilter intentFilter, int sourceUserId,
+            int targetUserId, int flags) {
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
-        if (filter.countActions() == 0) {
+        if (intentFilter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a crossProfile intent filter with no filter actions");
             return;
         }
         synchronized (mPackages) {
-            mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(
-                    new CrossProfileIntentFilter(filter, removable, targetUserId));
+            CrossProfileIntentFilter filter = new CrossProfileIntentFilter(intentFilter,
+                    targetUserId, flags);
+            mSettings.editCrossProfileIntentResolverLPw(sourceUserId).addFilter(filter);
             mSettings.writePackageRestrictionsLPr(sourceUserId);
         }
     }
@@ -11559,12 +11607,14 @@
         mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, null);
         synchronized (mPackages) {
-            CrossProfileIntentResolver cpir =
+            CrossProfileIntentResolver resolver =
                     mSettings.editCrossProfileIntentResolverLPw(sourceUserId);
             HashSet<CrossProfileIntentFilter> set =
-                    new HashSet<CrossProfileIntentFilter>(cpir.filterSet());
-            for (CrossProfileIntentFilter cpif : set) {
-                if (cpif.isRemovable()) cpir.removeFilter(cpif);
+                    new HashSet<CrossProfileIntentFilter>(resolver.filterSet());
+            for (CrossProfileIntentFilter filter : set) {
+                if ((filter.getFlags() & PackageManager.SET_BY_PROFILE_OWNER) != 0) {
+                    resolver.removeFilter(filter);
+                }
             }
             mSettings.writePackageRestrictionsLPr(sourceUserId);
         }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 5cf5713..4897b1d 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -3454,12 +3454,12 @@
             long id = Binder.clearCallingIdentity();
             try {
                 if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, true /*removable*/, callingUserId,
-                            UserHandle.USER_OWNER);
+                    pm.addCrossProfileIntentFilter(filter, callingUserId, UserHandle.USER_OWNER,
+                            PackageManager.SET_BY_PROFILE_OWNER);
                 }
                 if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, true /*removable*/, UserHandle.USER_OWNER,
-                            callingUserId);
+                    pm.addCrossProfileIntentFilter(filter, UserHandle.USER_OWNER, callingUserId,
+                            PackageManager.SET_BY_PROFILE_OWNER);
                 }
             } catch (RemoteException re) {
                 // Shouldn't happen
@@ -3480,6 +3480,8 @@
             long id = Binder.clearCallingIdentity();
             try {
                 pm.clearCrossProfileIntentFilters(callingUserId);
+                // If we want to support multiple managed profiles, we will have to only remove
+                // those that have callingUserId as their target.
                 pm.clearCrossProfileIntentFilters(UserHandle.USER_OWNER);
             } catch (RemoteException re) {
                 // Shouldn't happen
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 17db1b4..a3b32b3 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -707,17 +707,8 @@
      * @hide
      */
     @Override
-    public void addCrossProfileIntentFilter(IntentFilter filter, boolean removable,
-            int sourceUserId, int targetUserId) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void addForwardingIntentFilter(IntentFilter filter, boolean removable, int sourceUserId,
-            int targetUserId) {
+    public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
+            int flags) {
         throw new UnsupportedOperationException();
     }
 
@@ -729,14 +720,6 @@
         throw new UnsupportedOperationException();
     }
 
-    /**
-     * @hide
-     */
-    @Override
-    public void clearForwardingIntentFilters(int sourceUserId) {
-        throw new UnsupportedOperationException();
-    }
-
     /** {@hide} */
     public PackageInstaller getPackageInstaller() {
         throw new UnsupportedOperationException();