Commit 859bc0e6 authored by Mihai Sardarescu's avatar Mihai Sardarescu Committed by Commit Bot

[Dice] Avoid showing the sync confirmation dialog before sync engine starts.

In pre-DICE, the sync confirmation dialog was always shown after the
accounts were added to the Gaia cookies. This took several seconds
allowing the sync engine to initialize and check whether sync was
allowed for the given account.

When DICE enabled, the sync confirmation dialog should only be shown
after sync has been initialized or failed to be initialized. This allows
us to make sure that the policy to enable or disable sync for the given
account is checked before displaying the sync confirmation dialog.

BUG = 812546

Change-Id: Ic414cd8eb5a810a1ff0827526361b10f8e76210b
Reviewed-on: https://chromium-review.googlesource.com/921741Reviewed-by: default avatarDavid Roger <droger@chromium.org>
Reviewed-by: default avatarNicolas Zea <zea@chromium.org>
Commit-Queue: Mihai Sardarescu <msarda@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537348}
parent 46ec8079
...@@ -306,15 +306,42 @@ void DiceTurnSyncOnHelper::SigninAndShowSyncConfirmationUI() { ...@@ -306,15 +306,42 @@ void DiceTurnSyncOnHelper::SigninAndShowSyncConfirmationUI() {
signin_metrics::LogSigninReason(signin_reason_); signin_metrics::LogSigninReason(signin_reason_);
base::RecordAction(base::UserMetricsAction("Signin_Signin_Succeed")); base::RecordAction(base::UserMetricsAction("Signin_Signin_Succeed"));
// Take a SyncSetupInProgressHandle, so that the UI code can use
// IsFirstSyncSetupInProgress() as a way to know if there is a signin in
// progress.
// TODO(https://crbug.com/811211): Remove this handle.
browser_sync::ProfileSyncService* sync_service = GetProfileSyncService(); browser_sync::ProfileSyncService* sync_service = GetProfileSyncService();
if (sync_service) if (sync_service) {
// Take a SyncSetupInProgressHandle, so that the UI code can use
// IsFirstSyncSetupInProgress() as a way to know if there is a signin in
// progress.
// TODO(https://crbug.com/811211): Remove this handle.
sync_blocker_ = sync_service->GetSetupInProgressHandle(); sync_blocker_ = sync_service->GetSetupInProgressHandle();
// Show Sync confirmation. if (SyncStartupTracker::GetSyncServiceState(profile_) ==
SyncStartupTracker::SYNC_STARTUP_PENDING) {
// Wait until sync is initialized so that the confirmation UI can be
// aware of startup errors. This is needed to make sure that the sync
// confirmation dialog is shown only after the sync service had a chance
// to check whether sync was disabled by admin.
// See http://crbug.com/812546
sync_startup_tracker_.reset(new SyncStartupTracker(profile_, this));
return;
}
}
ShowSyncConfirmationUI();
}
void DiceTurnSyncOnHelper::SyncStartupCompleted() {
DCHECK(sync_startup_tracker_);
sync_startup_tracker_.reset();
ShowSyncConfirmationUI();
}
void DiceTurnSyncOnHelper::SyncStartupFailed() {
DCHECK(sync_startup_tracker_);
sync_startup_tracker_.reset();
ShowSyncConfirmationUI();
}
void DiceTurnSyncOnHelper::ShowSyncConfirmationUI() {
delegate_->ShowSyncConfirmation( delegate_->ShowSyncConfirmation(
base::BindOnce(&DiceTurnSyncOnHelper::FinishSyncSetupAndDelete, base::BindOnce(&DiceTurnSyncOnHelper::FinishSyncSetupAndDelete,
weak_pointer_factory_.GetWeakPtr())); weak_pointer_factory_.GetWeakPtr()));
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync/sync_startup_tracker.h"
#include "chrome/browser/ui/webui/signin/login_ui_service.h" #include "chrome/browser/ui/webui/signin/login_ui_service.h"
#include "components/signin/core/browser/account_info.h" #include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/signin_metrics.h" #include "components/signin/core/browser/signin_metrics.h"
...@@ -30,7 +31,7 @@ class SyncSetupInProgressHandle; ...@@ -30,7 +31,7 @@ class SyncSetupInProgressHandle;
// Handles details of signing the user in with SigninManager and turning on // Handles details of signing the user in with SigninManager and turning on
// sync for an account that is already present in the token service. // sync for an account that is already present in the token service.
class DiceTurnSyncOnHelper { class DiceTurnSyncOnHelper : public SyncStartupTracker::Observer {
public: public:
// Behavior when the signin is aborted (by an error or cancelled by the user). // Behavior when the signin is aborted (by an error or cancelled by the user).
enum class SigninAbortedMode { enum class SigninAbortedMode {
...@@ -107,6 +108,10 @@ class DiceTurnSyncOnHelper { ...@@ -107,6 +108,10 @@ class DiceTurnSyncOnHelper {
const std::string& account_id, const std::string& account_id,
SigninAbortedMode signin_aborted_mode); SigninAbortedMode signin_aborted_mode);
// SyncStartupTracker::Observer:
void SyncStartupCompleted() override;
void SyncStartupFailed() override;
private: private:
enum class ProfileMode { enum class ProfileMode {
// Attempts to sign the user in |profile_|. Note that if the account to be // Attempts to sign the user in |profile_|. Note that if the account to be
...@@ -120,7 +125,7 @@ class DiceTurnSyncOnHelper { ...@@ -120,7 +125,7 @@ class DiceTurnSyncOnHelper {
}; };
// DiceTurnSyncOnHelper deletes itself. // DiceTurnSyncOnHelper deletes itself.
~DiceTurnSyncOnHelper(); ~DiceTurnSyncOnHelper() override;
// Handles can offer sign-in errors. It returns true if there is an error, // Handles can offer sign-in errors. It returns true if there is an error,
// and false otherwise. // and false otherwise.
...@@ -164,6 +169,11 @@ class DiceTurnSyncOnHelper { ...@@ -164,6 +169,11 @@ class DiceTurnSyncOnHelper {
// UI. // UI.
void SigninAndShowSyncConfirmationUI(); void SigninAndShowSyncConfirmationUI();
// Displays the Sync confirmation UI.
// Note: If sync fails to start (e.g. sync is disabled by admin), the sync
// confirmation dialog will be updated accordingly.
void ShowSyncConfirmationUI();
// Handles the user input from the sync confirmation UI and deletes this // Handles the user input from the sync confirmation UI and deletes this
// object. // object.
void FinishSyncSetupAndDelete( void FinishSyncSetupAndDelete(
...@@ -193,6 +203,8 @@ class DiceTurnSyncOnHelper { ...@@ -193,6 +203,8 @@ class DiceTurnSyncOnHelper {
std::string dm_token_; std::string dm_token_;
std::string client_id_; std::string client_id_;
std::unique_ptr<SyncStartupTracker> sync_startup_tracker_;
base::WeakPtrFactory<DiceTurnSyncOnHelper> weak_pointer_factory_; base::WeakPtrFactory<DiceTurnSyncOnHelper> weak_pointer_factory_;
DISALLOW_COPY_AND_ASSIGN(DiceTurnSyncOnHelper); DISALLOW_COPY_AND_ASSIGN(DiceTurnSyncOnHelper);
}; };
......
...@@ -38,6 +38,9 @@ ...@@ -38,6 +38,9 @@
#include "content/public/test/test_browser_thread_bundle.h" #include "content/public/test/test_browser_thread_bundle.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using ::testing::AtLeast;
using ::testing::Return;
class DiceTurnSyncOnHelperTest; class DiceTurnSyncOnHelperTest;
namespace { namespace {
...@@ -221,6 +224,33 @@ class DiceTurnSyncOnHelperTest : public testing::Test { ...@@ -221,6 +224,33 @@ class DiceTurnSyncOnHelperTest : public testing::Test {
std::make_unique<TestDiceTurnSyncOnHelperDelegate>(this)); std::make_unique<TestDiceTurnSyncOnHelperDelegate>(this));
} }
void SetExpectationsForSyncStartupCompleted() {
browser_sync::ProfileSyncServiceMock* sync_service_mock =
GetProfileSyncServiceMock();
EXPECT_CALL(*sync_service_mock, GetSetupInProgressHandle()).Times(1);
EXPECT_CALL(*sync_service_mock, CanSyncStart())
.Times(AtLeast(0))
.WillRepeatedly(Return(true));
EXPECT_CALL(*sync_service_mock, IsEngineInitialized())
.Times(AtLeast(0))
.WillRepeatedly(Return(true));
}
void SetExpectationsForSyncStartupPending() {
browser_sync::ProfileSyncServiceMock* sync_service_mock =
GetProfileSyncServiceMock();
EXPECT_CALL(*sync_service_mock, GetSetupInProgressHandle()).Times(1);
EXPECT_CALL(*sync_service_mock, CanSyncStart())
.Times(AtLeast(0))
.WillRepeatedly(Return(true));
EXPECT_CALL(*sync_service_mock, IsEngineInitialized())
.Times(AtLeast(0))
.WillRepeatedly(Return(false));
EXPECT_CALL(*sync_service_mock, waiting_for_auth())
.Times(AtLeast(0))
.WillRepeatedly(Return(true));
}
void CheckDelegateCalls() { void CheckDelegateCalls() {
EXPECT_EQ(expected_login_error_email_, login_error_email_); EXPECT_EQ(expected_login_error_email_, login_error_email_);
EXPECT_EQ(expected_login_error_message_, login_error_message_); EXPECT_EQ(expected_login_error_message_, login_error_message_);
...@@ -532,10 +562,9 @@ TEST_F(DiceTurnSyncOnHelperTest, EnterpriseConfirmationNewProfile) { ...@@ -532,10 +562,9 @@ TEST_F(DiceTurnSyncOnHelperTest, EnterpriseConfirmationNewProfile) {
TEST_F(DiceTurnSyncOnHelperTest, UndoSync) { TEST_F(DiceTurnSyncOnHelperTest, UndoSync) {
// Set expectations. // Set expectations.
expected_sync_confirmation_shown_ = true; expected_sync_confirmation_shown_ = true;
browser_sync::ProfileSyncServiceMock* sync_service_mock = SetExpectationsForSyncStartupCompleted();
GetProfileSyncServiceMock(); EXPECT_CALL(*GetProfileSyncServiceMock(), SetFirstSetupComplete()).Times(0);
EXPECT_CALL(*sync_service_mock, SetFirstSetupComplete()).Times(0);
EXPECT_CALL(*sync_service_mock, GetSetupInProgressHandle()).Times(1);
// Signin flow. // Signin flow.
EXPECT_FALSE(signin_manager()->IsAuthenticated()); EXPECT_FALSE(signin_manager()->IsAuthenticated());
CreateDiceTurnOnSyncHelper( CreateDiceTurnOnSyncHelper(
...@@ -551,10 +580,9 @@ TEST_F(DiceTurnSyncOnHelperTest, ConfigureSync) { ...@@ -551,10 +580,9 @@ TEST_F(DiceTurnSyncOnHelperTest, ConfigureSync) {
// Set expectations. // Set expectations.
expected_sync_confirmation_shown_ = true; expected_sync_confirmation_shown_ = true;
expected_sync_settings_shown_ = true; expected_sync_settings_shown_ = true;
browser_sync::ProfileSyncServiceMock* sync_service_mock = SetExpectationsForSyncStartupCompleted();
GetProfileSyncServiceMock(); EXPECT_CALL(*GetProfileSyncServiceMock(), SetFirstSetupComplete()).Times(0);
EXPECT_CALL(*sync_service_mock, SetFirstSetupComplete()).Times(0);
EXPECT_CALL(*sync_service_mock, GetSetupInProgressHandle()).Times(1);
// Configure the test. // Configure the test.
sync_confirmation_result_ = sync_confirmation_result_ =
LoginUIService::SyncConfirmationUIClosedResult::CONFIGURE_SYNC_FIRST; LoginUIService::SyncConfirmationUIClosedResult::CONFIGURE_SYNC_FIRST;
...@@ -572,10 +600,8 @@ TEST_F(DiceTurnSyncOnHelperTest, ConfigureSync) { ...@@ -572,10 +600,8 @@ TEST_F(DiceTurnSyncOnHelperTest, ConfigureSync) {
TEST_F(DiceTurnSyncOnHelperTest, StartSync) { TEST_F(DiceTurnSyncOnHelperTest, StartSync) {
// Set expectations. // Set expectations.
expected_sync_confirmation_shown_ = true; expected_sync_confirmation_shown_ = true;
browser_sync::ProfileSyncServiceMock* sync_service_mock = SetExpectationsForSyncStartupCompleted();
GetProfileSyncServiceMock(); EXPECT_CALL(*GetProfileSyncServiceMock(), SetFirstSetupComplete()).Times(1);
EXPECT_CALL(*sync_service_mock, SetFirstSetupComplete()).Times(1);
EXPECT_CALL(*sync_service_mock, GetSetupInProgressHandle()).Times(1);
// Configure the test. // Configure the test.
sync_confirmation_result_ = LoginUIService::SyncConfirmationUIClosedResult:: sync_confirmation_result_ = LoginUIService::SyncConfirmationUIClosedResult::
SYNC_WITH_DEFAULT_SETTINGS; SYNC_WITH_DEFAULT_SETTINGS;
...@@ -588,3 +614,58 @@ TEST_F(DiceTurnSyncOnHelperTest, StartSync) { ...@@ -588,3 +614,58 @@ TEST_F(DiceTurnSyncOnHelperTest, StartSync) {
EXPECT_EQ(account_id(), signin_manager()->GetAuthenticatedAccountId()); EXPECT_EQ(account_id(), signin_manager()->GetAuthenticatedAccountId());
CheckDelegateCalls(); CheckDelegateCalls();
} }
// Tests that the user is signed in and Sync configuration is complete.
// Regression test for http://crbug.com/812546
TEST_F(DiceTurnSyncOnHelperTest,
ShowSyncDialogBlockedUntilSyncStartupCompleted) {
// Set expectations.
expected_sync_confirmation_shown_ = false;
SetExpectationsForSyncStartupPending();
// Signin flow.
EXPECT_FALSE(signin_manager()->IsAuthenticated());
DiceTurnSyncOnHelper* dice_sync_starter = CreateDiceTurnOnSyncHelper(
DiceTurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT);
// Check that the account was set in the sign-in manager, but the sync
// confirmation dialog was not yet shown.
EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id()));
EXPECT_EQ(account_id(), signin_manager()->GetAuthenticatedAccountId());
CheckDelegateCalls();
// Simulate that sync startup has completed.
expected_sync_confirmation_shown_ = true;
EXPECT_CALL(*GetProfileSyncServiceMock(), SetFirstSetupComplete()).Times(1);
sync_confirmation_result_ = LoginUIService::SyncConfirmationUIClosedResult::
SYNC_WITH_DEFAULT_SETTINGS;
dice_sync_starter->SyncStartupCompleted();
CheckDelegateCalls();
}
// Tests that the user is signed in and Sync configuration is complete.
// Regression test for http://crbug.com/812546
TEST_F(DiceTurnSyncOnHelperTest, ShowSyncDialogBlockedUntilSyncStartupFailed) {
// Set expectations.
expected_sync_confirmation_shown_ = false;
SetExpectationsForSyncStartupPending();
// Signin flow.
EXPECT_FALSE(signin_manager()->IsAuthenticated());
DiceTurnSyncOnHelper* dice_sync_starter = CreateDiceTurnOnSyncHelper(
DiceTurnSyncOnHelper::SigninAbortedMode::REMOVE_ACCOUNT);
// Check that the primary account was added to the token service and in the
// sign-in manager.
EXPECT_TRUE(token_service()->RefreshTokenIsAvailable(account_id()));
EXPECT_EQ(account_id(), signin_manager()->GetAuthenticatedAccountId());
CheckDelegateCalls();
// Simulate that sync startup has failed.
expected_sync_confirmation_shown_ = true;
EXPECT_CALL(*GetProfileSyncServiceMock(), SetFirstSetupComplete()).Times(1);
sync_confirmation_result_ = LoginUIService::SyncConfirmationUIClosedResult::
SYNC_WITH_DEFAULT_SETTINGS;
dice_sync_starter->SyncStartupFailed();
CheckDelegateCalls();
}
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