Commit c8908992 authored by Boris Sazonov's avatar Boris Sazonov Committed by Commit Bot

[Signin][Android] Suppress sign-in promo if account cache isn't populated yet

Fixes an ANR that happens on Chrome startup. Now, if the list of
accounts is not available when launchSigninPromoIfNeeded is invoked,
the promo is suppressed.

Bug: b/160838338
Change-Id: Ibbdbfc2f0adc7ae40fe22568f5607c2c4a9f42c5
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303443Reviewed-by: default avatarAlice Wang <aliceywang@chromium.org>
Commit-Queue: Boris Sazonov <bsazonov@chromium.org>
Cr-Commit-Position: refs/heads/master@{#790798}
parent a0f31df5
...@@ -12,13 +12,11 @@ import androidx.annotation.VisibleForTesting; ...@@ -12,13 +12,11 @@ import androidx.annotation.VisibleForTesting;
import androidx.collection.ArraySet; import androidx.collection.ArraySet;
import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.supplier.Supplier;
import org.chromium.chrome.browser.ChromeVersionInfo; import org.chromium.chrome.browser.ChromeVersionInfo;
import org.chromium.chrome.browser.preferences.Pref; import org.chromium.chrome.browser.preferences.Pref;
import org.chromium.chrome.browser.profiles.Profile; import org.chromium.chrome.browser.profiles.Profile;
import org.chromium.components.signin.AccountManagerFacadeProvider; import org.chromium.components.signin.AccountManagerFacadeProvider;
import org.chromium.components.signin.AccountUtils; import org.chromium.components.signin.AccountUtils;
import org.chromium.components.signin.identitymanager.IdentityManager;
import org.chromium.components.signin.metrics.SigninAccessPoint; import org.chromium.components.signin.metrics.SigninAccessPoint;
import org.chromium.components.user_prefs.UserPrefs; import org.chromium.components.user_prefs.UserPrefs;
import org.chromium.ui.base.WindowAndroid; import org.chromium.ui.base.WindowAndroid;
...@@ -39,24 +37,29 @@ public class SigninPromoUtil { ...@@ -39,24 +37,29 @@ public class SigninPromoUtil {
* @return Whether the signin promo is shown. * @return Whether the signin promo is shown.
*/ */
public static boolean launchSigninPromoIfNeeded(final Activity activity) { public static boolean launchSigninPromoIfNeeded(final Activity activity) {
if (!AccountManagerFacadeProvider.getInstance().isCachePopulated()) {
// Suppress the promo if the account list isn't available yet.
return false;
}
SigninPreferencesManager preferencesManager = SigninPreferencesManager.getInstance(); SigninPreferencesManager preferencesManager = SigninPreferencesManager.getInstance();
int currentMajorVersion = ChromeVersionInfo.getProductMajorVersion(); int currentMajorVersion = ChromeVersionInfo.getProductMajorVersion();
boolean isSignedIn = IdentityServicesProvider.get()
.getIdentityManager(Profile.getLastUsedRegularProfile())
.hasPrimaryAccount();
boolean wasSignedIn = boolean wasSignedIn =
TextUtils.isEmpty(UserPrefs.get(Profile.getLastUsedRegularProfile()) TextUtils.isEmpty(UserPrefs.get(Profile.getLastUsedRegularProfile())
.getString(Pref.GOOGLE_SERVICES_LAST_USERNAME)); .getString(Pref.GOOGLE_SERVICES_LAST_USERNAME));
List<String> accountNames = AccountUtils.toAccountNames( Set<String> accountNames = new ArraySet<>(AccountUtils.toAccountNames(
AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts()); AccountManagerFacadeProvider.getInstance().tryGetGoogleAccounts()));
Supplier<Set<String>> accountNamesSupplier = () -> new ArraySet<>(accountNames); if (!shouldLaunchSigninPromo(preferencesManager, currentMajorVersion, isSignedIn,
IdentityManager identityManager = IdentityServicesProvider.get().getIdentityManager( wasSignedIn, accountNames)) {
Profile.getLastUsedRegularProfile());
if (!shouldLaunchSigninPromo(preferencesManager, currentMajorVersion,
identityManager.hasPrimaryAccount(), wasSignedIn, accountNamesSupplier)) {
return false; return false;
} }
SigninUtils.startSigninActivityIfAllowed(activity, SigninAccessPoint.SIGNIN_PROMO); SigninUtils.startSigninActivityIfAllowed(activity, SigninAccessPoint.SIGNIN_PROMO);
preferencesManager.setSigninPromoLastShownVersion(currentMajorVersion); preferencesManager.setSigninPromoLastShownVersion(currentMajorVersion);
preferencesManager.setSigninPromoLastAccountNames(new ArraySet<>(accountNames)); preferencesManager.setSigninPromoLastAccountNames(accountNames);
return true; return true;
} }
...@@ -66,15 +69,13 @@ public class SigninPromoUtil { ...@@ -66,15 +69,13 @@ public class SigninPromoUtil {
* @param currentMajorVersion the current major version of Chrome * @param currentMajorVersion the current major version of Chrome
* @param isSignedIn is user currently signed in * @param isSignedIn is user currently signed in
* @param wasSignedIn has used manually signed out * @param wasSignedIn has used manually signed out
* @param accountNamesSupplier the supplier of the set of account names currently on device. * @param accountNames the list of accounts on the device
* Supplier is used here because AccountManagerFacade cache may be not populated yet, so
* it makes sense to check other flags before getting accounts.
* @return Whether the signin promo should be shown. * @return Whether the signin promo should be shown.
*/ */
@VisibleForTesting @VisibleForTesting
static boolean shouldLaunchSigninPromo(SigninPreferencesManager preferencesManager, static boolean shouldLaunchSigninPromo(SigninPreferencesManager preferencesManager,
int currentMajorVersion, boolean isSignedIn, boolean wasSignedIn, int currentMajorVersion, boolean isSignedIn, boolean wasSignedIn,
Supplier<Set<String>> accountNamesSupplier) { Set<String> accountNames) {
int lastPromoMajorVersion = preferencesManager.getSigninPromoLastShownVersion(); int lastPromoMajorVersion = preferencesManager.getSigninPromoLastShownVersion();
if (lastPromoMajorVersion == 0) { if (lastPromoMajorVersion == 0) {
preferencesManager.setSigninPromoLastShownVersion(currentMajorVersion); preferencesManager.setSigninPromoLastShownVersion(currentMajorVersion);
...@@ -90,9 +91,7 @@ public class SigninPromoUtil { ...@@ -90,9 +91,7 @@ public class SigninPromoUtil {
// Promo can be shown at most once every 2 Chrome major versions. // Promo can be shown at most once every 2 Chrome major versions.
if (currentMajorVersion < lastPromoMajorVersion + 2) return false; if (currentMajorVersion < lastPromoMajorVersion + 2) return false;
// Defer getting accounts, as AccountManagerFacade cache may be not populated yet. // Don't show if the account list isn't available yet or there are no accounts in it.
Set<String> accountNames = accountNamesSupplier.get();
// Don't show if there are no Google accounts on the device.
if (accountNames.isEmpty()) return false; if (accountNames.isEmpty()) return false;
// Don't show if no new accounts have been added after the last time promo was shown. // Don't show if no new accounts have been added after the last time promo was shown.
......
...@@ -25,6 +25,7 @@ import org.chromium.base.supplier.Supplier; ...@@ -25,6 +25,7 @@ import org.chromium.base.supplier.Supplier;
import org.chromium.base.test.BaseRobolectricTestRunner; import org.chromium.base.test.BaseRobolectricTestRunner;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections;
import java.util.Set; import java.util.Set;
/** Tests for {@link SigninPromoUtil}. */ /** Tests for {@link SigninPromoUtil}. */
...@@ -45,17 +46,6 @@ public class SigninPromoUtilTest { ...@@ -45,17 +46,6 @@ public class SigninPromoUtilTest {
verifyNoMoreInteractions(ignoreStubs(mPreferencesManager)); verifyNoMoreInteractions(ignoreStubs(mPreferencesManager));
} }
/**
* Returns account list supplier that throws unchecked exception, causing the test to fail. This
* is helpful to ensure that other signals for {@link SigninPromoUtil#shouldLaunchSigninPromo}
* are checked before getting account list (as account list may not be ready yet).
*/
private Supplier<Set<String>> shouldNotTryToGetAccounts() {
return () -> {
throw new RuntimeException("Should not try to get accounts!");
};
}
/** /**
* Creates a {@link Supplier} that returns a list of accounts provided to this method. * Creates a {@link Supplier} that returns a list of accounts provided to this method.
* @param accountNames The account names to return from {@link Supplier} * @param accountNames The account names to return from {@link Supplier}
...@@ -68,7 +58,7 @@ public class SigninPromoUtilTest { ...@@ -68,7 +58,7 @@ public class SigninPromoUtilTest {
public void whenNoLastShownVersionShouldReturnFalseAndSaveVersion() { public void whenNoLastShownVersionShouldReturnFalseAndSaveVersion() {
when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(0); when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(0);
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, shouldNotTryToGetAccounts())); mPreferencesManager, 42, false, false, ImmutableSet.of("test@gmail.com")));
verify(mPreferencesManager).setSigninPromoLastShownVersion(42); verify(mPreferencesManager).setSigninPromoLastShownVersion(42);
} }
...@@ -76,28 +66,28 @@ public class SigninPromoUtilTest { ...@@ -76,28 +66,28 @@ public class SigninPromoUtilTest {
public void whenSignedInShouldReturnFalse() { public void whenSignedInShouldReturnFalse() {
when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38); when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38);
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, true, false, shouldNotTryToGetAccounts())); mPreferencesManager, 42, true, false, ImmutableSet.of("test@gmail.com")));
} }
@Test @Test
public void whenWasSignedInShouldReturnFalse() { public void whenWasSignedInShouldReturnFalse() {
when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38); when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38);
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, true, shouldNotTryToGetAccounts())); mPreferencesManager, 42, false, true, ImmutableSet.of("test@gmail.com")));
} }
@Test @Test
public void whenVersionDifferenceTooSmallShouldReturnFalse() { public void whenVersionDifferenceTooSmallShouldReturnFalse() {
when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(41); when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(41);
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, shouldNotTryToGetAccounts())); mPreferencesManager, 42, false, false, ImmutableSet.of("test@gmail.com")));
} }
@Test @Test
public void whenNoAccountsShouldReturnFalse() { public void whenNoAccountsShouldReturnFalse() {
when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38); when(mPreferencesManager.getSigninPromoLastShownVersion()).thenReturn(38);
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, accountsSupplier())); mPreferencesManager, 42, false, false, Collections.emptySet()));
} }
@Test @Test
...@@ -106,7 +96,7 @@ public class SigninPromoUtilTest { ...@@ -106,7 +96,7 @@ public class SigninPromoUtilTest {
// Old implementation hasn't been storing account list // Old implementation hasn't been storing account list
when(mPreferencesManager.getSigninPromoLastAccountNames()).thenReturn(null); when(mPreferencesManager.getSigninPromoLastAccountNames()).thenReturn(null);
Assert.assertTrue(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertTrue(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, accountsSupplier("test@gmail.com"))); mPreferencesManager, 42, false, false, ImmutableSet.of("test@gmail.com")));
} }
@Test @Test
...@@ -115,7 +105,7 @@ public class SigninPromoUtilTest { ...@@ -115,7 +105,7 @@ public class SigninPromoUtilTest {
when(mPreferencesManager.getSigninPromoLastAccountNames()) when(mPreferencesManager.getSigninPromoLastAccountNames())
.thenReturn(ImmutableSet.of("test@gmail.com")); .thenReturn(ImmutableSet.of("test@gmail.com"));
Assert.assertTrue(SigninPromoUtil.shouldLaunchSigninPromo(mPreferencesManager, 42, false, Assert.assertTrue(SigninPromoUtil.shouldLaunchSigninPromo(mPreferencesManager, 42, false,
false, accountsSupplier("test@gmail.com", "test2@gmail.com"))); false, ImmutableSet.of("test@gmail.com", "test2@gmail.com")));
} }
@Test @Test
...@@ -124,7 +114,7 @@ public class SigninPromoUtilTest { ...@@ -124,7 +114,7 @@ public class SigninPromoUtilTest {
when(mPreferencesManager.getSigninPromoLastAccountNames()) when(mPreferencesManager.getSigninPromoLastAccountNames())
.thenReturn(ImmutableSet.of("test@gmail.com")); .thenReturn(ImmutableSet.of("test@gmail.com"));
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, accountsSupplier("test@gmail.com"))); mPreferencesManager, 42, false, false, ImmutableSet.of("test@gmail.com")));
} }
@Test @Test
...@@ -133,6 +123,6 @@ public class SigninPromoUtilTest { ...@@ -133,6 +123,6 @@ public class SigninPromoUtilTest {
when(mPreferencesManager.getSigninPromoLastAccountNames()) when(mPreferencesManager.getSigninPromoLastAccountNames())
.thenReturn(ImmutableSet.of("test@gmail.com", "test2@gmail.com")); .thenReturn(ImmutableSet.of("test@gmail.com", "test2@gmail.com"));
Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo( Assert.assertFalse(SigninPromoUtil.shouldLaunchSigninPromo(
mPreferencesManager, 42, false, false, accountsSupplier("test2@gmail.com"))); mPreferencesManager, 42, false, false, ImmutableSet.of("test2@gmail.com")));
} }
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment