Commit 6ffc54a0 authored by Iulia Harasim's avatar Iulia Harasim Committed by Commit Bot

[Android] Add tests for personalized signin promos in Bookmarks

This CL adds a handful of tests for the personalized signin promos in
Bookmarks. The tests verify whether:
  - The promo can be manually dismissed / the promo gets automatically
    dismissed after the impression limit has been reached.
  - The signin buttons fire the right intents when clicked.
It also updates the API of AccountSigninActivity and replaces some
anonymous classes in SigninAndSyncView with lambdas.

Bug: 737743
Change-Id: I45d7dfd246f98e1a2ca4e3bf79616274c858d256
Reviewed-on: https://chromium-review.googlesource.com/686755
Commit-Queue: Iulia Harasim <iuliah@google.com>
Reviewed-by: default avatarBoris Sazonov <bsazonov@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#505050}
parent c6083866
......@@ -61,22 +61,6 @@ public class AccountSigninActivity extends AppCompatActivity
private @SigninFlowType int mSigninFlowType;
private boolean mIsFromPersonalizedPromo;
/**
* A convenience method to create a AccountSigninActivity passing the access point as an
* intent.
* @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
* @param isFromPersonalizedPromo Whether the signin activity is started from a personalized
* promo.
*/
public static void startAccountSigninActivity(
Context context, @AccessPoint int accessPoint, boolean isFromPersonalizedPromo) {
Intent intent = new Intent(context, AccountSigninActivity.class);
intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_DEFAULT);
intent.putExtra(INTENT_IS_FROM_PERSONALIZED_PROMO, isFromPersonalizedPromo);
context.startActivity(intent);
}
/**
* A convenience method to create a AccountSigninActivity passing the access point as an
* intent. Checks if the sign in flow can be started before showing the activity.
......@@ -91,12 +75,28 @@ public class AccountSigninActivity extends AppCompatActivity
return false;
}
startAccountSigninActivity(context, accessPoint, false);
context.startActivity(createIntentForDefaultSigninFlow(context, accessPoint, false));
return true;
}
/**
* Starts AccountSigninActivity from signin confirmation page.
* Creates an {@link Intent} which can be used to start the default signin flow.
* @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
* @param isFromPersonalizedPromo Whether the signin activity is started from a personalized
* promo.
*/
public static Intent createIntentForDefaultSigninFlow(
Context context, @AccessPoint int accessPoint, boolean isFromPersonalizedPromo) {
Intent intent = new Intent(context, AccountSigninActivity.class);
intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_DEFAULT);
intent.putExtra(INTENT_IS_FROM_PERSONALIZED_PROMO, isFromPersonalizedPromo);
return intent;
}
/**
* Creates an {@link Intent} which can be used to start the signin flow from the confirmation
* screen.
* @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
* @param selectAccount Account for which signin confirmation page should be shown.
* @param isDefaultAccount Whether {@param selectedAccount} is the default account on
......@@ -104,30 +104,32 @@ public class AccountSigninActivity extends AppCompatActivity
* @param isFromPersonalizedPromo Whether the signin activity is started from a personalized
* promo.
*/
public static void startFromConfirmationPage(Context context, @AccessPoint int accessPoint,
String selectAccount, boolean isDefaultAccount, boolean isFromPersonalizedPromo) {
public static Intent createIntentForConfirmationOnlySigninFlow(Context context,
@AccessPoint int accessPoint, String selectAccount, boolean isDefaultAccount,
boolean isFromPersonalizedPromo) {
Intent intent = new Intent(context, AccountSigninActivity.class);
intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_CONFIRMATION_ONLY);
intent.putExtra(INTENT_ACCOUNT_NAME, selectAccount);
intent.putExtra(INTENT_IS_DEFAULT_ACCOUNT, isDefaultAccount);
intent.putExtra(INTENT_IS_FROM_PERSONALIZED_PROMO, isFromPersonalizedPromo);
context.startActivity(intent);
return intent;
}
/**
* Starts AccountSigninActivity from "Add account" page.
* Creates an {@link Intent} which can be used to start the signin flow from the "Add Account"
* page.
* @param accessPoint {@link AccessPoint} for starting signin flow. Used in metrics.
* @param isFromPersonalizedPromo Whether the signin activity is started from a personalized
* promo.
*/
public static void startFromAddAccountPage(
public static Intent createIntentForAddAccountSigninFlow(
Context context, @AccessPoint int accessPoint, boolean isFromPersonalizedPromo) {
Intent intent = new Intent(context, AccountSigninActivity.class);
intent.putExtra(INTENT_SIGNIN_ACCESS_POINT, accessPoint);
intent.putExtra(INTENT_SIGNIN_FLOW_TYPE, SIGNIN_FLOW_ADD_NEW_ACCOUNT);
intent.putExtra(INTENT_IS_FROM_PERSONALIZED_PROMO, isFromPersonalizedPromo);
context.startActivity(intent);
return intent;
}
@Override
......
......@@ -195,26 +195,18 @@ public class SigninAndSyncView extends LinearLayout
? R.string.bookmark_sign_in_promo_description
: R.string.recent_tabs_sign_in_promo_description;
ButtonState positiveButton = new ButtonPresent(
R.string.sign_in_button,
new OnClickListener() {
@Override
public void onClick(View view) {
AccountSigninActivity.startAccountSigninActivity(
getContext(), mAccessPoint, false);
}
});
ButtonState positiveButton = new ButtonPresent(R.string.sign_in_button, view -> {
Context context = getContext();
context.startActivity(AccountSigninActivity.createIntentForDefaultSigninFlow(
context, mAccessPoint, false));
});
ButtonState negativeButton;
if (mAccessPoint == SigninAccessPoint.RECENT_TABS) {
negativeButton = new ButtonAbsent();
} else {
negativeButton = new ButtonPresent(R.string.no_thanks, new OnClickListener() {
@Override
public void onClick(View view) {
mListener.onViewDismissed();
}
});
negativeButton =
new ButtonPresent(R.string.no_thanks, view -> mListener.onViewDismissed());
}
return new ViewState(descId, positiveButton, negativeButton);
......@@ -226,18 +218,13 @@ public class SigninAndSyncView extends LinearLayout
int descId = R.string.recent_tabs_sync_promo_enable_android_sync;
ButtonState positiveButton = new ButtonPresent(
R.string.open_settings_button,
new OnClickListener() {
@Override
public void onClick(View v) {
// TODO(crbug.com/557784): Like AccountManagementFragment, this would also
// benefit from going directly to an account.
Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, new String[] {"com.google"});
getContext().startActivity(intent);
}
});
ButtonState positiveButton = new ButtonPresent(R.string.open_settings_button, view -> {
// TODO(crbug.com/557784): Like AccountManagementFragment, this would also
// benefit from going directly to an account.
Intent intent = new Intent(Settings.ACTION_SYNC_SETTINGS);
intent.putExtra(Settings.EXTRA_ACCOUNT_TYPES, new String[] {"com.google"});
getContext().startActivity(intent);
});
return new ViewState(descId, positiveButton, new ButtonAbsent());
}
......@@ -247,15 +234,9 @@ public class SigninAndSyncView extends LinearLayout
? R.string.bookmarks_sync_promo_enable_sync
: R.string.recent_tabs_sync_promo_enable_chrome_sync;
ButtonState positiveButton = new ButtonPresent(
R.string.enable_sync_button,
new OnClickListener() {
@Override
public void onClick(View v) {
PreferencesLauncher.launchSettingsPage(getContext(),
SyncCustomizationFragment.class.getName());
}
});
ButtonState positiveButton = new ButtonPresent(R.string.enable_sync_button,
view -> PreferencesLauncher.launchSettingsPage(
getContext(), SyncCustomizationFragment.class.getName()));
return new ViewState(descId, positiveButton, new ButtonAbsent());
}
......
......@@ -14,6 +14,7 @@ import android.view.View;
import android.view.ViewGroup;
import org.chromium.base.ContextUtils;
import org.chromium.base.VisibleForTesting;
import org.chromium.base.metrics.RecordHistogram;
import org.chromium.base.metrics.RecordUserAction;
import org.chromium.chrome.R;
......@@ -43,6 +44,7 @@ public class SigninPromoController implements ImpressionTracker.Listener {
"signin_promo_impressions_count_bookmarks";
private static final String SIGNIN_PROMO_IMPRESSIONS_COUNT_SETTINGS =
"signin_promo_impressions_count_settings";
private static final int MAX_IMPRESSIONS_BOOKMARKS = 20;
private static final int MAX_IMPRESSIONS_SETTINGS = 5;
......@@ -224,7 +226,8 @@ public class SigninPromoController implements ImpressionTracker.Listener {
view.getSigninButton().setText(R.string.sign_in_to_chrome);
view.getSigninButton().setOnClickListener(promoView -> {
recordSigninButtonUsed();
AccountSigninActivity.startFromAddAccountPage(context, mAccessPoint, true);
context.startActivity(AccountSigninActivity.createIntentForAddAccountSigninFlow(
context, mAccessPoint, true));
});
view.getChooseAccountButton().setVisibility(View.GONE);
......@@ -240,8 +243,8 @@ public class SigninPromoController implements ImpressionTracker.Listener {
view.getSigninButton().setText(signinButtonText);
view.getSigninButton().setOnClickListener(promoView -> {
recordSigninButtonUsed();
AccountSigninActivity.startFromConfirmationPage(
context, mAccessPoint, mProfileData.getAccountName(), true, true);
context.startActivity(AccountSigninActivity.createIntentForConfirmationOnlySigninFlow(
context, mAccessPoint, mProfileData.getAccountName(), true, true));
});
String chooseAccountButtonText = context.getString(
......@@ -249,7 +252,8 @@ public class SigninPromoController implements ImpressionTracker.Listener {
view.getChooseAccountButton().setText(chooseAccountButtonText);
view.getChooseAccountButton().setOnClickListener(promoView -> {
recordSigninButtonUsed();
AccountSigninActivity.startAccountSigninActivity(context, mAccessPoint, true);
context.startActivity(AccountSigninActivity.createIntentForDefaultSigninFlow(
context, mAccessPoint, true));
});
view.getChooseAccountButton().setVisibility(View.VISIBLE);
}
......@@ -290,4 +294,9 @@ public class SigninPromoController implements ImpressionTracker.Listener {
preferences.edit().putInt(mImpressionCountName, numImpressions).apply();
}
}
@VisibleForTesting
public static int getMaxImpressionsBookmarksForTests() {
return MAX_IMPRESSIONS_BOOKMARKS;
}
}
......@@ -1410,6 +1410,7 @@ chrome_test_java_sources = [
"javatests/src/org/chromium/chrome/browser/banners/InstallerDelegateTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkBridgeTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkModelTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkPersonalizedSigninPromoTest.java",
"javatests/src/org/chromium/chrome/browser/bookmarks/BookmarkTest.java",
"javatests/src/org/chromium/chrome/browser/browseractions/BrowserActionActivityTest.java",
"javatests/src/org/chromium/chrome/browser/browsing_data/BrowsingDataRemoverIntegrationTest.java",
......
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.chrome.browser.bookmarks;
import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.Espresso.pressBack;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.doesNotExist;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
import android.accounts.Account;
import android.content.Intent;
import android.support.test.filters.LargeTest;
import android.support.test.filters.MediumTest;
import android.support.test.runner.intent.IntentCallback;
import android.support.test.runner.intent.IntentMonitorRegistry;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.chromium.base.ThreadUtils;
import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ChromeSwitches;
import org.chromium.chrome.browser.signin.AccountSigninActivity;
import org.chromium.chrome.browser.signin.SigninAccessPoint;
import org.chromium.chrome.browser.signin.SigninPromoController;
import org.chromium.chrome.test.ChromeActivityTestRule;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.components.signin.AccountManagerFacade;
import org.chromium.components.signin.ProfileDataSource;
import org.chromium.components.signin.test.util.AccountHolder;
import org.chromium.components.signin.test.util.FakeAccountManagerDelegate;
import java.io.Closeable;
import java.util.ArrayList;
import java.util.List;
/**
* Tests for the personalized signin promo on the Bookmarks page.
*/
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE,
"enable-features=AndroidSigninPromos"})
public class BookmarkPersonalizedSigninPromoTest {
private static final String TEST_ACCOUNT_NAME = "test@gmail.com";
private static final String TEST_FULL_NAME = "Test Account";
@Rule
public final ChromeActivityTestRule<ChromeActivity> mActivityTestRule =
new ChromeActivityTestRule<>(ChromeActivity.class);
private final FakeAccountManagerDelegate mAccountManagerDelegate =
new FakeAccountManagerDelegate(FakeAccountManagerDelegate.ENABLE_PROFILE_DATA_SOURCE);
@Before
public void setUp() throws Exception {
mActivityTestRule.startMainActivityFromLauncher();
AccountManagerFacade.overrideAccountManagerFacadeForTests(mAccountManagerDelegate);
}
@Test
@MediumTest
public void testManualDismissPromo() throws Exception {
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
onView(withId(R.id.signin_promo_close_button)).perform(click());
onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
}
@Test
@LargeTest
public void testAutoDismissPromo() throws Exception {
int impressionCap = SigninPromoController.getMaxImpressionsBookmarksForTests();
for (int impression = 0; impression < impressionCap; impression++) {
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
pressBack();
}
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(doesNotExist());
}
@Test
@MediumTest
public void testSigninButtonDefaultAccount() throws Exception {
addTestAccount();
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
final List<Intent> startedIntents;
try (IntentCallbackHelper helper = new IntentCallbackHelper()) {
onView(withId(R.id.signin_promo_signin_button)).perform(click());
startedIntents = helper.getStartedIntents();
}
assertEquals("Choosing to sign in with the default account should fire an intent!", 1,
startedIntents.size());
Intent expectedIntent = AccountSigninActivity.createIntentForConfirmationOnlySigninFlow(
mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER,
TEST_ACCOUNT_NAME, true, true);
assertTrue(expectedIntent.filterEquals(startedIntents.get(0)));
}
@Test
@MediumTest
public void testSigninButtonNotDefaultAccount() throws Exception {
addTestAccount();
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
final List<Intent> startedIntents;
try (IntentCallbackHelper helper = new IntentCallbackHelper()) {
onView(withId(R.id.signin_promo_choose_account_button)).perform(click());
startedIntents = helper.getStartedIntents();
}
assertEquals("Choosing to sign in with another account should fire an intent!", 1,
startedIntents.size());
Intent expectedIntent = AccountSigninActivity.createIntentForDefaultSigninFlow(
mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER, true);
assertTrue(expectedIntent.filterEquals(startedIntents.get(0)));
}
@Test
@MediumTest
public void testSigninButtonNewAccount() throws Exception {
openBookmarkManager();
onView(withId(R.id.signin_promo_view_container)).check(matches(isDisplayed()));
final List<Intent> startedIntents;
try (IntentCallbackHelper helper = new IntentCallbackHelper()) {
onView(withId(R.id.signin_promo_signin_button)).perform(click());
startedIntents = helper.getStartedIntents();
}
assertFalse(
"Adding a new account should fire at least one intent!", startedIntents.isEmpty());
Intent expectedIntent = AccountSigninActivity.createIntentForAddAccountSigninFlow(
mActivityTestRule.getActivity(), SigninAccessPoint.BOOKMARK_MANAGER, true);
// Comparing only the first intent as AccountSigninActivity will fire an intent after
// starting the flow to add an account.
assertTrue(expectedIntent.filterEquals(startedIntents.get(0)));
}
private void openBookmarkManager() throws InterruptedException {
onView(withId(R.id.menu_button)).perform(click());
onView(withText("Bookmarks")).perform(click());
}
private void addTestAccount() {
Account account = AccountManagerFacade.createAccountFromName(TEST_ACCOUNT_NAME);
AccountHolder.Builder accountHolder = AccountHolder.builder(account).alwaysAccept(true);
mAccountManagerDelegate.addAccountHolderExplicitly(accountHolder.build());
ProfileDataSource.ProfileData profileData =
new ProfileDataSource.ProfileData(TEST_ACCOUNT_NAME, null, TEST_FULL_NAME, null);
ThreadUtils.runOnUiThreadBlocking(
() -> mAccountManagerDelegate.setProfileData(TEST_ACCOUNT_NAME, profileData));
}
private static class IntentCallbackHelper implements IntentCallback, Closeable {
private final List<Intent> mStartedIntents = new ArrayList<>();
public IntentCallbackHelper() {
IntentMonitorRegistry.getInstance().addIntentCallback(this);
}
@Override
public void onIntentSent(Intent intent) {
mStartedIntents.add(intent);
}
@Override
public void close() {
IntentMonitorRegistry.getInstance().removeIntentCallback(this);
}
public List<Intent> getStartedIntents() {
return mStartedIntents;
}
}
}
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