Merge "Adding user property for CrossProfileContentSharingStrategy." into main
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9b11b50..c64f230 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -4196,12 +4196,15 @@
 
   public final class UserProperties implements android.os.Parcelable {
     method public int describeContents();
+    method public int getCrossProfileContentSharingStrategy();
     method public int getShowInQuietMode();
     method public int getShowInSharingSurfaces();
     method public boolean isCredentialShareableWithParent();
     method public boolean isMediaSharedWithParent();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.UserProperties> CREATOR;
+    field public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1; // 0x1
+    field public static final int CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION = 0; // 0x0
     field public static final int SHOW_IN_QUIET_MODE_DEFAULT = 2; // 0x2
     field public static final int SHOW_IN_QUIET_MODE_HIDDEN = 1; // 0x1
     field public static final int SHOW_IN_QUIET_MODE_PAUSED = 0; // 0x0
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 7417137..3f2376d 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -1166,6 +1166,7 @@
   public static final class UserProperties.Builder {
     ctor public UserProperties.Builder();
     method @NonNull public android.content.pm.UserProperties build();
+    method @NonNull public android.content.pm.UserProperties.Builder setCrossProfileContentSharingStrategy(int);
     method @NonNull public android.content.pm.UserProperties.Builder setShowInQuietMode(int);
     method @NonNull public android.content.pm.UserProperties.Builder setShowInSharingSurfaces(int);
   }
diff --git a/core/java/android/content/pm/UserProperties.java b/core/java/android/content/pm/UserProperties.java
index 56e8291..c401268 100644
--- a/core/java/android/content/pm/UserProperties.java
+++ b/core/java/android/content/pm/UserProperties.java
@@ -69,6 +69,9 @@
     private static final String ATTR_DELETE_APP_WITH_PARENT = "deleteAppWithParent";
     private static final String ATTR_ALWAYS_VISIBLE = "alwaysVisible";
 
+    private static final String ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY =
+            "crossProfileContentSharingStrategy";
+
     /** Index values of each property (to indicate whether they are present in this object). */
     @IntDef(prefix = "INDEX_", value = {
             INDEX_SHOW_IN_LAUNCHER,
@@ -86,6 +89,7 @@
             INDEX_SHOW_IN_QUIET_MODE,
             INDEX_SHOW_IN_SHARING_SURFACES,
             INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE,
+            INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY
     })
     @Retention(RetentionPolicy.SOURCE)
     private @interface PropertyIndex {
@@ -105,6 +109,7 @@
     private static final int INDEX_SHOW_IN_QUIET_MODE = 12;
     private static final int INDEX_AUTH_ALWAYS_REQUIRED_TO_DISABLE_QUIET_MODE = 13;
     private static final int INDEX_SHOW_IN_SHARING_SURFACES = 14;
+    private static final int INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY = 15;
     /** A bit set, mapping each PropertyIndex to whether it is present (1) or absent (0). */
     private long mPropertiesPresent = 0;
 
@@ -365,6 +370,45 @@
      */
     @SuppressLint("UnflaggedApi") // b/306636213
     public static final int SHOW_IN_SHARING_SURFACES_NO = SHOW_IN_LAUNCHER_NO;
+    /**
+     * Possible values for cross profile content sharing strategy for this profile.
+     *
+     * @hide
+     */
+    @IntDef(prefix = {"CROSS_PROFILE_CONTENT_SHARING_STRATEGY_"}, value = {
+            CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION,
+            CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CrossProfileContentSharingStrategy {
+    }
+
+    /**
+     * Signifies that cross-profile content sharing strategy, both to and from this profile, should
+     * not be delegated to any other user/profile.
+     * For ex:
+     * If this property is set for a profile, content sharing applications (such as Android
+     * Sharesheet), should not delegate the decision to share content between that profile and
+     * another profile to whether content sharing is allowed between any other profile/user related
+     * to those profiles. They should instead decide, based upon whether content sharing is
+     * specifically allowed between the two profiles in question.
+     */
+    @SuppressLint("UnflaggedApi") // b/306636213
+    public static final int CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION = 0;
+
+    /**
+     * Signifies that cross-profile content sharing strategy, both to and from this profile, should
+     * be based upon the strategy used by the parent user of the profile.
+     * For ex:
+     * If this property is set for a profile A, content sharing applications (such as Android
+     * Sharesheet), should share content between profile A and profile B, based upon whether content
+     * sharing is allowed between the parent of profile A and profile B.
+     * If it's also set for profile B, then decision should, in turn be made by considering content
+     * sharing strategy between the parents of both profiles.
+     */
+    @SuppressLint("UnflaggedApi") // b/306636213
+    public static final int CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT = 1;
+
 
     /**
      * Creates a UserProperties (intended for the SystemServer) that stores a reference to the given
@@ -423,6 +467,7 @@
         setCredentialShareableWithParent(orig.isCredentialShareableWithParent());
         setShowInQuietMode(orig.getShowInQuietMode());
         setShowInSharingSurfaces(orig.getShowInSharingSurfaces());
+        setCrossProfileContentSharingStrategy(orig.getCrossProfileContentSharingStrategy());
     }
 
     /**
@@ -776,8 +821,7 @@
     private @CrossProfileIntentFilterAccessControlLevel int mCrossProfileIntentFilterAccessControl;
 
     /**
-     * Returns the user's {@link CrossProfileIntentResolutionStrategy}. If not explicitly
-     * configured, default value is {@link #CROSS_PROFILE_INTENT_RESOLUTION_STRATEGY_DEFAULT}.
+     * Returns the user's {@link CrossProfileIntentResolutionStrategy}.
      * @return user's {@link CrossProfileIntentResolutionStrategy}.
      *
      * @hide
@@ -792,11 +836,8 @@
         throw new SecurityException("You don't have permission to query "
                 + "crossProfileIntentResolutionStrategy");
     }
-    /**
-     * Sets {@link CrossProfileIntentResolutionStrategy} for the user.
-     * @param val resolution strategy for user
-     * @hide
-     */
+
+    /** @hide */
     public void setCrossProfileIntentResolutionStrategy(
             @CrossProfileIntentResolutionStrategy int val) {
         this.mCrossProfileIntentResolutionStrategy = val;
@@ -804,6 +845,39 @@
     }
     private @CrossProfileIntentResolutionStrategy int mCrossProfileIntentResolutionStrategy;
 
+    /**
+     * Returns the user's {@link CrossProfileContentSharingStrategy}.
+     *
+     * Content sharing applications, such as Android Sharesheet allow sharing of content
+     * (an image, for ex.) between profiles, based upon cross-profile access checks between the
+     * originating and destined profile.
+     * In some cases however, we may want another user (such as profile parent) to serve as the
+     * delegated user to be used for such checks.
+     * To effect the same, clients can fetch this property and accordingly replace the
+     * originating/destined profile by another user for cross-profile access checks.
+     *
+     * @return user's {@link CrossProfileContentSharingStrategy}.
+     */
+    @SuppressLint("UnflaggedApi")  // b/306636213
+    public @CrossProfileContentSharingStrategy int getCrossProfileContentSharingStrategy() {
+        if (isPresent(INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY)) {
+            return mCrossProfileContentSharingStrategy;
+        }
+        if (mDefaultProperties != null) {
+            return mDefaultProperties.mCrossProfileContentSharingStrategy;
+        }
+        throw new SecurityException("You don't have permission to query "
+                + "crossProfileContentSharingStrategy");
+    }
+
+    /** @hide */
+    public void setCrossProfileContentSharingStrategy(
+            @CrossProfileContentSharingStrategy int val) {
+        this.mCrossProfileContentSharingStrategy = val;
+        setPresent(INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY);
+    }
+    private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy;
+
 
     @Override
     public String toString() {
@@ -827,6 +901,7 @@
                 + isAuthAlwaysRequiredToDisableQuietMode()
                 + ", mDeleteAppWithParent=" + getDeleteAppWithParent()
                 + ", mAlwaysVisible=" + getAlwaysVisible()
+                + ", mCrossProfileContentSharingStrategy=" + getCrossProfileContentSharingStrategy()
                 + "}";
     }
 
@@ -856,6 +931,8 @@
                 + isAuthAlwaysRequiredToDisableQuietMode());
         pw.println(prefix + "    mDeleteAppWithParent=" + getDeleteAppWithParent());
         pw.println(prefix + "    mAlwaysVisible=" + getAlwaysVisible());
+        pw.println(prefix + "    mCrossProfileContentSharingStrategy="
+                + getCrossProfileContentSharingStrategy());
     }
 
     /**
@@ -934,6 +1011,8 @@
                 case ATTR_ALWAYS_VISIBLE:
                     setAlwaysVisible(parser.getAttributeBoolean(i));
                     break;
+                case ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY:
+                    setCrossProfileContentSharingStrategy(parser.getAttributeInt(i));
                 default:
                     Slog.w(LOG_TAG, "Skipping unknown property " + attributeName);
             }
@@ -1008,6 +1087,10 @@
             serializer.attributeBoolean(null, ATTR_ALWAYS_VISIBLE,
                     mAlwaysVisible);
         }
+        if (isPresent(INDEX_CROSS_PROFILE_CONTENT_SHARING_STRATEGY)) {
+            serializer.attributeInt(null, ATTR_CROSS_PROFILE_CONTENT_SHARING_STRATEGY,
+                    mCrossProfileContentSharingStrategy);
+        }
     }
 
     // For use only with an object that has already had any permission-lacking fields stripped out.
@@ -1029,6 +1112,7 @@
         dest.writeBoolean(mAuthAlwaysRequiredToDisableQuietMode);
         dest.writeBoolean(mDeleteAppWithParent);
         dest.writeBoolean(mAlwaysVisible);
+        dest.writeInt(mCrossProfileContentSharingStrategy);
     }
 
     /**
@@ -1054,6 +1138,7 @@
         mAuthAlwaysRequiredToDisableQuietMode = source.readBoolean();
         mDeleteAppWithParent = source.readBoolean();
         mAlwaysVisible = source.readBoolean();
+        mCrossProfileContentSharingStrategy = source.readInt();
     }
 
     @Override
@@ -1100,6 +1185,8 @@
         private boolean mAuthAlwaysRequiredToDisableQuietMode = false;
         private boolean mDeleteAppWithParent = false;
         private boolean mAlwaysVisible = false;
+        private @CrossProfileContentSharingStrategy int mCrossProfileContentSharingStrategy =
+                CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION;
 
         /**
          * @hide
@@ -1231,6 +1318,19 @@
             return this;
         }
 
+        /** Sets the value for {@link #mCrossProfileContentSharingStrategy}
+         * @hide
+         */
+
+        @TestApi
+        @SuppressLint("UnflaggedApi") // b/306636213
+        @NonNull
+        public Builder setCrossProfileContentSharingStrategy(@CrossProfileContentSharingStrategy
+                int crossProfileContentSharingStrategy) {
+            mCrossProfileContentSharingStrategy = crossProfileContentSharingStrategy;
+            return this;
+        }
+
         /** Builds a UserProperties object with *all* values populated.
          * @hide
          */
@@ -1253,7 +1353,8 @@
                     mCredentialShareableWithParent,
                     mAuthAlwaysRequiredToDisableQuietMode,
                     mDeleteAppWithParent,
-                    mAlwaysVisible);
+                    mAlwaysVisible,
+                    mCrossProfileContentSharingStrategy);
         }
     } // end Builder
 
@@ -1272,7 +1373,8 @@
             boolean credentialShareableWithParent,
             boolean authAlwaysRequiredToDisableQuietMode,
             boolean deleteAppWithParent,
-            boolean alwaysVisible) {
+            boolean alwaysVisible,
+            @CrossProfileContentSharingStrategy int crossProfileContentSharingStrategy) {
         mDefaultProperties = null;
         setShowInLauncher(showInLauncher);
         setStartWithParent(startWithParent);
@@ -1290,5 +1392,6 @@
                 authAlwaysRequiredToDisableQuietMode);
         setDeleteAppWithParent(deleteAppWithParent);
         setAlwaysVisible(alwaysVisible);
+        setCrossProfileContentSharingStrategy(crossProfileContentSharingStrategy);
     }
 }
diff --git a/services/core/java/com/android/server/pm/UserTypeFactory.java b/services/core/java/com/android/server/pm/UserTypeFactory.java
index 4ef8cb7..7f013b8 100644
--- a/services/core/java/com/android/server/pm/UserTypeFactory.java
+++ b/services/core/java/com/android/server/pm/UserTypeFactory.java
@@ -160,7 +160,9 @@
                                 UserProperties.SHOW_IN_SHARING_SURFACES_WITH_PARENT)
                         .setMediaSharedWithParent(true)
                         .setCredentialShareableWithParent(true)
-                        .setDeleteAppWithParent(true));
+                        .setDeleteAppWithParent(true)
+                        .setCrossProfileContentSharingStrategy(UserProperties
+                                .CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT));
     }
 
     /**
@@ -318,7 +320,9 @@
                                 UserProperties.SHOW_IN_SHARING_SURFACES_SEPARATE)
                         .setCrossProfileIntentFilterAccessControl(
                                 UserProperties.CROSS_PROFILE_INTENT_FILTER_ACCESS_LEVEL_SYSTEM)
-                        .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT));
+                        .setInheritDevicePolicy(UserProperties.INHERIT_DEVICE_POLICY_FROM_PARENT)
+                        .setCrossProfileContentSharingStrategy(
+                                UserProperties.CROSS_PROFILE_CONTENT_SHARING_DELEGATE_FROM_PARENT));
     }
 
     /**
diff --git a/services/tests/servicestests/res/xml/usertypes_test_profile.xml b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
index e89199d..9b047f2 100644
--- a/services/tests/servicestests/res/xml/usertypes_test_profile.xml
+++ b/services/tests/servicestests/res/xml/usertypes_test_profile.xml
@@ -45,6 +45,7 @@
             inheritDevicePolicy='450'
             deleteAppWithParent='false'
             alwaysVisible='true'
+            crossProfileContentSharingStrategy='0'
         />
     </profile-type>
     <profile-type name='custom.test.1' max-allowed-per-parent='14' />
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
index d70a4fd..72cc969 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserPropertiesTest.java
@@ -71,6 +71,7 @@
                 .setAuthAlwaysRequiredToDisableQuietMode(false)
                 .setDeleteAppWithParent(false)
                 .setAlwaysVisible(false)
+                .setCrossProfileContentSharingStrategy(0)
                 .build();
         final UserProperties actualProps = new UserProperties(defaultProps);
         actualProps.setShowInLauncher(14);
@@ -86,6 +87,7 @@
         actualProps.setAuthAlwaysRequiredToDisableQuietMode(true);
         actualProps.setDeleteAppWithParent(true);
         actualProps.setAlwaysVisible(true);
+        actualProps.setCrossProfileContentSharingStrategy(1);
 
         // Write the properties to xml.
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -199,6 +201,8 @@
                 copy::isMediaSharedWithParent, true);
         assertEqualGetterOrThrows(orig::isCredentialShareableWithParent,
                 copy::isCredentialShareableWithParent, true);
+        assertEqualGetterOrThrows(orig::getCrossProfileContentSharingStrategy,
+                copy::getCrossProfileContentSharingStrategy, true);
     }
 
     /**
@@ -256,5 +260,7 @@
                 .isEqualTo(actual.isAuthAlwaysRequiredToDisableQuietMode());
         assertThat(expected.getDeleteAppWithParent()).isEqualTo(actual.getDeleteAppWithParent());
         assertThat(expected.getAlwaysVisible()).isEqualTo(actual.getAlwaysVisible());
+        assertThat(expected.getCrossProfileContentSharingStrategy())
+                .isEqualTo(actual.getCrossProfileContentSharingStrategy());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
index 77f6939..d0ad573 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerServiceUserTypeTest.java
@@ -29,7 +29,6 @@
 
 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.assertTrue;
@@ -96,7 +95,8 @@
                 .setShowInQuietMode(30)
                 .setInheritDevicePolicy(340)
                 .setDeleteAppWithParent(true)
-                .setAlwaysVisible(true);
+                .setAlwaysVisible(true)
+                .setCrossProfileContentSharingStrategy(1);
 
         final UserTypeDetails type = new UserTypeDetails.Builder()
                 .setName("a.name")
@@ -175,6 +175,8 @@
                 .getInheritDevicePolicy());
         assertTrue(type.getDefaultUserPropertiesReference().getDeleteAppWithParent());
         assertTrue(type.getDefaultUserPropertiesReference().getAlwaysVisible());
+        assertEquals(1, type.getDefaultUserPropertiesReference()
+                .getCrossProfileContentSharingStrategy());
 
         assertEquals(23, type.getBadgeLabel(0));
         assertEquals(24, type.getBadgeLabel(1));
@@ -231,6 +233,8 @@
         assertEquals(UserProperties.SHOW_IN_LAUNCHER_SEPARATE, props.getShowInSharingSurfaces());
         assertEquals(UserProperties.SHOW_IN_QUIET_MODE_PAUSED,
                 props.getShowInQuietMode());
+        assertEquals(UserProperties.CROSS_PROFILE_CONTENT_SHARING_NO_DELEGATION,
+                props.getCrossProfileContentSharingStrategy());
 
         assertFalse(type.hasBadge());
     }
@@ -323,7 +327,8 @@
                 .setShowInSharingSurfaces(22)
                 .setShowInQuietMode(24)
                 .setDeleteAppWithParent(true)
-                .setAlwaysVisible(false);
+                .setAlwaysVisible(false)
+                .setCrossProfileContentSharingStrategy(1);
 
         final ArrayMap<String, UserTypeDetails.Builder> builders = new ArrayMap<>();
         builders.put(userTypeAosp1, new UserTypeDetails.Builder()
@@ -370,6 +375,8 @@
                 aospType.getDefaultUserPropertiesReference().getShowInQuietMode());
         assertTrue(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
         assertFalse(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
+        assertEquals(1, aospType.getDefaultUserPropertiesReference()
+                .getCrossProfileContentSharingStrategy());
 
         // userTypeAosp2 should be modified.
         aospType = builders.get(userTypeAosp2).createUserTypeDetails();
@@ -422,6 +429,8 @@
                 .getInheritDevicePolicy());
         assertFalse(aospType.getDefaultUserPropertiesReference().getDeleteAppWithParent());
         assertTrue(aospType.getDefaultUserPropertiesReference().getAlwaysVisible());
+        assertEquals(0, aospType.getDefaultUserPropertiesReference()
+                .getCrossProfileContentSharingStrategy());
 
         // userTypeOem1 should be created.
         UserTypeDetails.Builder customType = builders.get(userTypeOem1);
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 8933c6c..ced0bb5 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -23,7 +23,6 @@
 import static org.junit.Assume.assumeTrue;
 import static org.testng.Assert.assertEquals;
 import static org.testng.Assert.assertThrows;
-import static org.testng.Assert.assertTrue;
 
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
@@ -219,6 +218,8 @@
                 .isEqualTo(cloneUserProperties.isMediaSharedWithParent());
         assertThat(typeProps.isCredentialShareableWithParent())
                 .isEqualTo(cloneUserProperties.isCredentialShareableWithParent());
+        assertThat(typeProps.getCrossProfileContentSharingStrategy())
+                .isEqualTo(cloneUserProperties.getCrossProfileContentSharingStrategy());
         assertThrows(SecurityException.class, cloneUserProperties::getDeleteAppWithParent);
         assertThrows(SecurityException.class, cloneUserProperties::getAlwaysVisible);
         compareDrawables(mUserManager.getUserBadge(),
@@ -338,6 +339,8 @@
         assertThat(typeProps.isAuthAlwaysRequiredToDisableQuietMode())
                 .isEqualTo(privateProfileUserProperties
                         .isAuthAlwaysRequiredToDisableQuietMode());
+        assertThat(typeProps.getCrossProfileContentSharingStrategy())
+                .isEqualTo(privateProfileUserProperties.getCrossProfileContentSharingStrategy());
         assertThrows(SecurityException.class, privateProfileUserProperties::getDeleteAppWithParent);
         compareDrawables(mUserManager.getUserBadge(),
                 Resources.getSystem().getDrawable(userTypeDetails.getBadgePlain()));