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