• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2011 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/printing/cloud_print/cloud_print_setup_flow.h"
6 
7 #include "base/json/json_writer.h"
8 #include "base/memory/singleton.h"
9 #include "base/string_util.h"
10 #include "base/utf_string_conversions.h"
11 #include "base/values.h"
12 #include "chrome/browser/platform_util.h"
13 #include "chrome/browser/prefs/pref_service.h"
14 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
15 #include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.h"
16 #include "chrome/browser/printing/cloud_print/cloud_print_setup_source.h"
17 #include "chrome/browser/printing/cloud_print/cloud_print_url.h"
18 #include "chrome/browser/profiles/profile.h"
19 #include "chrome/browser/service/service_process_control.h"
20 #include "chrome/browser/service/service_process_control_manager.h"
21 #include "chrome/browser/ui/browser.h"
22 #include "chrome/browser/ui/browser_dialogs.h"
23 #include "chrome/browser/ui/browser_list.h"
24 #include "chrome/browser/ui/browser_window.h"
25 #include "chrome/browser/ui/webui/chrome_url_data_manager.h"
26 #include "chrome/common/net/gaia/gaia_auth_fetcher.h"
27 #include "chrome/common/net/gaia/gaia_constants.h"
28 #include "chrome/common/net/gaia/google_service_auth_error.h"
29 #include "chrome/common/pref_names.h"
30 #include "chrome/common/service_messages.h"
31 #include "content/browser/browser_thread.h"
32 #include "content/browser/renderer_host/render_view_host.h"
33 #include "content/browser/tab_contents/tab_contents.h"
34 #include "grit/chromium_strings.h"
35 #include "grit/locale_settings.h"
36 #include "ui/base/l10n/l10n_font_util.h"
37 #include "ui/gfx/font.h"
38 
39 namespace {
40 
SetupIframeXPath()41 string16& SetupIframeXPath() {
42   static string16 kSetupIframeXPath =
43       ASCIIToUTF16("//iframe[@id='cloudprintsetup']");
44   return kSetupIframeXPath;
45 }
46 
DoneIframeXPath()47 string16& DoneIframeXPath() {
48   static string16 kDoneIframeXPath =
49       ASCIIToUTF16("//iframe[@id='setupdone']");
50   return kDoneIframeXPath;
51 }
52 
53 }  // end namespace
54 
55 ////////////////////////////////////////////////////////////////////////////////
56 // CloudPrintSetupFlow implementation.
57 
58 // static
OpenDialog(Profile * profile,const base::WeakPtr<Delegate> & delegate,gfx::NativeWindow parent_window)59 CloudPrintSetupFlow* CloudPrintSetupFlow::OpenDialog(
60     Profile* profile,
61     const base::WeakPtr<Delegate>& delegate,
62     gfx::NativeWindow parent_window) {
63   DCHECK(profile);
64   // Set the arguments for showing the gaia login page.
65   DictionaryValue args;
66   args.SetString("user", "");
67   args.SetInteger("error", 0);
68   args.SetBoolean("editable_user", true);
69 
70   bool setup_done = false;
71   if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
72       !profile->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty())
73     setup_done = true;
74   args.SetString("pageToShow", setup_done ? "setupdone" : "cloudprintsetup");
75 
76   std::string json_args;
77   base::JSONWriter::Write(&args, false, &json_args);
78 
79   CloudPrintSetupFlow* flow = new CloudPrintSetupFlow(json_args, profile,
80                                                       delegate, setup_done);
81   // We may not always have a browser. This can happen when we are being
82   // invoked in the context of a "token expired" notfication. If we don't have
83   // a brower, use the underlying dialog system to show the dialog without
84   // using a browser.
85   if (!parent_window) {
86     Browser* browser = BrowserList::GetLastActive();
87     if (browser && browser->window())
88       parent_window = browser->window()->GetNativeHandle();
89   }
90   browser::ShowHtmlDialog(parent_window, profile, flow);
91   return flow;
92 }
93 
CloudPrintSetupFlow(const std::string & args,Profile * profile,const base::WeakPtr<Delegate> & delegate,bool setup_done)94 CloudPrintSetupFlow::CloudPrintSetupFlow(
95     const std::string& args,
96     Profile* profile,
97     const base::WeakPtr<Delegate>& delegate,
98     bool setup_done)
99     : web_ui_(NULL),
100       dialog_start_args_(args),
101       last_auth_error_(GoogleServiceAuthError::None()),
102       setup_done_(setup_done),
103       process_control_(NULL),
104       delegate_(delegate) {
105   // TODO(hclam): The data source should be added once.
106   profile_ = profile;
107   profile->GetChromeURLDataManager()->AddDataSource(
108       new CloudPrintSetupSource());
109 }
110 
~CloudPrintSetupFlow()111 CloudPrintSetupFlow::~CloudPrintSetupFlow() {
112 }
113 
Focus()114 void CloudPrintSetupFlow::Focus() {
115   // TODO(pranavk): implement this method.
116   NOTIMPLEMENTED();
117 }
118 
119 ///////////////////////////////////////////////////////////////////////////////
120 // HtmlDialogUIDelegate implementation.
GetDialogContentURL() const121 GURL CloudPrintSetupFlow::GetDialogContentURL() const {
122   return GURL("chrome://cloudprintsetup/setupflow");
123 }
124 
GetWebUIMessageHandlers(std::vector<WebUIMessageHandler * > * handlers) const125 void CloudPrintSetupFlow::GetWebUIMessageHandlers(
126     std::vector<WebUIMessageHandler*>* handlers) const {
127   // Create the message handler only after we are asked, the caller is
128   // responsible for deleting the objects.
129   handlers->push_back(
130       new CloudPrintSetupMessageHandler(
131           const_cast<CloudPrintSetupFlow*>(this)));
132 }
133 
GetDialogSize(gfx::Size * size) const134 void CloudPrintSetupFlow::GetDialogSize(gfx::Size* size) const {
135   PrefService* prefs = profile_->GetPrefs();
136   gfx::Font approximate_web_font(
137       UTF8ToUTF16(prefs->GetString(prefs::kWebKitSansSerifFontFamily)),
138       prefs->GetInteger(prefs::kWebKitDefaultFontSize));
139 
140   if (setup_done_) {
141     *size = ui::GetLocalizedContentsSizeForFont(
142         IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS,
143         IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES,
144         approximate_web_font);
145   } else {
146     *size = ui::GetLocalizedContentsSizeForFont(
147         IDS_CLOUD_PRINT_SETUP_WIZARD_WIDTH_CHARS,
148         IDS_CLOUD_PRINT_SETUP_WIZARD_HEIGHT_LINES,
149         approximate_web_font);
150   }
151 
152 #if !defined(OS_WIN)
153   // NOTE(scottbyer):The following comment comes from
154   // SyncSetupFlow::GetDialogSize, where this hack was copied from. By starting
155   // off development of the UI on Windows, the hack is seemingly backwards.
156 
157   // NOTE(akalin): This is a hack to work around a problem with font height on
158   // windows.  Basically font metrics are incorrectly returned in logical units
159   // instead of pixels on Windows.  Logical units are very commonly 96 DPI
160   // so our localized char/line counts are too small by a factor of 96/72.
161   // So we compensate for this on non-windows platform.
162 
163   // TODO(scottbyer): Fix the root cause, kill the hacks.
164   float scale_hack = 96.f/72.f;
165   size->set_width(size->width() * scale_hack);
166   size->set_height(size->height() * scale_hack);
167 #endif
168 }
169 
170 // A callback to notify the delegate that the dialog closed.
OnDialogClosed(const std::string & json_retval)171 void CloudPrintSetupFlow::OnDialogClosed(const std::string& json_retval) {
172   // If we are fetching the token then cancel the request.
173   if (authenticator_.get())
174     authenticator_->CancelRequest();
175 
176   if (delegate_)
177     delegate_->OnDialogClosed();
178   delete this;
179 }
180 
GetDialogArgs() const181 std::string CloudPrintSetupFlow::GetDialogArgs() const {
182   return dialog_start_args_;
183 }
184 
OnCloseContents(TabContents * source,bool * out_close_dialog)185 void CloudPrintSetupFlow::OnCloseContents(TabContents* source,
186                                           bool* out_close_dialog) {
187 }
188 
GetDialogTitle() const189 std::wstring CloudPrintSetupFlow::GetDialogTitle() const {
190   return UTF16ToWideHack(
191       l10n_util::GetStringUTF16(IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE));
192 }
193 
IsDialogModal() const194 bool CloudPrintSetupFlow::IsDialogModal() const {
195   // We are always modeless.
196   return false;
197 }
198 
ShouldShowDialogTitle() const199 bool CloudPrintSetupFlow::ShouldShowDialogTitle() const {
200   return true;
201 }
202 
203 ///////////////////////////////////////////////////////////////////////////////
204 // GaiaAuthConsumer implementation.
OnClientLoginSuccess(const GaiaAuthConsumer::ClientLoginResult & credentials)205 void CloudPrintSetupFlow::OnClientLoginSuccess(
206     const GaiaAuthConsumer::ClientLoginResult& credentials) {
207   // Save the token for the cloud print proxy.
208   lsid_ = credentials.lsid;
209 
210   // Show that Gaia login has succeeded.
211   ShowGaiaSuccessAndSettingUp();
212   authenticator_.reset();
213 
214   profile_->GetCloudPrintProxyService()->EnableForUser(credentials.lsid,
215                                                        login_);
216   // TODO(sanjeevr): Should we wait and verify that the enable succeeded?
217   ShowSetupDone();
218 }
219 
OnClientLoginFailure(const GoogleServiceAuthError & error)220 void CloudPrintSetupFlow::OnClientLoginFailure(
221     const GoogleServiceAuthError& error) {
222   last_auth_error_ = error;
223   ShowGaiaFailed(error);
224   authenticator_.reset();
225 }
226 
227 ///////////////////////////////////////////////////////////////////////////////
228 // Methods called by CloudPrintSetupMessageHandler
Attach(WebUI * web_ui)229 void CloudPrintSetupFlow::Attach(WebUI* web_ui) {
230   web_ui_ = web_ui;
231 }
232 
OnUserSubmittedAuth(const std::string & user,const std::string & password,const std::string & captcha,const std::string & access_code)233 void CloudPrintSetupFlow::OnUserSubmittedAuth(const std::string& user,
234                                               const std::string& password,
235                                               const std::string& captcha,
236                                               const std::string& access_code) {
237   // Save the login name only.
238   login_ = user;
239 
240   // Start the authenticator.
241   authenticator_.reset(
242       new GaiaAuthFetcher(this, GaiaConstants::kChromeSource,
243                           profile_->GetRequestContext()));
244 
245   if (!access_code.empty()) {
246     authenticator_->StartClientLogin(user, access_code,
247                                      GaiaConstants::kCloudPrintService,
248                                      std::string(), std::string(),
249                                      GaiaAuthFetcher::HostedAccountsAllowed);
250   } else {
251     authenticator_->StartClientLogin(user, password,
252                                      GaiaConstants::kCloudPrintService,
253                                      last_auth_error_.captcha().token, captcha,
254                                      GaiaAuthFetcher::HostedAccountsAllowed);
255   }
256 }
257 
OnUserClickedLearnMore()258 void CloudPrintSetupFlow::OnUserClickedLearnMore() {
259   web_ui_->tab_contents()->OpenURL(CloudPrintURL::GetCloudPrintLearnMoreURL(),
260                                    GURL(), NEW_FOREGROUND_TAB,
261                                    PageTransition::LINK);
262 }
263 
OnUserClickedPrintTestPage()264 void CloudPrintSetupFlow::OnUserClickedPrintTestPage() {
265   web_ui_->tab_contents()->OpenURL(CloudPrintURL::GetCloudPrintTestPageURL(),
266                                    GURL(), NEW_FOREGROUND_TAB,
267                                    PageTransition::LINK);
268 }
269 
270 ///////////////////////////////////////////////////////////////////////////////
271 // Helper methods for showing contents of the Web UI
ShowGaiaLogin(const DictionaryValue & args)272 void CloudPrintSetupFlow::ShowGaiaLogin(const DictionaryValue& args) {
273   if (web_ui_)
274     web_ui_->CallJavascriptFunction("cloudprint.showSetupLogin");
275 
276   std::string json;
277   base::JSONWriter::Write(&args, false, &json);
278   string16 javascript = UTF8ToUTF16("cloudprint.showGaiaLogin(" + json + ");");
279 
280   ExecuteJavascriptInIFrame(SetupIframeXPath(), javascript);
281 }
282 
ShowGaiaSuccessAndSettingUp()283 void CloudPrintSetupFlow::ShowGaiaSuccessAndSettingUp() {
284   ExecuteJavascriptInIFrame(
285       SetupIframeXPath(),
286       ASCIIToUTF16("cloudprint.showGaiaSuccessAndSettingUp();"));
287 }
288 
ShowGaiaFailed(const GoogleServiceAuthError & error)289 void CloudPrintSetupFlow::ShowGaiaFailed(const GoogleServiceAuthError& error) {
290   DictionaryValue args;
291   args.SetString("pageToShow", "cloudprintsetup");
292   args.SetString("user", login_);
293   args.SetInteger("error", error.state());
294   args.SetBoolean("editable_user", true);
295   args.SetString("captchaUrl", error.captcha().image_url.spec());
296   ShowGaiaLogin(args);
297 }
298 
ShowSetupDone()299 void CloudPrintSetupFlow::ShowSetupDone() {
300   setup_done_ = true;
301   string16 product_name = l10n_util::GetStringUTF16(IDS_PRODUCT_NAME);
302   string16 message = l10n_util::GetStringFUTF16(IDS_CLOUD_PRINT_SETUP_DONE,
303                                                 product_name,
304                                                 UTF8ToUTF16(login_));
305   string16 javascript(ASCIIToUTF16("cloudprint.setMessage('") + message +
306                       ASCIIToUTF16("');"));
307   ExecuteJavascriptInIFrame(DoneIframeXPath(), javascript);
308 
309   if (web_ui_) {
310     PrefService* prefs = profile_->GetPrefs();
311     gfx::Font approximate_web_font(
312         UTF8ToUTF16(prefs->GetString(prefs::kWebKitSansSerifFontFamily)),
313         prefs->GetInteger(prefs::kWebKitDefaultFontSize));
314     gfx::Size done_size = ui::GetLocalizedContentsSizeForFont(
315         IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_WIDTH_CHARS,
316         IDS_CLOUD_PRINT_SETUP_WIZARD_DONE_HEIGHT_LINES,
317         approximate_web_font);
318 
319     FundamentalValue new_width(done_size.width());
320     FundamentalValue new_height(done_size.height());
321     web_ui_->CallJavascriptFunction("cloudprint.showSetupDone",
322                                     new_width, new_height);
323   }
324 
325   ExecuteJavascriptInIFrame(DoneIframeXPath(),
326                             ASCIIToUTF16("cloudprint.onPageShown();"));
327 }
328 
ExecuteJavascriptInIFrame(const string16 & iframe_xpath,const string16 & js)329 void CloudPrintSetupFlow::ExecuteJavascriptInIFrame(
330     const string16& iframe_xpath,
331     const string16& js) {
332   if (web_ui_) {
333     RenderViewHost* rvh = web_ui_->tab_contents()->render_view_host();
334     rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js);
335   }
336 }
337