Migrate Profile.isChild to use capabilities in AccountManagement UI

* Update the AccountManagementFragment to use the
`isSubjectToParentalControls` capability

* Update FakeAccountManagerFacade to explicitly set capabilities in
AccountHolder which can now store capabilities.


Bug: b/319209578
Change-Id: I0ac689d9773a40e984b1a8c05a0c8258834f8950
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5169126
Reviewed-by: Nohemi Fernandez <fernandex@chromium.org>
Reviewed-by: Boris Sazonov <bsazonov@chromium.org>
Commit-Queue: Liza Bipin <mlbipin@google.com>
Cr-Commit-Position: refs/heads/main@{#1255496}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
index 7a54d37..cbea47e 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/sync/settings/AccountManagementFragment.java
@@ -17,6 +17,7 @@
 import androidx.preference.PreferenceScreen;
 
 import org.chromium.chrome.R;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.preferences.Pref;
 import org.chromium.chrome.browser.settings.ChromeBaseSettingsFragment;
 import org.chromium.chrome.browser.settings.ChromeManagedPreferenceDelegate;
@@ -38,6 +39,8 @@
 import org.chromium.components.signin.AccountManagerFacadeProvider;
 import org.chromium.components.signin.AccountUtils;
 import org.chromium.components.signin.GAIAServiceType;
+import org.chromium.components.signin.Tribool;
+import org.chromium.components.signin.base.AccountInfo;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
 import org.chromium.components.signin.metrics.SignoutReason;
@@ -184,7 +187,7 @@
 
     private void configureSignOutSwitch() {
         Preference signOutPreference = findPreference(PREF_SIGN_OUT);
-        if (getProfile().isChild()) {
+        if (isSupervisedUser()) {
             getPreferenceScreen().removePreference(signOutPreference);
             getPreferenceScreen().removePreference(findPreference(PREF_SIGN_OUT_DIVIDER));
         } else {
@@ -230,7 +233,7 @@
 
     private void configureChildAccountPreferences() {
         Preference parentAccounts = findPreference(PREF_PARENT_ACCOUNT_CATEGORY);
-        if (getProfile().isChild()) {
+        if (isSupervisedUser()) {
             PrefService prefService = UserPrefs.get(getProfile());
 
             String firstParent = prefService.getString(Pref.SUPERVISED_USER_CUSTODIAN_EMAIL);
@@ -456,4 +459,19 @@
         settingsLauncher.launchSettingsActivity(
                 context, AccountManagementFragment.class, arguments);
     }
+
+    private boolean isSupervisedUser() {
+        if (ChromeFeatureList.isEnabled(
+                ChromeFeatureList.MIGRATE_ACCOUNT_MANAGEMENT_SETTINGS_TO_CAPABILITIES)) {
+            assert mSignedInCoreAccountInfo != null;
+            AccountInfo accountinfo =
+                    IdentityServicesProvider.get()
+                            .getIdentityManager(getProfile())
+                            .findExtendedAccountInfoByEmailAddress(
+                                    mSignedInCoreAccountInfo.getEmail());
+            return accountinfo.getAccountCapabilities().isSubjectToParentalControls()
+                    == Tribool.TRUE;
+        }
+        return getProfile().isChild();
+    }
 }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
index 02ab611..0e47998 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/sync/AccountManagementFragmentTest.java
@@ -30,16 +30,21 @@
 import org.junit.rules.RuleChain;
 import org.junit.runner.RunWith;
 
-import org.chromium.base.test.util.Batch;
+import org.chromium.base.FeatureList;
+import org.chromium.base.test.params.ParameterAnnotations;
+import org.chromium.base.test.params.ParameterProvider;
+import org.chromium.base.test.params.ParameterSet;
+import org.chromium.base.test.params.ParameterizedRunner;
 import org.chromium.base.test.util.CommandLineFlags;
 import org.chromium.base.test.util.CriteriaHelper;
 import org.chromium.base.test.util.Feature;
+import org.chromium.chrome.browser.flags.ChromeFeatureList;
 import org.chromium.chrome.browser.flags.ChromeSwitches;
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.settings.SettingsActivityTestRule;
 import org.chromium.chrome.browser.signin.services.IdentityServicesProvider;
 import org.chromium.chrome.browser.sync.settings.AccountManagementFragment;
-import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
+import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.chrome.test.R;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
@@ -48,12 +53,16 @@
 import org.chromium.components.signin.base.AccountInfo;
 import org.chromium.components.signin.base.CoreAccountInfo;
 import org.chromium.components.signin.identitymanager.ConsentLevel;
+import org.chromium.components.signin.test.util.AccountCapabilitiesBuilder;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
+import java.util.Arrays;
+import java.util.List;
+
 /** Tests {@link AccountManagementFragment}. */
-@RunWith(ChromeJUnit4ClassRunner.class)
+@RunWith(ParameterizedRunner.class)
+@ParameterAnnotations.UseRunnerDelegate(ChromeJUnit4RunnerDelegate.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
-@Batch(Batch.PER_CLASS)
 public class AccountManagementFragmentTest {
     private static final String CHILD_ACCOUNT_NAME =
             AccountManagerTestRule.generateChildEmail("account@gmail.com");
@@ -78,6 +87,33 @@
                     .setBugComponent(ChromeRenderTestRule.Component.SERVICES_SYNC)
                     .build();
 
+    public static class MigrateAccountManagementSettingsToCapabilitiesParams
+            implements ParameterProvider {
+
+        private static List<ParameterSet> sMigrateAccountManagementSettingsToCapabilities =
+                Arrays.asList(
+                        new ParameterSet()
+                                .value(true)
+                                .name("MigrateProfileIsChildFlagParamsEnabled"),
+                        new ParameterSet()
+                                .value(false)
+                                .name("MigrateProfileIsChildFlagParamsDisabled"));
+
+        @Override
+        public List<ParameterSet> getParameters() {
+            return sMigrateAccountManagementSettingsToCapabilities;
+        }
+    }
+
+    @ParameterAnnotations.UseMethodParameterBefore(
+            MigrateAccountManagementSettingsToCapabilitiesParams.class)
+    public void enableFlag(boolean isMigrateAccountManagementSettingsToCapabilitiesFlagEnabled) {
+        FeatureList.TestValues testValuesOverride = new FeatureList.TestValues();
+        testValuesOverride.addFeatureFlagOverride(
+                ChromeFeatureList.MIGRATE_ACCOUNT_MANAGEMENT_SETTINGS_TO_CAPABILITIES,
+                isMigrateAccountManagementSettingsToCapabilitiesFlagEnabled);
+    }
+
     @Before
     public void setUp() {
         mActivityTestRule.startMainActivityOnBlankPage();
@@ -170,12 +206,19 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    public void testAccountManagementViewForChildAccount() throws Exception {
-        mSigninTestRule.addAccountAndWaitForSeeding(CHILD_ACCOUNT_NAME);
-        final Profile profile =
-                TestThreadUtils.runOnUiThreadBlockingNoException(
-                        Profile::getLastUsedRegularProfile);
-        CriteriaHelper.pollUiThread(profile::isChild);
+    @ParameterAnnotations.UseMethodParameter(
+            MigrateAccountManagementSettingsToCapabilitiesParams.class)
+    public void testAccountManagementViewForChildAccount(
+            boolean isMigrateAccountManagementSettingsToCapabilitiesFlagEnabled) throws Exception {
+        final AccountCapabilitiesBuilder accountCapabilitiesBuilder =
+                new AccountCapabilitiesBuilder();
+        CoreAccountInfo primarySupervisedAccount =
+                mSigninTestRule.addAccount(
+                        CHILD_ACCOUNT_NAME,
+                        accountCapabilitiesBuilder.setIsSubjectToParentalControls(true).build());
+        mSigninTestRule.waitForSeeding();
+        mSigninTestRule.waitForSignin(primarySupervisedAccount);
+
         mSettingsActivityTestRule.startSettingsActivity();
         CriteriaHelper.pollUiThread(
                 () -> {
@@ -194,14 +237,20 @@
     @Test
     @MediumTest
     @Feature("RenderTest")
-    public void testAccountManagementViewForChildAccountWithSecondaryEduAccount() throws Exception {
-        mSigninTestRule.addAccount(CHILD_ACCOUNT_NAME);
+    @ParameterAnnotations.UseMethodParameter(
+            MigrateAccountManagementSettingsToCapabilitiesParams.class)
+    public void testAccountManagementViewForChildAccountWithSecondaryEduAccount(
+            boolean isMigrateAccountManagementSettingsToCapabilitiesFlagEnabled) throws Exception {
+        final AccountCapabilitiesBuilder accountCapabilitiesBuilder =
+                new AccountCapabilitiesBuilder();
+        CoreAccountInfo primarySupervisedAccount =
+                mSigninTestRule.addAccount(
+                        CHILD_ACCOUNT_NAME,
+                        accountCapabilitiesBuilder.setIsSubjectToParentalControls(true).build());
         mSigninTestRule.addAccount("account@school.com");
         mSigninTestRule.waitForSeeding();
-        final Profile profile =
-                TestThreadUtils.runOnUiThreadBlockingNoException(
-                        Profile::getLastUsedRegularProfile);
-        CriteriaHelper.pollUiThread(profile::isChild);
+        mSigninTestRule.waitForSignin(primarySupervisedAccount);
+
         mSettingsActivityTestRule.startSettingsActivity();
         CriteriaHelper.pollUiThread(
                 () -> {
diff --git a/chrome/browser/flags/android/chrome_feature_list.cc b/chrome/browser/flags/android/chrome_feature_list.cc
index 2808968..9f68e5a 100644
--- a/chrome/browser/flags/android/chrome_feature_list.cc
+++ b/chrome/browser/flags/android/chrome_feature_list.cc
@@ -334,6 +334,7 @@
     &send_tab_to_self::kSendTabToSelfV2,
     &share::kScreenshotsForAndroidV2,
     &supervised_user::kKidFriendlyContentFeed,
+    &supervised_user::kMigrateAccountManagementSettingsToCapabilities,
     &switches::kForceStartupSigninPromo,
     &switches::kForceDisableExtendedSyncPromos,
     &switches::kSearchEngineChoice,
diff --git a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
index da9dfd7..2d3db93f0 100644
--- a/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
+++ b/chrome/browser/flags/android/java/src/org/chromium/chrome/browser/flags/ChromeFeatureList.java
@@ -317,6 +317,8 @@
             "MessagesForAndroidInfrastructure";
     public static final String MESSAGES_FOR_ANDROID_PERMISSION_UPDATE =
             "MessagesForAndroidPermissionUpdate";
+    public static final String MIGRATE_ACCOUNT_MANAGEMENT_SETTINGS_TO_CAPABILITIES =
+            "MigrateAccountManagementSettingsToCapabilities";
     public static final String MUlTI_INSTANCE_APPLICATION_STATUS_CLEANUP =
             "MultiInstanceApplicationStatusCleanup";
     public static final String NEW_TAB_SEARCH_ENGINE_URL_ANDROID = "NewTabSearchEngineUrlAndroid";
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
index 750c67c..fe8357f 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/AccountManagerTestRule.java
@@ -177,7 +177,7 @@
                         givenName,
                         avatar,
                         capabilities);
-        mFakeAccountManagerFacade.addAccount(AccountUtils.createAccountFromName(email));
+        mFakeAccountManagerFacade.addAccountWithAccountInfo(accountInfo);
         // TODO(https://crbug.com/1352119): Revise this test rule and remove the condition here.
         if (mFakeAccountInfoService != null) mFakeAccountInfoService.addAccountInfo(accountInfo);
         return accountInfo;
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestRule.java
index 0f6d302b..496a3e3 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/signin/SigninTestRule.java
@@ -22,6 +22,9 @@
 import org.chromium.components.sync.SyncService;
 import org.chromium.content_public.browser.test.util.TestThreadUtils;
 
+import java.util.HashMap;
+import java.util.Map;
+
 /**
  * This test rule mocks AccountManagerFacade and manages sign-in/sign-out.
  *
@@ -35,11 +38,14 @@
 public class SigninTestRule extends AccountManagerTestRule {
     public static final AccountCapabilities NON_DISPLAYABLE_EMAIL_ACCOUNT_CAPABILITIES =
             new AccountCapabilities(
-                    new String[] {
-                        AccountCapabilitiesConstants
-                                .CAN_HAVE_EMAIL_ADDRESS_DISPLAYED_CAPABILITY_NAME
-                    },
-                    new boolean[] {false});
+                    new HashMap<>(
+                            Map.of(
+                                    AccountCapabilitiesConstants
+                                            .CAN_HAVE_EMAIL_ADDRESS_DISPLAYED_CAPABILITY_NAME,
+                                    false,
+                                    AccountCapabilitiesConstants
+                                            .IS_SUBJECT_TO_PARENTAL_CONTROLS_CAPABILITY_NAME,
+                                    true)));
 
     private boolean mIsSignedIn;
 
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesBuilder.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesBuilder.java
index 087dde3..5f4a4a5 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesBuilder.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountCapabilitiesBuilder.java
@@ -27,6 +27,13 @@
         return this;
     }
 
+    public AccountCapabilitiesBuilder setIsSubjectToParentalControls(boolean value) {
+        mCapabilities.put(
+                AccountCapabilitiesConstants.IS_SUBJECT_TO_PARENTAL_CONTROLS_CAPABILITY_NAME,
+                value);
+        return this;
+    }
+
     /** @return {@link AccountCapabilities} object with the capabilities set up with the builder. */
     public AccountCapabilities build() {
         return new AccountCapabilities((HashMap<String, Boolean>) mCapabilities.clone());
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountHolder.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountHolder.java
index 4757412..3f02e51 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountHolder.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/AccountHolder.java
@@ -10,6 +10,8 @@
 
 import org.chromium.components.signin.AccessTokenData;
 import org.chromium.components.signin.AccountUtils;
+import org.chromium.components.signin.base.AccountCapabilities;
+import org.chromium.components.signin.base.AccountInfo;
 
 import java.util.Collections;
 import java.util.HashMap;
@@ -27,6 +29,7 @@
     private final Account mAccount;
     private final Map<String, AccessTokenData> mAuthTokens;
     private final Set<String> mFeatures;
+    private AccountCapabilities mAccountCapabilities = new AccountCapabilities(new HashMap<>());
 
     private AccountHolder(Account account) {
         assert account != null : "account shouldn't be null!";
@@ -35,6 +38,13 @@
         mFeatures = new HashSet<>();
     }
 
+    private AccountHolder(AccountInfo accountInfo) {
+        this(AccountUtils.createAccountFromName(accountInfo.getEmail()));
+        if (accountInfo != null) {
+            mAccountCapabilities = accountInfo.getAccountCapabilities();
+        }
+    }
+
     public Account getAccount() {
         return mAccount;
     }
@@ -95,10 +105,19 @@
         return new AccountHolder(account);
     }
 
+    /** Creates an {@link AccountHolder} from account and accountInfo. */
+    public static AccountHolder createFromAccount(AccountInfo accountInfo) {
+        return new AccountHolder(accountInfo);
+    }
+
     /** Creates an {@link AccountHolder} from email and features. */
     public static AccountHolder createFromEmailAndFeatures(String email, String... features) {
         final AccountHolder accountHolder = createFromEmail(email);
         Collections.addAll(accountHolder.mFeatures, features);
         return accountHolder;
     }
+
+    public AccountCapabilities getAccountCapabilities() {
+        return mAccountCapabilities;
+    }
 }
diff --git a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java
index 5ec6847..66df20c0 100644
--- a/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java
+++ b/components/signin/public/android/java/src/org/chromium/components/signin/test/util/FakeAccountManagerFacade.java
@@ -24,10 +24,10 @@
 import org.chromium.components.signin.AccountsChangeObserver;
 import org.chromium.components.signin.AuthException;
 import org.chromium.components.signin.base.AccountCapabilities;
+import org.chromium.components.signin.base.AccountInfo;
 import org.chromium.components.signin.base.CoreAccountInfo;
 
 import java.util.ArrayList;
-import java.util.HashMap;
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
@@ -160,8 +160,11 @@
     }
 
     @Override
+
     public Promise<AccountCapabilities> getAccountCapabilities(CoreAccountInfo coreAccountInfo) {
-        return Promise.fulfilled(new AccountCapabilities(new HashMap<>()));
+        AccountHolder accountHolder =
+                getAccountHolder(AccountUtils.createAccountFromName(coreAccountInfo.getEmail()));
+        return Promise.fulfilled(accountHolder.getAccountCapabilities());
     }
 
     @Override
@@ -193,6 +196,14 @@
                 });
     }
 
+    public void addAccountWithAccountInfo(AccountInfo accountInfo) {
+        ThreadUtils.runOnUiThreadBlocking(
+                () -> {
+                    mAccountHolders.add(AccountHolder.createFromAccount(accountInfo));
+                    fireOnAccountsChangedNotification();
+                });
+    }
+
     /** Removes an account from the fake AccountManagerFacade. */
     public void removeAccount(Account account) {
         ThreadUtils.runOnUiThreadBlocking(
@@ -271,7 +282,7 @@
     }
 
     @MainThread
-    private @Nullable AccountHolder getAccountHolder(Account account) throws AuthException {
+    private @Nullable AccountHolder getAccountHolder(Account account) {
         ThreadUtils.checkUiThread();
         for (AccountHolder accountHolder : mAccountHolders) {
             if (accountHolder.getAccount().equals(account)) {
diff --git a/components/supervised_user/core/common/features.cc b/components/supervised_user/core/common/features.cc
index 3ad60f17..a1285f6 100644
--- a/components/supervised_user/core/common/features.cc
+++ b/components/supervised_user/core/common/features.cc
@@ -125,6 +125,12 @@
              "CustomWebSignInInterceptForSupervisedUsers",
              base::FEATURE_DISABLED_BY_DEFAULT);
 
+#if BUILDFLAG(IS_ANDROID)
+BASE_FEATURE(kMigrateAccountManagementSettingsToCapabilities,
+             "MigrateAccountManagementSettingsToCapabilities",
+             base::FEATURE_ENABLED_BY_DEFAULT);
+#endif
+
 bool IsChildAccountSupervisionEnabled() {
 #if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_CHROMEOS)
   // Supervision features are fully supported on Android and ChromeOS.
diff --git a/components/supervised_user/core/common/features.h b/components/supervised_user/core/common/features.h
index ae39395..d6db30a 100644
--- a/components/supervised_user/core/common/features.h
+++ b/components/supervised_user/core/common/features.h
@@ -51,6 +51,12 @@
 // Forces Safe Search for supervised users.
 BASE_DECLARE_FEATURE(kForceGoogleSafeSearchForSupervisedUsers);
 
+// Updates usages of Profile.isChild() in Profile.java to use the account
+// capability to determine if account is supervised.
+#if BUILDFLAG(IS_ANDROID)
+BASE_DECLARE_FEATURE(kMigrateAccountManagementSettingsToCapabilities);
+#endif
+
 // Returns whether local parent approvals on Family Link user's device are
 // enabled.
 // Local web approvals are only available when refreshed version of web