OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2010 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 "app/gfx/font_util.h" |
| 8 #include "base/json/json_writer.h" |
| 9 #include "base/singleton.h" |
| 10 #include "base/string_util.h" |
| 11 #include "base/utf_string_conversions.h" |
| 12 #include "base/values.h" |
| 13 #include "chrome/browser/browser.h" |
| 14 #include "chrome/browser/browser_list.h" |
| 15 #include "chrome/browser/dom_ui/chrome_url_data_manager.h" |
| 16 #include "chrome/browser/dom_ui/dom_ui_util.h" |
| 17 #include "chrome/browser/platform_util.h" |
| 18 #include "chrome/browser/prefs/pref_service.h" |
| 19 #include "chrome/browser/printing/cloud_print/cloud_print_setup_message_handler.
h" |
| 20 #include "chrome/browser/profile.h" |
| 21 #include "chrome/browser/remoting/remoting_resources_source.h" |
| 22 #include "chrome/browser/renderer_host/render_view_host.h" |
| 23 #include "chrome/browser/service/service_process_control.h" |
| 24 #include "chrome/browser/service/service_process_control_manager.h" |
| 25 #include "chrome/browser/tab_contents/tab_contents.h" |
| 26 #include "chrome/common/net/gaia/gaia_authenticator2.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 "chrome/common/service_process_type.h" |
| 32 #include "gfx/font.h" |
| 33 #include "grit/locale_settings.h" |
| 34 |
| 35 static const wchar_t kLoginIFrameXPath[] = L"//iframe[@id='login']"; |
| 36 static const wchar_t kDoneIframeXPath[] = L"//iframe[@id='done']"; |
| 37 |
| 38 //////////////////////////////////////////////////////////////////////////////// |
| 39 // CloudPrintServiceProcessHelper |
| 40 // |
| 41 // This is a helper class to perform actions when the service process |
| 42 // is connected or launched. The events are sent back to CloudPrintSetupFlow |
| 43 // when the dialog is still active. CloudPrintSetupFlow can detach from this |
| 44 // helper class when the dialog is closed. |
| 45 |
| 46 class CloudPrintServiceProcessHelper |
| 47 : public base::RefCountedThreadSafe<CloudPrintServiceProcessHelper> { |
| 48 public: |
| 49 explicit CloudPrintServiceProcessHelper(CloudPrintSetupFlow* flow) |
| 50 : flow_(flow) { |
| 51 } |
| 52 |
| 53 void Detach() { |
| 54 flow_ = NULL; |
| 55 } |
| 56 |
| 57 void OnProcessLaunched() { |
| 58 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 59 // If the flow is detached then show the done page. |
| 60 if (!flow_) |
| 61 return; |
| 62 |
| 63 flow_->OnProcessLaunched(); |
| 64 } |
| 65 |
| 66 private: |
| 67 CloudPrintSetupFlow* flow_; |
| 68 |
| 69 DISALLOW_COPY_AND_ASSIGN(CloudPrintServiceProcessHelper); |
| 70 }; |
| 71 |
| 72 //////////////////////////////////////////////////////////////////////////////// |
| 73 // CloudPrintServiceDisableTask |
| 74 // |
| 75 // This is a helper class to get the proxy service launched if it |
| 76 // isn't, in order to properly inform it that it should be disabled. |
| 77 |
| 78 class CloudPrintServiceDisableTask |
| 79 : public base::RefCountedThreadSafe<CloudPrintServiceDisableTask> { |
| 80 public: |
| 81 explicit CloudPrintServiceDisableTask(Profile* profile) |
| 82 : profile_(profile), |
| 83 process_control_(NULL) { |
| 84 } |
| 85 |
| 86 void StartDisable() { |
| 87 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 88 |
| 89 process_control_ = |
| 90 ServiceProcessControlManager::instance()->GetProcessControl( |
| 91 profile_, |
| 92 kServiceProcessCloudPrint); |
| 93 |
| 94 if (process_control_) { |
| 95 // If the process isn't connected, launch it now. This will run |
| 96 // the task whether the process is already launched or not, as |
| 97 // long as it's able to connect back up. |
| 98 process_control_->Launch( |
| 99 NewRunnableMethod( |
| 100 this, &CloudPrintServiceDisableTask::OnProcessLaunched)); |
| 101 } |
| 102 } |
| 103 |
| 104 void OnProcessLaunched() { |
| 105 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 106 DCHECK(process_control_); |
| 107 if (process_control_->is_connected()) |
| 108 process_control_->Send(new ServiceMsg_DisableCloudPrintProxy()); |
| 109 profile_->GetPrefs()->SetString(prefs::kCloudPrintEmail, std::string()); |
| 110 } |
| 111 |
| 112 private: |
| 113 Profile* profile_; |
| 114 ServiceProcessControl* process_control_; |
| 115 |
| 116 DISALLOW_COPY_AND_ASSIGN(CloudPrintServiceDisableTask); |
| 117 }; |
| 118 |
| 119 //////////////////////////////////////////////////////////////////////////////// |
| 120 // CloudPrintServiceRefreshTask |
| 121 // |
| 122 // This is a helper class to perform a preferences refresh of the |
| 123 // enablement state and registered e-mail from the cloud print proxy |
| 124 // service. |
| 125 |
| 126 class CloudPrintServiceRefreshTask |
| 127 : public base::RefCountedThreadSafe<CloudPrintServiceRefreshTask> { |
| 128 public: |
| 129 explicit CloudPrintServiceRefreshTask( |
| 130 Profile* profile, |
| 131 Callback2<bool, std::string>::Type* callback) |
| 132 : profile_(profile), |
| 133 process_control_(NULL), |
| 134 callback_(callback) { |
| 135 DCHECK(callback); |
| 136 } |
| 137 |
| 138 void StartRefresh() { |
| 139 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 140 |
| 141 process_control_ = |
| 142 ServiceProcessControlManager::instance()->GetProcessControl( |
| 143 profile_, |
| 144 kServiceProcessCloudPrint); |
| 145 |
| 146 if (process_control_) { |
| 147 // If the process isn't connected, launch it now. This will run |
| 148 // the task whether the process is already launched or not, as |
| 149 // long as it's able to connect back up. |
| 150 process_control_->Launch( |
| 151 NewRunnableMethod( |
| 152 this, &CloudPrintServiceRefreshTask::OnProcessLaunched)); |
| 153 } |
| 154 } |
| 155 |
| 156 void OnProcessLaunched() { |
| 157 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| 158 DCHECK(process_control_); |
| 159 |
| 160 if (callback_ != NULL) |
| 161 process_control_->GetCloudPrintProxyStatus(callback_.release()); |
| 162 } |
| 163 |
| 164 private: |
| 165 Profile* profile_; |
| 166 ServiceProcessControl* process_control_; |
| 167 |
| 168 // Callback that gets invoked when a status message is received from |
| 169 // the cloud print proxy. |
| 170 scoped_ptr<Callback2<bool, std::string>::Type> callback_; |
| 171 |
| 172 DISALLOW_COPY_AND_ASSIGN(CloudPrintServiceRefreshTask); |
| 173 }; |
| 174 |
| 175 //////////////////////////////////////////////////////////////////////////////// |
| 176 // CloudPrintSetupFlow implementation. |
| 177 |
| 178 // static |
| 179 CloudPrintSetupFlow* CloudPrintSetupFlow::OpenDialog(Profile* profile) { |
| 180 // Set the arguments for showing the gaia login page. |
| 181 DictionaryValue args; |
| 182 args.SetString("iframeToShow", "login"); |
| 183 args.SetString("user", ""); |
| 184 args.SetInteger("error", 0); |
| 185 args.SetBoolean("editable_user", true); |
| 186 |
| 187 if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) && |
| 188 !profile->GetPrefs()->GetString(prefs::kCloudPrintEmail).empty()) { |
| 189 args.SetString("iframeToShow", "done"); |
| 190 } |
| 191 |
| 192 std::string json_args; |
| 193 base::JSONWriter::Write(&args, false, &json_args); |
| 194 |
| 195 // Create a browser to run the dialog. The new CloudPrintSetupFlow |
| 196 // class takes ownership. |
| 197 Browser* browser = Browser::CreateForPopup(profile); |
| 198 DCHECK(browser); |
| 199 |
| 200 CloudPrintSetupFlow* flow = new CloudPrintSetupFlow(json_args, browser); |
| 201 browser->BrowserShowHtmlDialog(flow, NULL); |
| 202 return flow; |
| 203 } |
| 204 |
| 205 // static |
| 206 void CloudPrintSetupFlow::DisableCloudPrintProxy(Profile* profile) { |
| 207 scoped_refptr<CloudPrintServiceDisableTask> refresh_task = |
| 208 new CloudPrintServiceDisableTask(profile); |
| 209 ChromeThread::PostTask( |
| 210 ChromeThread::UI, FROM_HERE, |
| 211 NewRunnableMethod(refresh_task.get(), |
| 212 &CloudPrintServiceDisableTask::StartDisable)); |
| 213 } |
| 214 |
| 215 // static |
| 216 void CloudPrintSetupFlow::RefreshPreferencesFromService( |
| 217 Profile* profile, |
| 218 Callback2<bool, std::string>::Type* callback) { |
| 219 scoped_refptr<CloudPrintServiceRefreshTask> refresh_task = |
| 220 new CloudPrintServiceRefreshTask(profile, callback); |
| 221 ChromeThread::PostTask( |
| 222 ChromeThread::UI, FROM_HERE, |
| 223 NewRunnableMethod(refresh_task.get(), |
| 224 &CloudPrintServiceRefreshTask::StartRefresh)); |
| 225 } |
| 226 |
| 227 CloudPrintSetupFlow::CloudPrintSetupFlow(const std::string& args, |
| 228 Browser* browser) |
| 229 : dom_ui_(NULL), |
| 230 dialog_start_args_(args), |
| 231 process_control_(NULL) { |
| 232 // TODO(hclam): The data source should be added once. |
| 233 browser_.reset(browser); |
| 234 ChromeThread::PostTask( |
| 235 ChromeThread::IO, FROM_HERE, |
| 236 NewRunnableMethod(Singleton<ChromeURLDataManager>::get(), |
| 237 &ChromeURLDataManager::AddDataSource, |
| 238 make_scoped_refptr(new RemotingResourcesSource()))); |
| 239 } |
| 240 |
| 241 CloudPrintSetupFlow::~CloudPrintSetupFlow() { |
| 242 } |
| 243 |
| 244 void CloudPrintSetupFlow::Focus() { |
| 245 // TODO(pranavk): implement this method. |
| 246 NOTIMPLEMENTED(); |
| 247 } |
| 248 |
| 249 /////////////////////////////////////////////////////////////////////////////// |
| 250 // HtmlDialogUIDelegate implementation. |
| 251 GURL CloudPrintSetupFlow::GetDialogContentURL() const { |
| 252 return GURL("chrome://remotingresources/setup"); |
| 253 } |
| 254 |
| 255 void CloudPrintSetupFlow::GetDOMMessageHandlers( |
| 256 std::vector<DOMMessageHandler*>* handlers) const { |
| 257 // Create the message handler only after we are asked, the caller is |
| 258 // responsible for deleting the objects. |
| 259 handlers->push_back( |
| 260 new CloudPrintSetupMessageHandler( |
| 261 const_cast<CloudPrintSetupFlow*>(this))); |
| 262 } |
| 263 |
| 264 void CloudPrintSetupFlow::GetDialogSize(gfx::Size* size) const { |
| 265 PrefService* prefs = browser_->profile()->GetPrefs(); |
| 266 gfx::Font approximate_web_font( |
| 267 UTF8ToWide(prefs->GetString(prefs::kWebKitSansSerifFontFamily)), |
| 268 prefs->GetInteger(prefs::kWebKitDefaultFontSize)); |
| 269 |
| 270 // TODO(pranavk) Replace the following SYNC resources with REMOTING Resources. |
| 271 *size = gfx::GetLocalizedContentsSizeForFont( |
| 272 IDS_SYNC_SETUP_WIZARD_WIDTH_CHARS, |
| 273 IDS_SYNC_SETUP_WIZARD_HEIGHT_LINES, |
| 274 approximate_web_font); |
| 275 } |
| 276 |
| 277 // A callback to notify the delegate that the dialog closed. |
| 278 void CloudPrintSetupFlow::OnDialogClosed(const std::string& json_retval) { |
| 279 // If we are fetching the token then cancel the request. |
| 280 if (authenticator_.get()) |
| 281 authenticator_->CancelRequest(); |
| 282 |
| 283 // If the service process helper is still active then detach outself from it. |
| 284 // This is because the dialog is closing and this object is going to be |
| 285 // deleted but the service process launch is still in progress so we don't |
| 286 // the service process helper to call us when the process is launched. |
| 287 if (service_process_helper_.get()) |
| 288 service_process_helper_->Detach(); |
| 289 delete this; |
| 290 } |
| 291 |
| 292 std::string CloudPrintSetupFlow::GetDialogArgs() const { |
| 293 return dialog_start_args_; |
| 294 } |
| 295 |
| 296 void CloudPrintSetupFlow::OnCloseContents(TabContents* source, |
| 297 bool* out_close_dialog) { |
| 298 } |
| 299 |
| 300 std::wstring CloudPrintSetupFlow::GetDialogTitle() const { |
| 301 return l10n_util::GetString(IDS_CLOUD_PRINT_SETUP_DIALOG_TITLE); |
| 302 } |
| 303 |
| 304 bool CloudPrintSetupFlow::IsDialogModal() const { |
| 305 return true; |
| 306 } |
| 307 |
| 308 /////////////////////////////////////////////////////////////////////////////// |
| 309 // GaiaAuthConsumer implementation. |
| 310 void CloudPrintSetupFlow::OnClientLoginFailure( |
| 311 const GoogleServiceAuthError& error) { |
| 312 ShowGaiaFailed(error); |
| 313 authenticator_.reset(); |
| 314 } |
| 315 |
| 316 void CloudPrintSetupFlow::OnClientLoginSuccess( |
| 317 const GaiaAuthConsumer::ClientLoginResult& credentials) { |
| 318 // Save the token for the cloud print proxy. |
| 319 lsid_ = credentials.lsid; |
| 320 |
| 321 // Show that Gaia login has succeeded. |
| 322 ShowGaiaSuccessAndSettingUp(); |
| 323 authenticator_.reset(); |
| 324 |
| 325 // And then launch the service process if it has not started yet. |
| 326 // If we have already connected to the service process then submit the tokens |
| 327 // to it to register the host. |
| 328 process_control_ = |
| 329 ServiceProcessControlManager::instance()->GetProcessControl( |
| 330 browser_->profile(), |
| 331 kServiceProcessCloudPrint); |
| 332 |
| 333 #if defined(OS_WIN) |
| 334 // TODO(hclam): This call only works on Windows. I need to make it |
| 335 // work on other platforms. |
| 336 service_process_helper_ = new CloudPrintServiceProcessHelper(this); |
| 337 |
| 338 // If the process isn't connected, launch it now. This will run the |
| 339 // task whether the process is already launched or not, as long as |
| 340 // it's able to connect back up. |
| 341 process_control_->Launch( |
| 342 NewRunnableMethod(service_process_helper_.get(), |
| 343 &CloudPrintServiceProcessHelper::OnProcessLaunched)); |
| 344 #else |
| 345 ShowSetupDone(); |
| 346 #endif |
| 347 } |
| 348 |
| 349 /////////////////////////////////////////////////////////////////////////////// |
| 350 // Methods called by CloudPrintSetupMessageHandler |
| 351 void CloudPrintSetupFlow::Attach(DOMUI* dom_ui) { |
| 352 dom_ui_ = dom_ui; |
| 353 } |
| 354 |
| 355 void CloudPrintSetupFlow::OnUserSubmittedAuth(const std::string& user, |
| 356 const std::string& password, |
| 357 const std::string& captcha) { |
| 358 // Save the login name only. |
| 359 login_ = user; |
| 360 |
| 361 // Start the authenticator. |
| 362 authenticator_.reset( |
| 363 new GaiaAuthenticator2(this, GaiaConstants::kChromeSource, |
| 364 browser_->profile()->GetRequestContext())); |
| 365 authenticator_->StartClientLogin(user, password, |
| 366 GaiaConstants::kCloudPrintService, |
| 367 "", captcha); |
| 368 } |
| 369 |
| 370 /////////////////////////////////////////////////////////////////////////////// |
| 371 // Method called by CloudPrintServiceProcessHelper |
| 372 void CloudPrintSetupFlow::OnProcessLaunched() { |
| 373 DCHECK(process_control_->is_connected()); |
| 374 // TODO(scottbyer): Need to wait for an ACK to be sure that it is |
| 375 // actually active. |
| 376 if (!lsid_.empty()) |
| 377 process_control_->Send(new ServiceMsg_EnableCloudPrintProxy(lsid_)); |
| 378 |
| 379 // Save the preference that we have completed the setup of cloud |
| 380 // print. |
| 381 browser_->profile()->GetPrefs()->SetString(prefs::kCloudPrintEmail, login_); |
| 382 ShowSetupDone(); |
| 383 } |
| 384 |
| 385 /////////////////////////////////////////////////////////////////////////////// |
| 386 // Helper methods for showing contents of the DOM UI |
| 387 void CloudPrintSetupFlow::ShowGaiaLogin(const DictionaryValue& args) { |
| 388 if (dom_ui_) |
| 389 dom_ui_->CallJavascriptFunction(L"showGaiaLoginIframe"); |
| 390 |
| 391 std::string json; |
| 392 base::JSONWriter::Write(&args, false, &json); |
| 393 std::wstring javascript = std::wstring(L"showGaiaLogin") + |
| 394 L"(" + UTF8ToWide(json) + L");"; |
| 395 ExecuteJavascriptInIFrame(kLoginIFrameXPath, javascript); |
| 396 } |
| 397 |
| 398 void CloudPrintSetupFlow::ShowGaiaSuccessAndSettingUp() { |
| 399 ExecuteJavascriptInIFrame(kLoginIFrameXPath, |
| 400 L"showGaiaSuccessAndSettingUp();"); |
| 401 } |
| 402 |
| 403 void CloudPrintSetupFlow::ShowGaiaFailed(const GoogleServiceAuthError& error) { |
| 404 DictionaryValue args; |
| 405 args.SetString("iframeToShow", "login"); |
| 406 args.SetString("user", ""); |
| 407 args.SetInteger("error", error.state()); |
| 408 args.SetBoolean("editable_user", true); |
| 409 args.SetString("captchaUrl", error.captcha().image_url.spec()); |
| 410 ShowGaiaLogin(args); |
| 411 } |
| 412 |
| 413 void CloudPrintSetupFlow::ShowSetupDone() { |
| 414 std::wstring javascript = L"setMessage('You are all set!');"; |
| 415 ExecuteJavascriptInIFrame(kDoneIframeXPath, javascript); |
| 416 |
| 417 if (dom_ui_) |
| 418 dom_ui_->CallJavascriptFunction(L"showSetupDone"); |
| 419 |
| 420 ExecuteJavascriptInIFrame(kDoneIframeXPath, L"onPageShown();"); |
| 421 } |
| 422 |
| 423 void CloudPrintSetupFlow::ExecuteJavascriptInIFrame( |
| 424 const std::wstring& iframe_xpath, |
| 425 const std::wstring& js) { |
| 426 if (dom_ui_) { |
| 427 RenderViewHost* rvh = dom_ui_->tab_contents()->render_view_host(); |
| 428 rvh->ExecuteJavascriptInWebFrame(iframe_xpath, js); |
| 429 } |
| 430 } |
OLD | NEW |