local_discovery_ui_handler.cc revision 46d4c2bc3267f3f028f39e7e311b0f89aba2e4fd
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
50namespace local_discovery {
51
52namespace {
53
54const char kDictionaryKeyServiceName[] = "service_name";
55const char kDictionaryKeyDisplayName[] = "display_name";
56const char kDictionaryKeyDescription[] = "description";
57const char kDictionaryKeyType[] = "type";
58const char kDictionaryKeyIsWifi[] = "is_wifi";
59const char kDictionaryKeyID[] = "id";
60
61const char kKeyPrefixMDns[] = "MDns:";
62
63#if defined(ENABLE_WIFI_BOOTSTRAPPING)
64const char kKeyPrefixWifi[] = "WiFi:";
65#endif  // ENABLE_WIFI_BOOTSTRAPPING
66
67int g_num_visible = 0;
68
69scoped_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
81void 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
100LocalDiscoveryUIHandler::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
120LocalDiscoveryUIHandler::~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
131bool LocalDiscoveryUIHandler::GetHasVisible() {
132  return g_num_visible != 0;
133}
134
135void 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
174void 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_ =
184        PrivetHTTPAsynchronousFactory::CreateInstance(
185            service_discovery_client_.get(), profile->GetRequestContext());
186
187    SigninManagerBase* signin_manager =
188        SigninManagerFactory::GetInstance()->GetForProfile(profile);
189    if (signin_manager)
190      signin_manager->AddObserver(this);
191  }
192
193  privet_lister_->Start();
194  privet_lister_->DiscoverNewDevices(false);
195
196#if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
197  StartCloudPrintConnector();
198#endif
199
200#if defined(ENABLE_WIFI_BOOTSTRAPPING)
201  if (CommandLine::ForCurrentProcess()->HasSwitch(
202          switches::kEnableCloudDevices)) {
203    StartWifiBootstrapping();
204  }
205#endif
206
207  CheckUserLoggedIn();
208}
209
210void LocalDiscoveryUIHandler::HandleIsVisible(const base::ListValue* args) {
211  bool is_visible = false;
212  bool rv = args->GetBoolean(0, &is_visible);
213  DCHECK(rv);
214  SetIsVisible(is_visible);
215}
216
217void LocalDiscoveryUIHandler::HandleRegisterDevice(
218    const base::ListValue* args) {
219  std::string device;
220
221  bool rv = args->GetString(0, &device);
222  DCHECK(rv);
223
224  privet_resolution_ = privet_http_factory_->CreatePrivetHTTP(
225      device,
226      device_descriptions_[device].address,
227      base::Bind(&LocalDiscoveryUIHandler::StartRegisterHTTP,
228                 base::Unretained(this)));
229  privet_resolution_->Start();
230}
231
232void LocalDiscoveryUIHandler::HandleCancelRegistration(
233    const base::ListValue* args) {
234  ResetCurrentRegistration();
235}
236
237void LocalDiscoveryUIHandler::HandleRequestDeviceList(
238    const base::ListValue* args) {
239  failed_list_count_ = 0;
240  succeded_list_count_ = 0;
241  cloud_devices_.clear();
242
243  cloud_print_printer_list_ = CreateApiFlow(
244      scoped_ptr<GCDApiFlow::Request>(new CloudPrintPrinterList(this)));
245  if (CommandLine::ForCurrentProcess()->HasSwitch(
246      switches::kEnableCloudDevices)) {
247    cloud_device_list_ = CreateApiFlow(
248        scoped_ptr<GCDApiFlow::Request>(new CloudDeviceList(this)));
249  }
250
251  if (cloud_print_printer_list_)
252    cloud_print_printer_list_->Start();
253  if (cloud_device_list_)
254    cloud_device_list_->Start();
255  CheckListingDone();
256}
257
258void LocalDiscoveryUIHandler::HandleOpenCloudPrintURL(
259    const base::ListValue* args) {
260  std::string id;
261  bool rv = args->GetString(0, &id);
262  DCHECK(rv);
263
264  Browser* browser = chrome::FindBrowserWithWebContents(
265      web_ui()->GetWebContents());
266  DCHECK(browser);
267
268  chrome::AddSelectedTabWithURL(browser,
269                                cloud_devices::GetCloudPrintManageDeviceURL(id),
270                                content::PAGE_TRANSITION_FROM_API);
271}
272
273void LocalDiscoveryUIHandler::HandleShowSyncUI(
274    const base::ListValue* args) {
275  Browser* browser = chrome::FindBrowserWithWebContents(
276      web_ui()->GetWebContents());
277  DCHECK(browser);
278
279  GURL url(signin::GetPromoURL(signin::SOURCE_DEVICES_PAGE,
280                               true));  // auto close after success.
281
282  browser->OpenURL(
283      content::OpenURLParams(url, content::Referrer(), SINGLETON_TAB,
284                             content::PAGE_TRANSITION_AUTO_BOOKMARK, false));
285}
286
287void LocalDiscoveryUIHandler::StartRegisterHTTP(
288    scoped_ptr<PrivetHTTPClient> http_client) {
289  current_http_client_.swap(http_client);
290
291  std::string user = GetSyncAccount();
292
293  if (!current_http_client_) {
294    SendRegisterError();
295    return;
296  }
297
298  current_register_operation_ =
299      current_http_client_->CreateRegisterOperation(user, this);
300  current_register_operation_->Start();
301}
302
303void LocalDiscoveryUIHandler::OnPrivetRegisterClaimToken(
304    PrivetRegisterOperation* operation,
305    const std::string& token,
306    const GURL& url) {
307  web_ui()->CallJavascriptFunction(
308      "local_discovery.onRegistrationConfirmedOnPrinter");
309  if (device_descriptions_.count(current_http_client_->GetName()) == 0) {
310    SendRegisterError();
311    return;
312  }
313
314  confirm_api_call_flow_ = CreateApiFlow(
315      scoped_ptr<GCDApiFlow::Request>(new PrivetConfirmApiCallFlow(
316          token,
317          base::Bind(&LocalDiscoveryUIHandler::OnConfirmDone,
318                     base::Unretained(this)))));
319  if (!confirm_api_call_flow_) {
320    SendRegisterError();
321    return;
322  }
323  confirm_api_call_flow_->Start();
324}
325
326void LocalDiscoveryUIHandler::OnPrivetRegisterError(
327    PrivetRegisterOperation* operation,
328    const std::string& action,
329    PrivetRegisterOperation::FailureReason reason,
330    int printer_http_code,
331    const base::DictionaryValue* json) {
332  std::string error;
333
334  if (reason == PrivetRegisterOperation::FAILURE_JSON_ERROR &&
335      json->GetString(kPrivetKeyError, &error)) {
336    if (error == kPrivetErrorTimeout) {
337        web_ui()->CallJavascriptFunction(
338            "local_discovery.onRegistrationTimeout");
339      return;
340    } else if (error == kPrivetErrorCancel) {
341      web_ui()->CallJavascriptFunction(
342            "local_discovery.onRegistrationCanceledPrinter");
343      return;
344    }
345  }
346
347  SendRegisterError();
348}
349
350void LocalDiscoveryUIHandler::OnPrivetRegisterDone(
351    PrivetRegisterOperation* operation,
352    const std::string& device_id) {
353  std::string name = operation->GetHTTPClient()->GetName();
354
355  current_register_operation_.reset();
356  current_http_client_.reset();
357
358  // HACK(noamsml): Generate network traffic so the Windows firewall doesn't
359  // block the printer's announcement.
360  privet_lister_->DiscoverNewDevices(false);
361
362  DeviceDescriptionMap::iterator found = device_descriptions_.find(name);
363
364  if (found == device_descriptions_.end()) {
365    // TODO(noamsml): Handle the case where a printer's record is not present at
366    // the end of registration.
367    SendRegisterError();
368    return;
369  }
370
371  SendRegisterDone(found->first, found->second);
372}
373
374void LocalDiscoveryUIHandler::OnConfirmDone(GCDApiFlow::Status status) {
375  if (status == GCDApiFlow::SUCCESS) {
376    confirm_api_call_flow_.reset();
377    current_register_operation_->CompleteRegistration();
378  } else {
379    SendRegisterError();
380  }
381}
382
383void LocalDiscoveryUIHandler::DeviceChanged(
384    bool added,
385    const std::string& name,
386    const DeviceDescription& description) {
387  device_descriptions_[name] = description;
388
389  base::DictionaryValue info;
390
391  base::StringValue service_key(kKeyPrefixMDns + name);
392
393  if (description.id.empty()) {
394    info.SetString(kDictionaryKeyServiceName, name);
395    info.SetString(kDictionaryKeyDisplayName, description.name);
396    info.SetString(kDictionaryKeyDescription, description.description);
397    info.SetString(kDictionaryKeyType, description.type);
398    info.SetBoolean(kDictionaryKeyIsWifi, false);
399
400    web_ui()->CallJavascriptFunction(
401        "local_discovery.onUnregisteredDeviceUpdate", service_key, info);
402  } else {
403    scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
404
405    web_ui()->CallJavascriptFunction(
406        "local_discovery.onUnregisteredDeviceUpdate", service_key, *null_value);
407  }
408}
409
410void LocalDiscoveryUIHandler::DeviceRemoved(const std::string& name) {
411  device_descriptions_.erase(name);
412  scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
413  base::StringValue name_value(kKeyPrefixMDns + name);
414
415  web_ui()->CallJavascriptFunction("local_discovery.onUnregisteredDeviceUpdate",
416                                   name_value, *null_value);
417}
418
419void LocalDiscoveryUIHandler::DeviceCacheFlushed() {
420  web_ui()->CallJavascriptFunction("local_discovery.onDeviceCacheFlushed");
421  privet_lister_->DiscoverNewDevices(false);
422}
423
424void LocalDiscoveryUIHandler::OnDeviceListReady(
425    const std::vector<Device>& devices) {
426  cloud_devices_.insert(cloud_devices_.end(), devices.begin(), devices.end());
427  ++succeded_list_count_;
428  CheckListingDone();
429}
430
431void LocalDiscoveryUIHandler::OnDeviceListUnavailable() {
432  ++failed_list_count_;
433  CheckListingDone();
434}
435
436void LocalDiscoveryUIHandler::GoogleSigninSucceeded(
437    const std::string& username,
438    const std::string& password) {
439  CheckUserLoggedIn();
440}
441
442void LocalDiscoveryUIHandler::GoogleSignedOut(const std::string& username) {
443  CheckUserLoggedIn();
444}
445
446void LocalDiscoveryUIHandler::SendRegisterError() {
447  web_ui()->CallJavascriptFunction("local_discovery.onRegistrationFailed");
448}
449
450void LocalDiscoveryUIHandler::SendRegisterDone(
451    const std::string& service_name, const DeviceDescription& device) {
452  base::DictionaryValue printer_value;
453
454  printer_value.SetString(kDictionaryKeyID, device.id);
455  printer_value.SetString(kDictionaryKeyDisplayName, device.name);
456  printer_value.SetString(kDictionaryKeyDescription, device.description);
457  printer_value.SetString(kDictionaryKeyServiceName, service_name);
458
459  web_ui()->CallJavascriptFunction("local_discovery.onRegistrationSuccess",
460                                   printer_value);
461}
462
463void LocalDiscoveryUIHandler::SetIsVisible(bool visible) {
464  if (visible != is_visible_) {
465    g_num_visible += visible ? 1 : -1;
466    is_visible_ = visible;
467  }
468}
469
470std::string LocalDiscoveryUIHandler::GetSyncAccount() {
471  Profile* profile = Profile::FromWebUI(web_ui());
472  SigninManagerBase* signin_manager =
473      SigninManagerFactory::GetForProfileIfExists(profile);
474
475  if (!signin_manager) {
476    return "";
477  }
478
479  return signin_manager->GetAuthenticatedUsername();
480}
481
482// TODO(noamsml): Create master object for registration flow.
483void LocalDiscoveryUIHandler::ResetCurrentRegistration() {
484  if (current_register_operation_.get()) {
485    current_register_operation_->Cancel();
486    current_register_operation_.reset();
487  }
488
489  confirm_api_call_flow_.reset();
490  privet_resolution_.reset();
491  current_http_client_.reset();
492}
493
494void LocalDiscoveryUIHandler::CheckUserLoggedIn() {
495  base::FundamentalValue logged_in_value(!GetSyncAccount().empty());
496  web_ui()->CallJavascriptFunction("local_discovery.setUserLoggedIn",
497                                   logged_in_value);
498}
499
500void LocalDiscoveryUIHandler::CheckListingDone() {
501  int started = 0;
502  if (cloud_print_printer_list_)
503    ++started;
504  if (cloud_device_list_)
505    ++started;
506
507  if (started > failed_list_count_ + succeded_list_count_)
508    return;
509
510  if (succeded_list_count_ <= 0) {
511    web_ui()->CallJavascriptFunction(
512        "local_discovery.onCloudDeviceListUnavailable");
513    return;
514  }
515
516  base::ListValue devices_list;
517  std::set<std::string> local_ids;
518
519  for (DeviceDescriptionMap::iterator i = device_descriptions_.begin();
520       i != device_descriptions_.end(); i++) {
521    local_ids.insert(i->second.id);
522  }
523
524  ReadDevicesList(cloud_devices_, local_ids, &devices_list);
525
526  web_ui()->CallJavascriptFunction(
527      "local_discovery.onCloudDeviceListAvailable", devices_list);
528  cloud_print_printer_list_.reset();
529  cloud_device_list_.reset();
530}
531
532scoped_ptr<GCDApiFlow> LocalDiscoveryUIHandler::CreateApiFlow(
533    scoped_ptr<GCDApiFlow::Request> request) {
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 make_scoped_ptr(
546      new GCDApiFlow(profile->GetRequestContext(),
547                     token_service,
548                     signin_manager->GetAuthenticatedAccountId(),
549                     request.Pass()));
550}
551
552#if defined(CLOUD_PRINT_CONNECTOR_UI_AVAILABLE)
553void LocalDiscoveryUIHandler::StartCloudPrintConnector() {
554  Profile* profile = Profile::FromWebUI(web_ui());
555
556  base::Closure cloud_print_callback = base::Bind(
557      &LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged,
558          base::Unretained(this));
559
560  if (cloud_print_connector_email_.GetPrefName().empty()) {
561    cloud_print_connector_email_.Init(
562        prefs::kCloudPrintEmail, profile->GetPrefs(), cloud_print_callback);
563  }
564
565  if (cloud_print_connector_enabled_.GetPrefName().empty()) {
566    cloud_print_connector_enabled_.Init(
567        prefs::kCloudPrintProxyEnabled, profile->GetPrefs(),
568        cloud_print_callback);
569  }
570
571  if (cloud_print_connector_ui_enabled_) {
572    SetupCloudPrintConnectorSection();
573    RefreshCloudPrintStatusFromService();
574  } else {
575    RemoveCloudPrintConnectorSection();
576  }
577}
578
579void LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged() {
580  if (cloud_print_connector_ui_enabled_)
581    SetupCloudPrintConnectorSection();
582}
583
584void LocalDiscoveryUIHandler::ShowCloudPrintSetupDialog(
585    const base::ListValue* args) {
586  content::RecordAction(
587      base::UserMetricsAction("Options_EnableCloudPrintProxy"));
588  // Open the connector enable page in the current tab.
589  Profile* profile = Profile::FromWebUI(web_ui());
590  content::OpenURLParams params(
591      cloud_devices::GetCloudPrintEnableURL(
592          CloudPrintProxyServiceFactory::GetForProfile(profile)->proxy_id()),
593      content::Referrer(),
594      CURRENT_TAB,
595      content::PAGE_TRANSITION_LINK,
596      false);
597  web_ui()->GetWebContents()->OpenURL(params);
598}
599
600void LocalDiscoveryUIHandler::HandleDisableCloudPrintConnector(
601    const base::ListValue* args) {
602  content::RecordAction(
603      base::UserMetricsAction("Options_DisableCloudPrintProxy"));
604  CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
605      DisableForUser();
606}
607
608void LocalDiscoveryUIHandler::SetupCloudPrintConnectorSection() {
609  Profile* profile = Profile::FromWebUI(web_ui());
610
611  if (!CloudPrintProxyServiceFactory::GetForProfile(profile)) {
612    cloud_print_connector_ui_enabled_ = false;
613    RemoveCloudPrintConnectorSection();
614    return;
615  }
616
617  bool cloud_print_connector_allowed =
618      !cloud_print_connector_enabled_.IsManaged() ||
619      cloud_print_connector_enabled_.GetValue();
620  base::FundamentalValue allowed(cloud_print_connector_allowed);
621
622  std::string email;
623  if (profile->GetPrefs()->HasPrefPath(prefs::kCloudPrintEmail) &&
624      cloud_print_connector_allowed) {
625    email = profile->GetPrefs()->GetString(prefs::kCloudPrintEmail);
626  }
627  base::FundamentalValue disabled(email.empty());
628
629  base::string16 label_str;
630  if (email.empty()) {
631    label_str = l10n_util::GetStringFUTF16(
632        IDS_LOCAL_DISCOVERY_CLOUD_PRINT_CONNECTOR_DISABLED_LABEL,
633        l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT));
634  } else {
635    label_str = l10n_util::GetStringFUTF16(
636        IDS_OPTIONS_CLOUD_PRINT_CONNECTOR_ENABLED_LABEL,
637        l10n_util::GetStringUTF16(IDS_GOOGLE_CLOUD_PRINT),
638        base::UTF8ToUTF16(email));
639  }
640  base::StringValue label(label_str);
641
642  web_ui()->CallJavascriptFunction(
643      "local_discovery.setupCloudPrintConnectorSection", disabled, label,
644      allowed);
645}
646
647void LocalDiscoveryUIHandler::RemoveCloudPrintConnectorSection() {
648  web_ui()->CallJavascriptFunction(
649      "local_discovery.removeCloudPrintConnectorSection");
650}
651
652void LocalDiscoveryUIHandler::RefreshCloudPrintStatusFromService() {
653  if (cloud_print_connector_ui_enabled_)
654    CloudPrintProxyServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()))->
655        RefreshStatusFromService();
656}
657
658#endif // cloud print connector option stuff
659
660#if defined(ENABLE_WIFI_BOOTSTRAPPING)
661
662void LocalDiscoveryUIHandler::StartWifiBootstrapping() {
663  // Since LocalDiscoveryUIHandler isn't destroyed every time the page is
664  // refreshed, reset bootstrapping_device_lister_ so it's destoryed before
665  // wifi_manager_ is.
666  bootstrapping_device_lister_.reset();
667
668  wifi_manager_ = wifi::WifiManager::Create();
669  bootstrapping_device_lister_.reset(new wifi::BootstrappingDeviceLister(
670      wifi_manager_.get(),
671      base::Bind(&LocalDiscoveryUIHandler::OnBootstrappingDeviceChanged,
672                 base::Unretained(this))));
673
674  wifi_manager_->Start();
675  bootstrapping_device_lister_->Start();
676  wifi_manager_->RequestScan();
677}
678
679void LocalDiscoveryUIHandler::OnBootstrappingDeviceChanged(
680    bool available,
681    const wifi::BootstrappingDeviceDescription& description) {
682  base::DictionaryValue info;
683
684  base::StringValue service_key(kKeyPrefixWifi + description.device_ssid);
685
686  if (available) {
687    info.SetString(kDictionaryKeyServiceName, description.device_ssid);
688    info.SetString(kDictionaryKeyDisplayName, description.device_name);
689    info.SetString(kDictionaryKeyDescription, std::string());
690    info.SetString(kDictionaryKeyType, description.device_kind);
691    info.SetBoolean(kDictionaryKeyIsWifi, true);
692
693    web_ui()->CallJavascriptFunction(
694        "local_discovery.onUnregisteredDeviceUpdate", service_key, info);
695  } else {
696    scoped_ptr<base::Value> null_value(base::Value::CreateNullValue());
697
698    web_ui()->CallJavascriptFunction(
699        "local_discovery.onUnregisteredDeviceUpdate", service_key, *null_value);
700  }
701}
702
703#endif  // ENABLE_WIFI_BOOTSTRAPPING
704
705}  // namespace local_discovery
706