• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_switches.h"
33 #include "components/cloud_devices/common/cloud_devices_urls.h"
34 #include "components/signin/core/browser/profile_oauth2_token_service.h"
35 #include "components/signin/core/browser/signin_manager_base.h"
36 #include "content/public/browser/user_metrics.h"
37 #include "content/public/browser/web_ui.h"
38 #include "content/public/common/page_transition_types.h"
39 #include "grit/generated_resources.h"
40 #include "net/base/host_port_pair.h"
41 #include "net/base/net_util.h"
42 #include "net/base/url_util.h"
43 #include "net/http/http_status_code.h"
44 #include "ui/base/l10n/l10n_util.h"
45 
46 #if defined(ENABLE_FULL_PRINTING) && !defined(OS_CHROMEOS)
47 #define CLOUD_PRINT_CONNECTOR_UI_AVAILABLE
48 #endif
49 
50 namespace local_discovery {
51 
52 namespace {
53 
54 const char kDictionaryKeyServiceName[] = "service_name";
55 const char kDictionaryKeyDisplayName[] = "display_name";
56 const char kDictionaryKeyDescription[] = "description";
57 const char kDictionaryKeyType[] = "type";
58 const char kDictionaryKeyIsWifi[] = "is_wifi";
59 const char kDictionaryKeyID[] = "id";
60 
61 const char kKeyPrefixMDns[] = "MDns:";
62 
63 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
64 const char kKeyPrefixWifi[] = "WiFi:";
65 #endif  // ENABLE_WIFI_BOOTSTRAPPING
66 
67 int g_num_visible = 0;
68 
CreateDeviceInfo(const CloudDeviceListDelegate::Device & description)69 scoped_ptr<base::DictionaryValue> CreateDeviceInfo(
70     const CloudDeviceListDelegate::Device& description) {
71   scoped_ptr<base::DictionaryValue> return_value(new base::DictionaryValue);
72 
73   return_value->SetString(kDictionaryKeyID, description.id);
74   return_value->SetString(kDictionaryKeyDisplayName, description.display_name);
75   return_value->SetString(kDictionaryKeyDescription, description.description);
76   return_value->SetString(kDictionaryKeyType, description.type);
77 
78   return return_value.Pass();
79 }
80 
ReadDevicesList(const std::vector<CloudDeviceListDelegate::Device> & devices,const std::set<std::string> & local_ids,base::ListValue * devices_list)81 void ReadDevicesList(
82     const std::vector<CloudDeviceListDelegate::Device>& devices,
83     const std::set<std::string>& local_ids,
84     base::ListValue* devices_list) {
85   for (CloudDeviceList::iterator i = devices.begin(); i != devices.end(); i++) {
86     if (local_ids.count(i->id) > 0) {
87       devices_list->Append(CreateDeviceInfo(*i).release());
88     }
89   }
90 
91   for (CloudDeviceList::iterator i = devices.begin(); i != devices.end(); i++) {
92     if (local_ids.count(i->id) == 0) {
93       devices_list->Append(CreateDeviceInfo(*i).release());
94     }
95   }
96 }
97 
98 }  // namespace
99 
LocalDiscoveryUIHandler()100 LocalDiscoveryUIHandler::LocalDiscoveryUIHandler()
101     : is_visible_(false),
102       failed_list_count_(0),
103       succeded_list_count_(0) {
104 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
105 #if !defined(GOOGLE_CHROME_BUILD) && defined(OS_WIN)
106   // On Windows, we need the PDF plugin which is only guaranteed to exist on
107   // Google Chrome builds. Use a command-line switch for Windows non-Google
108   //  Chrome builds.
109   cloud_print_connector_ui_enabled_ =
110       CommandLine::ForCurrentProcess()->HasSwitch(
111       switches::kEnableCloudPrintProxy);
112 #else
113   // Always enabled for Linux and Google Chrome Windows builds.
114   // Never enabled for Chrome OS, we don't even need to indicate it.
115   cloud_print_connector_ui_enabled_ = true;
116 #endif
117 #endif  // defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
118 }
119 
~LocalDiscoveryUIHandler()120 LocalDiscoveryUIHandler::~LocalDiscoveryUIHandler() {
121   Profile* profile = Profile::FromWebUI(web_ui());
122   SigninManagerBase* signin_manager =
123       SigninManagerFactory::GetInstance()->GetForProfile(profile);
124   if (signin_manager)
125     signin_manager->RemoveObserver(this);
126   ResetCurrentRegistration();
127   SetIsVisible(false);
128 }
129 
130 // static
GetHasVisible()131 bool LocalDiscoveryUIHandler::GetHasVisible() {
132   return g_num_visible != 0;
133 }
134 
RegisterMessages()135 void LocalDiscoveryUIHandler::RegisterMessages() {
136   web_ui()->RegisterMessageCallback("start", base::Bind(
137       &LocalDiscoveryUIHandler::HandleStart,
138       base::Unretained(this)));
139   web_ui()->RegisterMessageCallback("isVisible", base::Bind(
140       &LocalDiscoveryUIHandler::HandleIsVisible,
141       base::Unretained(this)));
142   web_ui()->RegisterMessageCallback("registerDevice", base::Bind(
143       &LocalDiscoveryUIHandler::HandleRegisterDevice,
144       base::Unretained(this)));
145   web_ui()->RegisterMessageCallback("cancelRegistration", base::Bind(
146       &LocalDiscoveryUIHandler::HandleCancelRegistration,
147       base::Unretained(this)));
148   web_ui()->RegisterMessageCallback(
149       "requestDeviceList",
150       base::Bind(&LocalDiscoveryUIHandler::HandleRequestDeviceList,
151                  base::Unretained(this)));
152   web_ui()->RegisterMessageCallback("openCloudPrintURL", base::Bind(
153       &LocalDiscoveryUIHandler::HandleOpenCloudPrintURL,
154       base::Unretained(this)));
155   web_ui()->RegisterMessageCallback("showSyncUI", base::Bind(
156       &LocalDiscoveryUIHandler::HandleShowSyncUI,
157       base::Unretained(this)));
158 
159   // Cloud print connector related messages
160 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
161   if (cloud_print_connector_ui_enabled_) {
162     web_ui()->RegisterMessageCallback(
163         "showCloudPrintSetupDialog",
164         base::Bind(&LocalDiscoveryUIHandler::ShowCloudPrintSetupDialog,
165                    base::Unretained(this)));
166     web_ui()->RegisterMessageCallback(
167         "disableCloudPrintConnector",
168         base::Bind(&LocalDiscoveryUIHandler::HandleDisableCloudPrintConnector,
169                    base::Unretained(this)));
170   }
171 #endif  // defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
172 }
173 
HandleStart(const base::ListValue * args)174 void LocalDiscoveryUIHandler::HandleStart(const base::ListValue* args) {
175   Profile* profile = Profile::FromWebUI(web_ui());
176 
177   // If privet_lister_ is already set, it is a mock used for tests or the result
178   // of a reload.
179   if (!privet_lister_) {
180     service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance();
181     privet_lister_.reset(
182         new PrivetDeviceListerImpl(service_discovery_client_.get(), this));
183     privet_http_factory_ = PrivetHTTPAsynchronousFactory::CreateInstance(
184         service_discovery_client_.get(), profile->GetRequestContext());
185 
186     SigninManagerBase* signin_manager =
187         SigninManagerFactory::GetInstance()->GetForProfile(profile);
188     if (signin_manager)
189       signin_manager->AddObserver(this);
190   }
191 
192   privet_lister_->Start();
193   privet_lister_->DiscoverNewDevices(false);
194 
195 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
196   StartCloudPrintConnector();
197 #endif
198 
199 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
200   if (CommandLine::ForCurrentProcess()->HasSwitch(
201           switches::kEnableCloudDevices)) {
202     StartWifiBootstrapping();
203   }
204 #endif
205 
206   CheckUserLoggedIn();
207 }
208 
HandleIsVisible(const base::ListValue * args)209 void LocalDiscoveryUIHandler::HandleIsVisible(const base::ListValue* args) {
210   bool is_visible = false;
211   bool rv = args->GetBoolean(0, &is_visible);
212   DCHECK(rv);
213   SetIsVisible(is_visible);
214 }
215 
HandleRegisterDevice(const base::ListValue * args)216 void LocalDiscoveryUIHandler::HandleRegisterDevice(
217     const base::ListValue* args) {
218   std::string device;
219 
220   bool rv = args->GetString(0, &device);
221   DCHECK(rv);
222 
223   privet_resolution_ = privet_http_factory_->CreatePrivetHTTP(
224       device,
225       device_descriptions_[device].address,
226       base::Bind(&LocalDiscoveryUIHandler::StartRegisterHTTP,
227                  base::Unretained(this)));
228   privet_resolution_->Start();
229 }
230 
HandleCancelRegistration(const base::ListValue * args)231 void LocalDiscoveryUIHandler::HandleCancelRegistration(
232     const base::ListValue* args) {
233   ResetCurrentRegistration();
234 }
235 
HandleRequestDeviceList(const base::ListValue * args)236 void LocalDiscoveryUIHandler::HandleRequestDeviceList(
237     const base::ListValue* args) {
238   failed_list_count_ = 0;
239   succeded_list_count_ = 0;
240   cloud_devices_.clear();
241 
242   cloud_print_printer_list_ = CreateApiFlow();
243   if (CommandLine::ForCurrentProcess()->HasSwitch(
244       switches::kEnableCloudDevices)) {
245     cloud_device_list_ = CreateApiFlow();
246   }
247 
248   if (cloud_print_printer_list_) {
249     cloud_print_printer_list_->Start(
250         make_scoped_ptr<GCDApiFlow::Request>(new CloudPrintPrinterList(this)));
251   }
252   if (cloud_device_list_) {
253     cloud_device_list_->Start(
254         make_scoped_ptr<GCDApiFlow::Request>(new CloudDeviceList(this)));
255   }
256   CheckListingDone();
257 }
258 
HandleOpenCloudPrintURL(const base::ListValue * args)259 void LocalDiscoveryUIHandler::HandleOpenCloudPrintURL(
260     const base::ListValue* args) {
261   std::string id;
262   bool rv = args->GetString(0, &id);
263   DCHECK(rv);
264 
265   Browser* browser = chrome::FindBrowserWithWebContents(
266       web_ui()->GetWebContents());
267   DCHECK(browser);
268 
269   chrome::AddSelectedTabWithURL(browser,
270                                 cloud_devices::GetCloudPrintManageDeviceURL(id),
271                                 content::PAGE_TRANSITION_FROM_API);
272 }
273 
HandleShowSyncUI(const base::ListValue * args)274 void LocalDiscoveryUIHandler::HandleShowSyncUI(
275     const base::ListValue* args) {
276   Browser* browser = chrome::FindBrowserWithWebContents(
277       web_ui()->GetWebContents());
278   DCHECK(browser);
279 
280   GURL url(signin::GetPromoURL(signin::SOURCE_DEVICES_PAGE,
281                                true));  // auto close after success.
282 
283   browser->OpenURL(
284       content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB,
285                              content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
286 }
287 
StartRegisterHTTP(scoped_ptr<PrivetHTTPClient> http_client)288 void LocalDiscoveryUIHandler::StartRegisterHTTP(
289     scoped_ptr<PrivetHTTPClient> http_client) {
290   current_http_client_ = PrivetV1HTTPClient::CreateDefault(http_client.Pass());
291 
292   std::string user = GetSyncAccount();
293 
294   if (!current_http_client_) {
295     SendRegisterError();
296     return;
297   }
298 
299   current_register_operation_ =
300       current_http_client_->CreateRegisterOperation(user, this);
301   current_register_operation_->Start();
302 }
303 
OnPrivetRegisterClaimToken(PrivetRegisterOperation * operation,const std::string & token,const GURL & url)304 void LocalDiscoveryUIHandler::OnPrivetRegisterClaimToken(
305     PrivetRegisterOperation* operation,
306     const std::string& token,
307     const GURL& url) {
308   web_ui()->CallJavascriptFunction(
309       "local_discovery.onRegistrationConfirmedOnPrinter");
310   if (device_descriptions_.count(current_http_client_->GetName()) == 0) {
311     SendRegisterError();
312     return;
313   }
314 
315   confirm_api_call_flow_ = CreateApiFlow();
316   if (!confirm_api_call_flow_) {
317     SendRegisterError();
318     return;
319   }
320   confirm_api_call_flow_->Start(
321       make_scoped_ptr<GCDApiFlow::Request>(new PrivetConfirmApiCallFlow(
322           token,
323           base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone,
324                      base::Unretained(this)))));
325 }
326 
OnPrivetRegisterError(PrivetRegisterOperation * operation,const std::string & action,PrivetRegisterOperation::FailureReason reason,int printer_http_code,const base::DictionaryValue * json)327 void LocalDiscoveryUIHandler::OnPrivetRegisterError(
328     PrivetRegisterOperation* operation,
329     const std::string& action,
330     PrivetRegisterOperation::FailureReason reason,
331     int printer_http_code,
332     const base::DictionaryValue* json) {
333   std::string error;
334 
335   if (reason == PrivetRegisterOperation::FAILURE_JSON_ERROR &&
336       json->GetString(kPrivetKeyError, &error)) {
337     if (error == kPrivetErrorTimeout) {
338         web_ui()->CallJavascriptFunction(
339             "local_discovery.onRegistrationTimeout");
340       return;
341     } else if (error == kPrivetErrorCancel) {
342       web_ui()->CallJavascriptFunction(
343             "local_discovery.onRegistrationCanceledPrinter");
344       return;
345     }
346   }
347 
348   SendRegisterError();
349 }
350 
OnPrivetRegisterDone(PrivetRegisterOperation * operation,const std::string & device_id)351 void LocalDiscoveryUIHandler::OnPrivetRegisterDone(
352     PrivetRegisterOperation* operation,
353     const std::string& device_id) {
354   std::string name = operation->GetHTTPClient()->GetName();
355 
356   current_register_operation_.reset();
357   current_http_client_.reset();
358 
359   // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
360   // block the printer's announcement.
361   privet_lister_->DiscoverNewDevices(false);
362 
363   DeviceDescriptionMap::iterator found = device_descriptions_.find(name);
364 
365   if (found == device_descriptions_.end()) {
366     // TODO(noamsml): Handle the case where a printer's record is not present at
367     // the end of registration.
368     SendRegisterError();
369     return;
370   }
371 
372   SendRegisterDone(found->first, found->second);
373 }
374 
OnConfirmDone(GCDApiFlow::Status status)375 void LocalDiscoveryUIHandler::OnConfirmDone(GCDApiFlow::Status status) {
376   if (status == GCDApiFlow::SUCCESS) {
377     confirm_api_call_flow_.reset();
378     current_register_operation_->CompleteRegistration();
379   } else {
380     SendRegisterError();
381   }
382 }
383 
DeviceChanged(bool added,const std::string & name,const DeviceDescription & description)384 void LocalDiscoveryUIHandler::DeviceChanged(
385     bool added,
386     const std::string& name,
387     const DeviceDescription& description) {
388   device_descriptions_[name] = description;
389 
390   base::DictionaryValue info;
391 
392   base::StringValue service_key(kKeyPrefixMDns + name);
393 
394   if (description.id.empty()) {
395     info.SetString(kDictionaryKeyServiceName, name);
396     info.SetString(kDictionaryKeyDisplayName, description.name);
397     info.SetString(kDictionaryKeyDescription, description.description);
398     info.SetString(kDictionaryKeyType, description.type);
399     info.SetBoolean(kDictionaryKeyIsWifi, false);
400 
401     web_ui()->CallJavascriptFunction(
402         "local_discovery.onUnregisteredDeviceUpdate", service_key, info);
403   } else {
404     scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
405 
406     web_ui()->CallJavascriptFunction(
407         "local_discovery.onUnregisteredDeviceUpdate", service_key, *null_value);
408   }
409 }
410 
DeviceRemoved(const std::string & name)411 void LocalDiscoveryUIHandler::DeviceRemoved(const std::string& name) {
412   device_descriptions_.erase(name);
413   scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
414   base::StringValue name_value(kKeyPrefixMDns + name);
415 
416   web_ui()->CallJavascriptFunction("local_discovery.onUnregisteredDeviceUpdate",
417                                    name_value, *null_value);
418 }
419 
DeviceCacheFlushed()420 void LocalDiscoveryUIHandler::DeviceCacheFlushed() {
421   web_ui()->CallJavascriptFunction("local_discovery.onDeviceCacheFlushed");
422   privet_lister_->DiscoverNewDevices(false);
423 }
424 
OnDeviceListReady(const std::vector<Device> & devices)425 void LocalDiscoveryUIHandler::OnDeviceListReady(
426     const std::vector<Device>& devices) {
427   cloud_devices_.insert(cloud_devices_.end(), devices.begin(), devices.end());
428   ++succeded_list_count_;
429   CheckListingDone();
430 }
431 
OnDeviceListUnavailable()432 void LocalDiscoveryUIHandler::OnDeviceListUnavailable() {
433   ++failed_list_count_;
434   CheckListingDone();
435 }
436 
GoogleSigninSucceeded(const std::string & username,const std::string & password)437 void LocalDiscoveryUIHandler::GoogleSigninSucceeded(
438     const std::string& username,
439     const std::string& password) {
440   CheckUserLoggedIn();
441 }
442 
GoogleSignedOut(const std::string & username)443 void LocalDiscoveryUIHandler::GoogleSignedOut(const std::string& username) {
444   CheckUserLoggedIn();
445 }
446 
SendRegisterError()447 void LocalDiscoveryUIHandler::SendRegisterError() {
448   web_ui()->CallJavascriptFunction("local_discovery.onRegistrationFailed");
449 }
450 
SendRegisterDone(const std::string & service_name,const DeviceDescription & device)451 void LocalDiscoveryUIHandler::SendRegisterDone(
452     const std::string& service_name, const DeviceDescription& device) {
453   base::DictionaryValue printer_value;
454 
455   printer_value.SetString(kDictionaryKeyID, device.id);
456   printer_value.SetString(kDictionaryKeyDisplayName, device.name);
457   printer_value.SetString(kDictionaryKeyDescription, device.description);
458   printer_value.SetString(kDictionaryKeyServiceName, service_name);
459 
460   web_ui()->CallJavascriptFunction("local_discovery.onRegistrationSuccess",
461                                    printer_value);
462 }
463 
SetIsVisible(bool visible)464 void LocalDiscoveryUIHandler::SetIsVisible(bool visible) {
465   if (visible != is_visible_) {
466     g_num_visible += visible ? 1 : -1;
467     is_visible_ = visible;
468   }
469 }
470 
GetSyncAccount()471 std::string LocalDiscoveryUIHandler::GetSyncAccount() {
472   Profile* profile = Profile::FromWebUI(web_ui());
473   SigninManagerBase* signin_manager =
474       SigninManagerFactory::GetForProfileIfExists(profile);
475 
476   if (!signin_manager) {
477     return "";
478   }
479 
480   return signin_manager->GetAuthenticatedUsername();
481 }
482 
483 // TODO(noamsml): Create master object for registration flow.
ResetCurrentRegistration()484 void LocalDiscoveryUIHandler::ResetCurrentRegistration() {
485   if (current_register_operation_) {
486     current_register_operation_->Cancel();
487     current_register_operation_.reset();
488   }
489 
490   confirm_api_call_flow_.reset();
491   privet_resolution_.reset();
492   current_http_client_.reset();
493 }
494 
CheckUserLoggedIn()495 void LocalDiscoveryUIHandler::CheckUserLoggedIn() {
496   base::FundamentalValue logged_in_value(!GetSyncAccount().empty());
497   web_ui()->CallJavascriptFunction("local_discovery.setUserLoggedIn",
498                                    logged_in_value);
499 }
500 
CheckListingDone()501 void LocalDiscoveryUIHandler::CheckListingDone() {
502   int started = 0;
503   if (cloud_print_printer_list_)
504     ++started;
505   if (cloud_device_list_)
506     ++started;
507 
508   if (started > failed_list_count_ + succeded_list_count_)
509     return;
510 
511   if (succeded_list_count_ <= 0) {
512     web_ui()->CallJavascriptFunction(
513         "local_discovery.onCloudDeviceListUnavailable");
514     return;
515   }
516 
517   base::ListValue devices_list;
518   std::set<std::string> local_ids;
519 
520   for (DeviceDescriptionMap::iterator i = device_descriptions_.begin();
521        i != device_descriptions_.end(); i++) {
522     local_ids.insert(i->second.id);
523   }
524 
525   ReadDevicesList(cloud_devices_, local_ids, &devices_list);
526 
527   web_ui()->CallJavascriptFunction(
528       "local_discovery.onCloudDeviceListAvailable", devices_list);
529   cloud_print_printer_list_.reset();
530   cloud_device_list_.reset();
531 }
532 
CreateApiFlow()533 scoped_ptr<GCDApiFlow> LocalDiscoveryUIHandler::CreateApiFlow() {
534   Profile* profile = Profile::FromWebUI(web_ui());
535   if (!profile)
536     return scoped_ptr<GCDApiFlow>();
537   ProfileOAuth2TokenService* token_service =
538       ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
539   if (!token_service)
540     return scoped_ptr<GCDApiFlow>();
541   SigninManagerBase* signin_manager =
542       SigninManagerFactory::GetInstance()->GetForProfile(profile);
543   if (!signin_manager)
544     return scoped_ptr<GCDApiFlow>();
545   return GCDApiFlow::Create(profile->GetRequestContext(),
546                             token_service,
547                             signin_manager->GetAuthenticatedAccountId());
548 }
549 
550 #if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
StartCloudPrintConnector()551 void LocalDiscoveryUIHandler::StartCloudPrintConnector() {
552   Profile* profile = Profile::FromWebUI(web_ui());
553 
554   base::Closure cloud_print_callback = base::Bind(
555       &LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged,
556           base::Unretained(this));
557 
558   if (cloud_print_connector_email_.GetPrefName().empty()) {
559     cloud_print_connector_email_.Init(
560         prefs::kCloudPrintEmail, profile->GetPrefs(), cloud_print_callback);
561   }
562 
563   if (cloud_print_connector_enabled_.GetPrefName().empty()) {
564     cloud_print_connector_enabled_.Init(
565         prefs::kCloudPrintProxyEnabled, profile->GetPrefs(),
566         cloud_print_callback);
567   }
568 
569   if (cloud_print_connector_ui_enabled_) {
570     SetupCloudPrintConnectorSection();
571     RefreshCloudPrintStatusFromService();
572   } else {
573     RemoveCloudPrintConnectorSection();
574   }
575 }
576 
OnCloudPrintPrefsChanged()577 void LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged() {
578   if (cloud_print_connector_ui_enabled_)
579     SetupCloudPrintConnectorSection();
580 }
581 
ShowCloudPrintSetupDialog(const base::ListValue * args)582 void LocalDiscoveryUIHandler::ShowCloudPrintSetupDialog(
583     const base::ListValue* args) {
584   content::RecordAction(
585       base::UserMetricsAction("Options_EnableCloudPrintProxy"));
586   // Open the connector enable page in the current tab.
587   Profile* profile = Profile::FromWebUI(web_ui());
588   content::OpenURLParams params(
589       cloud_devices::GetCloudPrintEnableURL(
590           CloudPrintProxyServiceFactory::GetForProfile(profile)->proxy_id()),
591       content::Referrer(),
592       CURRENT_TAB,
593       content::PAGE_TRANSITION_LINK,
594       false);
595   web_ui()->GetWebContents()->OpenURL(params);
596 }
597 
HandleDisableCloudPrintConnector(const base::ListValue * args)598 void LocalDiscoveryUIHandler::HandleDisableCloudPrintConnector(
599     const base::ListValue* args) {
600   content::RecordAction(
601       base::UserMetricsAction("Options_DisableCloudPrintProxy"));
602   CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
603       DisableForUser();
604 }
605 
SetupCloudPrintConnectorSection()606 void LocalDiscoveryUIHandler::SetupCloudPrintConnectorSection() {
607   Profile* profile = Profile::FromWebUI(web_ui());
608 
609   if (!CloudPrintProxyServiceFactory::GetForProfile(profile)) {
610     cloud_print_connector_ui_enabled_ = false;
611     RemoveCloudPrintConnectorSection();
612     return;
613   }
614 
615   bool cloud_print_connector_allowed =
616       !cloud_print_connector_enabled_.IsManaged() ||
617       cloud_print_connector_enabled_.GetValue();
618   base::FundamentalValue allowed(cloud_print_connector_allowed);
619 
620   std::string email;
621   if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
622       cloud_print_connector_allowed) {
623     email = profile->GetPrefs()->GetString(prefs::kCloudPrintEmail);
624   }
625   base::FundamentalValue disabled(email.empty());
626 
627   base::string16 label_str;
628   if (email.empty()) {
629     label_str = l10n_util::GetStringFUTF16(
630         IDS_LOCAL_DISCOVERY_CLOUD_PRINT_CONNECTOR_DISABLED_LABEL,
631         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
632   } else {
633     label_str = l10n_util::GetStringFUTF16(
634         IDS_OPTIONS_CLOUD_PRINT_CONNECTOR_ENABLED_LABEL,
635         l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT),
636         base::UTF8ToUTF16(email));
637   }
638   base::StringValue label(label_str);
639 
640   web_ui()->CallJavascriptFunction(
641       "local_discovery.setupCloudPrintConnectorSection", disabled, label,
642       allowed);
643 }
644 
RemoveCloudPrintConnectorSection()645 void LocalDiscoveryUIHandler::RemoveCloudPrintConnectorSection() {
646   web_ui()->CallJavascriptFunction(
647       "local_discovery.removeCloudPrintConnectorSection");
648 }
649 
RefreshCloudPrintStatusFromService()650 void LocalDiscoveryUIHandler::RefreshCloudPrintStatusFromService() {
651   if (cloud_print_connector_ui_enabled_)
652     CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
653         RefreshStatusFromService();
654 }
655 
656 #endif // cloud print connector option stuff
657 
658 #if defined(ENABLE_WIFI_BOOTSTRAPPING)
659 
StartWifiBootstrapping()660 void LocalDiscoveryUIHandler::StartWifiBootstrapping() {
661   // Since LocalDiscoveryUIHandler isn't destroyed every time the page is
662   // refreshed, reset bootstrapping_device_lister_ so it's destoryed before
663   // wifi_manager_ is.
664   bootstrapping_device_lister_.reset();
665 
666   wifi_manager_ = wifi::WifiManager::Create();
667   bootstrapping_device_lister_.reset(new wifi::BootstrappingDeviceLister(
668       wifi_manager_.get(),
669       base::Bind(&LocalDiscoveryUIHandler::OnBootstrappingDeviceChanged,
670                  base::Unretained(this))));
671 
672   wifi_manager_->Start();
673   bootstrapping_device_lister_->Start();
674   wifi_manager_->RequestScan();
675 }
676 
OnBootstrappingDeviceChanged(bool available,const wifi::BootstrappingDeviceDescription & description)677 void LocalDiscoveryUIHandler::OnBootstrappingDeviceChanged(
678     bool available,
679     const wifi::BootstrappingDeviceDescription& description) {
680   base::DictionaryValue info;
681 
682   base::StringValue service_key(kKeyPrefixWifi + description.device_ssid);
683 
684   if (available) {
685     info.SetString(kDictionaryKeyServiceName, description.device_ssid);
686     info.SetString(kDictionaryKeyDisplayName, description.device_name);
687     info.SetString(kDictionaryKeyDescription, std::string());
688     info.SetString(kDictionaryKeyType, description.device_kind);
689     info.SetBoolean(kDictionaryKeyIsWifi, true);
690 
691     web_ui()->CallJavascriptFunction(
692         "local_discovery.onUnregisteredDeviceUpdate", service_key, info);
693   } else {
694     scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
695 
696     web_ui()->CallJavascriptFunction(
697         "local_discovery.onUnregisteredDeviceUpdate", service_key, *null_value);
698   }
699 }
700 
701 #endif  // ENABLE_WIFI_BOOTSTRAPPING
702 
703 }  // namespace local_discovery
704