1// Copyright (c) 2012 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/webui/ntp/new_tab_page_sync_handler.h"
6
7#include <vector>
8
9#include "base/bind.h"
10#include "base/bind_helpers.h"
11#include "base/prefs/pref_service.h"
12#include "base/strings/string_split.h"
13#include "base/strings/string_util.h"
14#include "base/strings/utf_string_conversions.h"
15#include "base/values.h"
16#include "chrome/browser/profiles/profile.h"
17#include "chrome/browser/signin/signin_manager_factory.h"
18#include "chrome/browser/signin/signin_promo.h"
19#include "chrome/browser/sync/profile_sync_service.h"
20#include "chrome/browser/sync/profile_sync_service_factory.h"
21#include "chrome/browser/ui/browser.h"
22#include "chrome/browser/ui/browser_finder.h"
23#include "chrome/browser/ui/chrome_pages.h"
24#include "chrome/browser/ui/webui/signin/login_ui_service.h"
25#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
26#include "chrome/common/pref_names.h"
27#include "chrome/grit/generated_resources.h"
28#include "components/signin/core/browser/signin_manager.h"
29#include "content/public/browser/render_view_host.h"
30#include "content/public/browser/web_ui.h"
31#include "net/cookies/cookie_monster.h"
32#include "net/url_request/url_request_context.h"
33#include "ui/base/l10n/l10n_util.h"
34
35NewTabPageSyncHandler::NewTabPageSyncHandler() : sync_service_(NULL),
36  waiting_for_initial_page_load_(true) {
37}
38
39NewTabPageSyncHandler::~NewTabPageSyncHandler() {
40  if (sync_service_)
41    sync_service_->RemoveObserver(this);
42}
43
44// static
45NewTabPageSyncHandler::MessageType
46    NewTabPageSyncHandler::FromSyncStatusMessageType(
47        sync_ui_util::MessageType type) {
48  switch (type) {
49    case sync_ui_util::SYNC_ERROR:
50      return SYNC_ERROR;
51    case sync_ui_util::SYNC_PROMO:
52      return SYNC_PROMO;
53    case sync_ui_util::PRE_SYNCED:
54    case sync_ui_util::SYNCED:
55    default:
56      return HIDE;
57  }
58}
59
60void NewTabPageSyncHandler::RegisterMessages() {
61  sync_service_ = ProfileSyncServiceFactory::GetInstance()->GetForProfile(
62      Profile::FromWebUI(web_ui()));
63  if (sync_service_)
64    sync_service_->AddObserver(this);
65  profile_pref_registrar_.Init(Profile::FromWebUI(web_ui())->GetPrefs());
66  profile_pref_registrar_.Add(
67      prefs::kSigninAllowed,
68      base::Bind(&NewTabPageSyncHandler::OnSigninAllowedPrefChange,
69                 base::Unretained(this)));
70
71  web_ui()->RegisterMessageCallback("GetSyncMessage",
72      base::Bind(&NewTabPageSyncHandler::HandleGetSyncMessage,
73                 base::Unretained(this)));
74  web_ui()->RegisterMessageCallback("SyncLinkClicked",
75      base::Bind(&NewTabPageSyncHandler::HandleSyncLinkClicked,
76                 base::Unretained(this)));
77}
78
79void NewTabPageSyncHandler::HandleGetSyncMessage(const base::ListValue* args) {
80  waiting_for_initial_page_load_ = false;
81  BuildAndSendSyncStatus();
82}
83
84void NewTabPageSyncHandler::HideSyncStatusSection() {
85  SendSyncMessageToPage(HIDE, std::string(), std::string());
86}
87
88void NewTabPageSyncHandler::BuildAndSendSyncStatus() {
89  DCHECK(!waiting_for_initial_page_load_);
90  SigninManagerBase* signin = SigninManagerFactory::GetForProfile(
91      Profile::FromWebUI(web_ui()));
92
93  // Hide the sync status section if sync is managed or disabled entirely.
94  if (!sync_service_ ||
95      sync_service_->IsManaged() ||
96      !signin ||
97      !signin->IsSigninAllowed()) {
98    HideSyncStatusSection();
99    return;
100  }
101
102  // Don't show sync status if setup is not complete.
103  if (!sync_service_->HasSyncSetupCompleted()) {
104    return;
105  }
106
107  // Once sync has been enabled, the supported "sync statuses" for the NNTP
108  // from the user's perspective are:
109  //
110  // "Sync error", when we can't authenticate or establish a connection with
111  //               the sync server (appropriate information appended to
112  //               message).
113  base::string16 status_msg;
114  base::string16 link_text;
115
116  sync_ui_util::MessageType type =
117      sync_ui_util::GetStatusLabelsForNewTabPage(sync_service_,
118                                                 *signin,
119                                                 &status_msg,
120                                                 &link_text);
121  SendSyncMessageToPage(FromSyncStatusMessageType(type),
122                        base::UTF16ToUTF8(status_msg),
123                        base::UTF16ToUTF8(link_text));
124}
125
126void NewTabPageSyncHandler::HandleSyncLinkClicked(const base::ListValue* args) {
127  DCHECK(!waiting_for_initial_page_load_);
128  if (!sync_service_ || !sync_service_->IsSyncEnabled())
129    return;
130  Browser* browser =
131      chrome::FindBrowserWithWebContents(web_ui()->GetWebContents());
132  if (!browser || browser->IsAttemptingToCloseBrowser())
133    return;
134  chrome::ShowBrowserSignin(browser, signin::SOURCE_NTP_LINK);
135
136  if (sync_service_->HasSyncSetupCompleted()) {
137    base::string16 user = base::UTF8ToUTF16(SigninManagerFactory::GetForProfile(
138        Profile::FromWebUI(web_ui()))->GetAuthenticatedUsername());
139    base::DictionaryValue value;
140    value.SetString("syncEnabledMessage",
141                    l10n_util::GetStringFUTF16(IDS_SYNC_NTP_SYNCED_TO,
142                    user));
143    web_ui()->CallJavascriptFunction("ntp.syncAlreadyEnabled", value);
144  } else {
145    ProfileSyncService::SyncEvent(ProfileSyncService::START_FROM_NTP);
146  }
147}
148
149void NewTabPageSyncHandler::OnStateChanged() {
150  // Don't do anything if the page has not yet loaded.
151  if (waiting_for_initial_page_load_)
152    return;
153  BuildAndSendSyncStatus();
154}
155
156void NewTabPageSyncHandler::OnSigninAllowedPrefChange() {
157  // Don't do anything if the page has not yet loaded.
158  if (waiting_for_initial_page_load_)
159    return;
160  BuildAndSendSyncStatus();
161}
162
163void NewTabPageSyncHandler::SendSyncMessageToPage(
164    MessageType type, std::string msg,
165    std::string linktext) {
166  base::DictionaryValue value;
167  std::string user;
168  std::string title;
169  std::string linkurl;
170
171  // If there is nothing to show, we should hide the sync section altogether.
172  if (type == HIDE || (msg.empty() && linktext.empty())) {
173    value.SetBoolean("syncsectionisvisible", false);
174  } else {
175    if (type == SYNC_ERROR)
176      title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_ERROR_TITLE);
177    else if (type == SYNC_PROMO)
178      title = l10n_util::GetStringUTF8(IDS_SYNC_NTP_SYNC_SECTION_PROMO_TITLE);
179    else
180      NOTREACHED();
181
182    value.SetBoolean("syncsectionisvisible", true);
183    value.SetString("msg", msg);
184    value.SetString("title", title);
185    if (linktext.empty()) {
186      value.SetBoolean("linkisvisible", false);
187    } else {
188      value.SetBoolean("linkisvisible", true);
189      value.SetString("linktext", linktext);
190
191      // The only time we set the URL is when the user is synced and we need to
192      // show a link to a web interface (e.g. http://docs.google.com). When we
193      // set that URL, HandleSyncLinkClicked won't be called when the user
194      // clicks on the link.
195      if (linkurl.empty()) {
196        value.SetBoolean("linkurlisset", false);
197      } else {
198        value.SetBoolean("linkurlisset", true);
199        value.SetString("linkurl", linkurl);
200      }
201    }
202  }
203  web_ui()->CallJavascriptFunction("ntp.syncMessageChanged", value);
204}
205