1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/sync/one_click_signin_sync_observer.h"
6
7#include "base/bind.h"
8#include "base/message_loop/message_loop.h"
9#include "chrome/browser/profiles/profile.h"
10#include "chrome/browser/signin/signin_promo.h"
11#include "chrome/browser/sync/profile_sync_service.h"
12#include "chrome/browser/sync/profile_sync_service_factory.h"
13#include "content/public/browser/web_contents.h"
14#include "content/public/browser/web_contents_delegate.h"
15
16namespace {
17
18void CloseTab(content::WebContents* tab) {
19  content::WebContentsDelegate* tab_delegate = tab->GetDelegate();
20  if (tab_delegate)
21    tab_delegate->CloseContents(tab);
22}
23
24}  // namespace
25
26
27OneClickSigninSyncObserver::OneClickSigninSyncObserver(
28    content::WebContents* web_contents,
29    const GURL& continue_url)
30    : content::WebContentsObserver(web_contents),
31      continue_url_(continue_url),
32      weak_ptr_factory_(this) {
33  DCHECK(!continue_url_.is_empty());
34
35  ProfileSyncService* sync_service = GetSyncService(web_contents);
36  if (sync_service) {
37    sync_service->AddObserver(this);
38  } else {
39    LoadContinueUrl();
40    // Post a task rather than calling |delete this| here, so that the
41    // destructor is not called directly from the constructor. Note that it's
42    // important to pass a weak pointer rather than base::Unretained(this)
43    // because it's possible for e.g. WebContentsDestroyed() to be called
44    // before this task has a chance to run.
45    base::MessageLoop::current()->PostTask(
46        FROM_HERE,
47        base::Bind(&OneClickSigninSyncObserver::DeleteObserver,
48                   weak_ptr_factory_.GetWeakPtr()));
49  }
50}
51
52OneClickSigninSyncObserver::~OneClickSigninSyncObserver() {}
53
54void OneClickSigninSyncObserver::WebContentsDestroyed() {
55  ProfileSyncService* sync_service = GetSyncService(web_contents());
56  if (sync_service)
57    sync_service->RemoveObserver(this);
58
59  delete this;
60}
61
62void OneClickSigninSyncObserver::OnStateChanged() {
63  ProfileSyncService* sync_service = GetSyncService(web_contents());
64
65  // At this point, the sign-in process is complete, and control has been handed
66  // back to the sync engine. Close the gaia sign in tab if the |continue_url_|
67  // contains the |auto_close| parameter. Otherwise, wait for sync setup to
68  // complete and then navigate to the |continue_url_|.
69  if (signin::IsAutoCloseEnabledInURL(continue_url_)) {
70    // Close the Gaia sign-in tab via a task to make sure we aren't in the
71    // middle of any WebUI handler code.
72    base::MessageLoop::current()->PostTask(
73        FROM_HERE,
74        base::Bind(&CloseTab, base::Unretained(web_contents())));
75  } else {
76    if (sync_service->FirstSetupInProgress()) {
77      // Sync setup has not completed yet. Wait for it to complete.
78      return;
79    }
80
81    if (sync_service->sync_initialized() &&
82        signin::GetSourceForPromoURL(continue_url_)
83            != signin::SOURCE_SETTINGS) {
84      // TODO(isherman): Having multiple settings pages open can cause issues
85      // redirecting after Sync is set up: http://crbug.com/355885
86      LoadContinueUrl();
87    }
88  }
89
90  sync_service->RemoveObserver(this);
91  delete this;
92}
93
94void OneClickSigninSyncObserver::LoadContinueUrl() {
95  web_contents()->GetController().LoadURL(
96      continue_url_,
97      content::Referrer(),
98      ui::PAGE_TRANSITION_AUTO_TOPLEVEL,
99      std::string());
100}
101
102ProfileSyncService* OneClickSigninSyncObserver::GetSyncService(
103    content::WebContents* web_contents) {
104  Profile* profile =
105      Profile::FromBrowserContext(web_contents->GetBrowserContext());
106  return ProfileSyncServiceFactory::GetForProfile(profile);
107}
108
109// static
110void OneClickSigninSyncObserver::DeleteObserver(
111    base::WeakPtr<OneClickSigninSyncObserver> observer) {
112  if (observer)
113    delete observer.get();
114}
115