Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / local_discovery / local_discovery_ui_handler.cc
1 // Copyright 2013 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/local_discovery/local_discovery_ui_handler.h"
6
7 #include <set>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/prefs/pref_service.h"
13 #include "base/strings/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/values.h"
16 #include "chrome/browser/local_discovery/privet_confirm_api_flow.h"
17 #include "chrome/browser/local_discovery/privet_constants.h"
18 #include "chrome/browser/local_discovery/privet_device_lister_impl.h"
19 #include "chrome/browser/local_discovery/privet_http_asynchronous_factory.h"
20 #include "chrome/browser/local_discovery/privet_http_impl.h"
21 #include "chrome/browser/local_discovery/service_discovery_shared_client.h"
22 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service.h"
23 #include "chrome/browser/printing/cloud_print/cloud_print_proxy_service_factory.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
26 #include "chrome/browser/signin/signin_manager_factory.h"
27 #include "chrome/browser/signin/signin_promo.h"
28 #include "chrome/browser/ui/browser_finder.h"
29 #include "chrome/browser/ui/browser_tabstrip.h"
30 #include "chrome/common/chrome_switches.h"
31 #include "chrome/common/pref_names.h"
32 #include "components/cloud_devices/common/cloud_devices_urls.h"
33 #include "components/signin/core/browser/profile_oauth2_token_service.h"
34 #include "components/signin/core/browser/signin_manager_base.h"
35 #include "content/public/browser/user_metrics.h"
36 #include "content/public/browser/web_ui.h"
37 #include "content/public/common/page_transition_types.h"
38 #include "grit/generated_resources.h"
39 #include "net/base/host_port_pair.h"
40 #include "net/base/net_util.h"
41 #include "net/base/url_util.h"
42 #include "net/http/http_status_code.h"
43 #include "ui/base/l10n/l10n_util.h"
44
45 #if defined(ENABLE_FULL_PRINTING) && !defined(OS_CHROMEOS)
46 #define CLOUD_PRINT_CONNECTOR_UI_AVAILABLE
47 #endif
48
49 namespace local_discovery {
50
51 namespace {
52 const char kDeviceTypePrinter[] = "printer";
53 int g_num_visible = 0;
54 }  // namespace
55
56 LocalDiscoveryUIHandler::LocalDiscoveryUIHandler() : is_visible_(false) {
57 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
58 #if !defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
59   // On Windows, we need the PDF plugin which is only guaranteed to exist on
60   // Google Chrome builds. Use a command-line switch for Windows non-Google
61   //  Chrome builds.
62   cloud_print_connector_ui_enabled_ =
63       CommandLine::ForCurrentProcess()->HasSwitch(
64       switches::kEnableCloudPrintProxy);
65 #else
66   // Always enabled for Linux and Google Chrome Windows builds.
67   // Never enabled for Chrome OS, we don't even need to indicate it.
68   cloud_print_connector_ui_enabled_ = true;
69 #endif
70 #endif  // defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
71 }
72
73 LocalDiscoveryUIHandler::~LocalDiscoveryUIHandler() {
74   Profile* profile = Profile::FromWebUI(web_ui());
75   SigninManagerBase* signin_manager =
76       SigninManagerFactory::GetInstance()->GetForProfile(profile);
77   if (signin_manager)
78     signin_manager->RemoveObserver(this);
79   ResetCurrentRegistration();
80   SetIsVisible(false);
81 }
82
83 // static
84 bool LocalDiscoveryUIHandler::GetHasVisible() {
85   return g_num_visible != 0;
86 }
87
88 void LocalDiscoveryUIHandler::RegisterMessages() {
89   web_ui()->RegisterMessageCallback("start", base::Bind(
90       &LocalDiscoveryUIHandler::HandleStart,
91       base::Unretained(this)));
92   web_ui()->RegisterMessageCallback("isVisible", base::Bind(
93       &LocalDiscoveryUIHandler::HandleIsVisible,
94       base::Unretained(this)));
95   web_ui()->RegisterMessageCallback("registerDevice", base::Bind(
96       &LocalDiscoveryUIHandler::HandleRegisterDevice,
97       base::Unretained(this)));
98   web_ui()->RegisterMessageCallback("cancelRegistration", base::Bind(
99       &LocalDiscoveryUIHandler::HandleCancelRegistration,
100       base::Unretained(this)));
101   web_ui()->RegisterMessageCallback("requestPrinterList", base::Bind(
102       &LocalDiscoveryUIHandler::HandleRequestPrinterList,
103       base::Unretained(this)));
104   web_ui()->RegisterMessageCallback("openCloudPrintURL", base::Bind(
105       &LocalDiscoveryUIHandler::HandleOpenCloudPrintURL,
106       base::Unretained(this)));
107   web_ui()->RegisterMessageCallback("showSyncUI", base::Bind(
108       &LocalDiscoveryUIHandler::HandleShowSyncUI,
109       base::Unretained(this)));
110
111   // Cloud print connector related messages
112 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
113   if (cloud_print_connector_ui_enabled_) {
114     web_ui()->RegisterMessageCallback(
115         "showCloudPrintSetupDialog",
116         base::Bind(&LocalDiscoveryUIHandler::ShowCloudPrintSetupDialog,
117                    base::Unretained(this)));
118     web_ui()->RegisterMessageCallback(
119         "disableCloudPrintConnector",
120         base::Bind(&LocalDiscoveryUIHandler::HandleDisableCloudPrintConnector,
121                    base::Unretained(this)));
122   }
123 #endif  // defined(ENABLE_FULL_PRINTING)
124 }
125
126 void LocalDiscoveryUIHandler::HandleStart(const base::ListValue* args) {
127   Profile* profile = Profile::FromWebUI(web_ui());
128
129   // If privet_lister_ is already set, it is a mock used for tests or the result
130   // of a reload.
131   if (!privet_lister_) {
132     service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
133     privet_lister_.reset(new PrivetDeviceListerImpl(
134         service_discovery_client_.get(), this));
135     privet_http_factory_ =
136         PrivetHTTPAsynchronousFactory::CreateInstance(
137             service_discovery_client_.get(), profile->GetRequestContext());
138
139     SigninManagerBase* signin_manager =
140         SigninManagerFactory::GetInstance()->GetForProfile(profile);
141     if (signin_manager)
142       signin_manager->AddObserver(this);
143   }
144
145   privet_lister_->Start();
146   privet_lister_->DiscoverNewDevices(false);
147
148 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
149   StartCloudPrintConnector();
150 #endif
151
152   CheckUserLoggedIn();
153 }
154
155 void LocalDiscoveryUIHandler::HandleIsVisible(const base::ListValue* args) {
156   bool is_visible = false;
157   bool rv = args->GetBoolean(0, &is_visible);
158   DCHECK(rv);
159   SetIsVisible(is_visible);
160 }
161
162 void LocalDiscoveryUIHandler::HandleRegisterDevice(
163     const base::ListValue* args) {
164   std::string device;
165
166   bool rv = args->GetString(0, &device);
167   DCHECK(rv);
168
169   privet_resolution_ = privet_http_factory_->CreatePrivetHTTP(
170       device,
171       device_descriptions_[device].address,
172       base::Bind(&LocalDiscoveryUIHandler::StartRegisterHTTP,
173                  base::Unretained(this)));
174   privet_resolution_->Start();
175 }
176
177 void LocalDiscoveryUIHandler::HandleCancelRegistration(
178     const base::ListValue* args) {
179   ResetCurrentRegistration();
180 }
181
182 void LocalDiscoveryUIHandler::HandleRequestPrinterList(
183     const base::ListValue* args) {
184   Profile* profile = Profile::FromWebUI(web_ui());
185   ProfileOAuth2TokenService* token_service =
186       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
187
188   SigninManagerBase* signin_manager =
189       SigninManagerFactory::GetInstance()->GetForProfile(profile);
190
191   cloud_print_printer_list_.reset(
192       new CloudPrintPrinterList(profile->GetRequestContext(),
193                                 token_service,
194                                 signin_manager->GetAuthenticatedAccountId(),
195                                 this));
196   cloud_print_printer_list_->Start();
197 }
198
199 void LocalDiscoveryUIHandler::HandleOpenCloudPrintURL(
200     const base::ListValue* args) {
201   std::string id;
202   bool rv = args->GetString(0, &id);
203   DCHECK(rv);
204
205   Browser* browser = chrome::FindBrowserWithWebContents(
206       web_ui()->GetWebContents());
207   DCHECK(browser);
208
209   chrome::AddSelectedTabWithURL(browser,
210                                 cloud_devices::GetCloudPrintManageDeviceURL(id),
211                                 content::PAGE_TRANSITION_FROM_API);
212 }
213
214 void LocalDiscoveryUIHandler::HandleShowSyncUI(
215     const base::ListValue* args) {
216   Browser* browser = chrome::FindBrowserWithWebContents(
217       web_ui()->GetWebContents());
218   DCHECK(browser);
219
220   GURL url(signin::GetPromoURL(signin::SOURCE_DEVICES_PAGE,
221                                true));  // auto close after success.
222
223   browser->OpenURL(
224       content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB,
225                              content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
226 }
227
228 void LocalDiscoveryUIHandler::StartRegisterHTTP(
229     scoped_ptr<PrivetHTTPClient> http_client) {
230   current_http_client_.swap(http_client);
231
232   std::string user = GetSyncAccount();
233
234   if (!current_http_client_) {
235     SendRegisterError();
236     return;
237   }
238
239   current_register_operation_ =
240       current_http_client_->CreateRegisterOperation(user, this);
241   current_register_operation_->Start();
242 }
243
244 void LocalDiscoveryUIHandler::OnPrivetRegisterClaimToken(
245     PrivetRegisterOperation* operation,
246     const std::string& token,
247     const GURL& url) {
248   web_ui()->CallJavascriptFunction(
249       "local_discovery.onRegistrationConfirmedOnPrinter");
250   if (device_descriptions_.count(current_http_client_->GetName()) == 0) {
251     SendRegisterError();
252     return;
253   }
254
255   bool is_cloud_print =
256       device_descriptions_[current_http_client_->GetName()].type ==
257       kDeviceTypePrinter;
258
259   Profile* profile = Profile::FromWebUI(web_ui());
260
261   ProfileOAuth2TokenService* token_service =
262       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
263
264   if (!token_service) {
265     SendRegisterError();
266     return;
267   }
268
269   SigninManagerBase* signin_manager =
270       SigninManagerFactory::GetInstance()->GetForProfile(profile);
271   if (!signin_manager) {
272     SendRegisterError();
273     return;
274   }
275
276   confirm_api_call_flow_.reset(new PrivetConfirmApiCallFlow(
277       profile->GetRequestContext(),
278       token_service,
279       signin_manager->GetAuthenticatedAccountId(),
280       is_cloud_print,
281       token,
282       base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone,
283                  base::Unretained(this))));
284   confirm_api_call_flow_->Start();
285 }
286
287 void LocalDiscoveryUIHandler::OnPrivetRegisterError(
288     PrivetRegisterOperation* operation,
289     const std::string& action,
290     PrivetRegisterOperation::FailureReason reason,
291     int printer_http_code,
292     const base::DictionaryValue* json) {
293   std::string error;
294
295   if (reason == PrivetRegisterOperation::FAILURE_JSON_ERROR &&
296       json->GetString(kPrivetKeyError, &error)) {
297     if (error == kPrivetErrorTimeout) {
298         web_ui()->CallJavascriptFunction(
299             "local_discovery.onRegistrationTimeout");
300       return;
301     } else if (error == kPrivetErrorCancel) {
302       web_ui()->CallJavascriptFunction(
303             "local_discovery.onRegistrationCanceledPrinter");
304       return;
305     }
306   }
307
308   SendRegisterError();
309 }
310
311 void LocalDiscoveryUIHandler::OnPrivetRegisterDone(
312     PrivetRegisterOperation* operation,
313     const std::string& device_id) {
314   std::string name = operation->GetHTTPClient()->GetName();
315
316   current_register_operation_.reset();
317   current_http_client_.reset();
318
319   // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
320   // block the printer's announcement.
321   privet_lister_->DiscoverNewDevices(false);
322
323   DeviceDescriptionMap::iterator found = device_descriptions_.find(name);
324
325   if (found == device_descriptions_.end()) {
326     // TODO(noamsml): Handle the case where a printer's record is not present at
327     // the end of registration.
328     SendRegisterError();
329     return;
330   }
331
332   SendRegisterDone(found->first, found->second);
333 }
334
335 void LocalDiscoveryUIHandler::OnConfirmDone(GCDBaseApiFlow::Status status) {
336   if (status == GCDBaseApiFlow::SUCCESS) {
337     confirm_api_call_flow_.reset();
338     current_register_operation_->CompleteRegistration();
339   } else {
340     SendRegisterError();
341   }
342 }
343
344 void LocalDiscoveryUIHandler::DeviceChanged(
345     bool added,
346     const std::string& name,
347     const DeviceDescription& description) {
348   device_descriptions_[name] = description;
349
350   base::DictionaryValue info;
351
352   base::StringValue service_name(name);
353   scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
354
355   if (description.id.empty()) {
356     info.SetString("service_name", name);
357     info.SetString("human_readable_name", description.name);
358     info.SetString("description", description.description);
359
360     web_ui()->CallJavascriptFunction(
361         "local_discovery.onUnregisteredDeviceUpdate",
362         service_name, info);
363   } else {
364     web_ui()->CallJavascriptFunction(
365         "local_discovery.onUnregisteredDeviceUpdate",
366         service_name, *null_value);
367   }
368 }
369
370 void LocalDiscoveryUIHandler::DeviceRemoved(const std::string& name) {
371   device_descriptions_.erase(name);
372   scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
373   base::StringValue name_value(name);
374
375   web_ui()->CallJavascriptFunction("local_discovery.onUnregisteredDeviceUpdate",
376                                    name_value, *null_value);
377 }
378
379 void LocalDiscoveryUIHandler::DeviceCacheFlushed() {
380   web_ui()->CallJavascriptFunction("local_discovery.onDeviceCacheFlushed");
381   privet_lister_->DiscoverNewDevices(false);
382 }
383
384 void LocalDiscoveryUIHandler::OnCloudPrintPrinterListReady() {
385   base::ListValue printer_object_list;
386   std::set<std::string> local_ids;
387
388   for (DeviceDescriptionMap::iterator i = device_descriptions_.begin();
389        i != device_descriptions_.end();
390        i++) {
391     std::string device_id = i->second.id;
392     if (!device_id.empty()) {
393       const CloudPrintPrinterList::PrinterDetails* details =
394           cloud_print_printer_list_->GetDetailsFor(device_id);
395
396       if (details) {
397         local_ids.insert(device_id);
398         printer_object_list.Append(CreatePrinterInfo(*details).release());
399       }
400     }
401   }
402
403   for (CloudPrintPrinterList::iterator i = cloud_print_printer_list_->begin();
404        i != cloud_print_printer_list_->end(); i++) {
405     if (local_ids.count(i->id) == 0) {
406       printer_object_list.Append(CreatePrinterInfo(*i).release());
407     }
408   }
409
410   web_ui()->CallJavascriptFunction(
411       "local_discovery.onCloudDeviceListAvailable", printer_object_list);
412 }
413
414 void LocalDiscoveryUIHandler::OnCloudPrintPrinterListUnavailable() {
415   web_ui()->CallJavascriptFunction(
416       "local_discovery.onCloudDeviceListUnavailable");
417 }
418
419 void LocalDiscoveryUIHandler::GoogleSigninSucceeded(
420     const std::string& username,
421     const std::string& password) {
422   CheckUserLoggedIn();
423 }
424
425 void LocalDiscoveryUIHandler::GoogleSignedOut(const std::string& username) {
426   CheckUserLoggedIn();
427 }
428
429 void LocalDiscoveryUIHandler::SendRegisterError() {
430   web_ui()->CallJavascriptFunction("local_discovery.onRegistrationFailed");
431 }
432
433 void LocalDiscoveryUIHandler::SendRegisterDone(
434     const std::string& service_name, const DeviceDescription& device) {
435   base::DictionaryValue printer_value;
436
437   printer_value.SetString("id", device.id);
438   printer_value.SetString("display_name", device.name);
439   printer_value.SetString("description", device.description);
440   printer_value.SetString("service_name", service_name);
441
442   web_ui()->CallJavascriptFunction("local_discovery.onRegistrationSuccess",
443                                    printer_value);
444 }
445
446 void LocalDiscoveryUIHandler::SetIsVisible(bool visible) {
447   if (visible != is_visible_) {
448     g_num_visible += visible ? 1 : -1;
449     is_visible_ = visible;
450   }
451 }
452
453 std::string LocalDiscoveryUIHandler::GetSyncAccount() {
454   Profile* profile = Profile::FromWebUI(web_ui());
455   SigninManagerBase* signin_manager =
456       SigninManagerFactory::GetForProfileIfExists(profile);
457
458   if (!signin_manager) {
459     return "";
460   }
461
462   return signin_manager->GetAuthenticatedUsername();
463 }
464
465 // TODO(noamsml): Create master object for registration flow.
466 void LocalDiscoveryUIHandler::ResetCurrentRegistration() {
467   if (current_register_operation_.get()) {
468     current_register_operation_->Cancel();
469     current_register_operation_.reset();
470   }
471
472   confirm_api_call_flow_.reset();
473   privet_resolution_.reset();
474   current_http_client_.reset();
475 }
476
477 scoped_ptr<base::DictionaryValue> LocalDiscoveryUIHandler::CreatePrinterInfo(
478     const CloudPrintPrinterList::PrinterDetails& description) {
479   scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
480
481   return_value->SetString("id", description.id);
482   return_value->SetString("display_name", description.display_name);
483   return_value->SetString("description", description.description);
484
485   return return_value.Pass();
486 }
487
488 void LocalDiscoveryUIHandler::CheckUserLoggedIn() {
489   base::FundamentalValue logged_in_value(!GetSyncAccount().empty());
490   web_ui()->CallJavascriptFunction("local_discovery.setUserLoggedIn",
491                                    logged_in_value);
492 }
493
494 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
495 void LocalDiscoveryUIHandler::StartCloudPrintConnector() {
496   Profile* profile = Profile::FromWebUI(web_ui());
497
498   base::Closure cloud_print_callback = base::Bind(
499       &LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged,
500           base::Unretained(this));
501
502   if (cloud_print_connector_email_.GetPrefName().empty()) {
503     cloud_print_connector_email_.Init(
504         prefs::kCloudPrintEmail, profile->GetPrefs(), cloud_print_callback);
505   }
506
507   if (cloud_print_connector_enabled_.GetPrefName().empty()) {
508     cloud_print_connector_enabled_.Init(
509         prefs::kCloudPrintProxyEnabled, profile->GetPrefs(),
510         cloud_print_callback);
511   }
512
513   if (cloud_print_connector_ui_enabled_) {
514     SetupCloudPrintConnectorSection();
515     RefreshCloudPrintStatusFromService();
516   } else {
517     RemoveCloudPrintConnectorSection();
518   }
519 }
520
521 void LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged() {
522   if (cloud_print_connector_ui_enabled_)
523     SetupCloudPrintConnectorSection();
524 }
525
526 void LocalDiscoveryUIHandler::ShowCloudPrintSetupDialog(
527     const base::ListValue* args) {
528   content::RecordAction(
529       base::UserMetricsAction("Options_EnableCloudPrintProxy"));
530   // Open the connector enable page in the current tab.
531   Profile* profile = Profile::FromWebUI(web_ui());
532   content::OpenURLParams params(
533       cloud_devices::GetCloudPrintEnableURL(
534           CloudPrintProxyServiceFactory::GetForProfile(profile)->proxy_id()),
535       content::Referrer(),
536       CURRENT_TAB,
537       content::PAGE_TRANSITION_LINK,
538       false);
539   web_ui()->GetWebContents()->OpenURL(params);
540 }
541
542 void LocalDiscoveryUIHandler::HandleDisableCloudPrintConnector(
543     const base::ListValue* args) {
544   content::RecordAction(
545       base::UserMetricsAction("Options_DisableCloudPrintProxy"));
546   CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
547       DisableForUser();
548 }
549
550 void LocalDiscoveryUIHandler::SetupCloudPrintConnectorSection() {
551   Profile* profile = Profile::FromWebUI(web_ui());
552
553   if (!CloudPrintProxyServiceFactory::GetForProfile(profile)) {
554     cloud_print_connector_ui_enabled_ = false;
555     RemoveCloudPrintConnectorSection();
556     return;
557   }
558
559   bool cloud_print_connector_allowed =
560       !cloud_print_connector_enabled_.IsManaged() ||
561       cloud_print_connector_enabled_.GetValue();
562   base::FundamentalValue allowed(cloud_print_connector_allowed);
563
564   std::string email;
565   if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
566       cloud_print_connector_allowed) {
567     email = profile->GetPrefs()->GetString(prefs::kCloudPrintEmail);
568   }
569   base::FundamentalValue disabled(email.empty());
570
571   base::string16 label_str;
572   if (email.empty()) {
573     label_str = l10n_util::GetStringFUTF16(
574         IDS_LOCAL_DISCOVERY_CLOUD_PRINT_CONNECTOR_DISABLED_LABEL,
575         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
576   } else {
577     label_str = l10n_util::GetStringFUTF16(
578         IDS_OPTIONS_CLOUD_PRINT_CONNECTOR_ENABLED_LABEL,
579         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT),
580         base::UTF8ToUTF16(email));
581   }
582   base::StringValue label(label_str);
583
584   web_ui()->CallJavascriptFunction(
585       "local_discovery.setupCloudPrintConnectorSection", disabled, label,
586       allowed);
587 }
588
589 void LocalDiscoveryUIHandler::RemoveCloudPrintConnectorSection() {
590   web_ui()->CallJavascriptFunction(
591       "local_discovery.removeCloudPrintConnectorSection");
592 }
593
594 void LocalDiscoveryUIHandler::RefreshCloudPrintStatusFromService() {
595   if (cloud_print_connector_ui_enabled_)
596     CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
597         RefreshStatusFromService();
598 }
599 #endif // cloud print connector option stuff
600
601 }  // namespace local_discovery