local_discovery_ui_handler.cc revision f8ee788a64d60abd8f2d742a5fdedde054ecd910
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_ = 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
209void 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
216void 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
231void LocalDiscoveryUIHandler::HandleCancelRegistration(
232    const base::ListValue* args) {
233  ResetCurrentRegistration();
234}
235
236void 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
259void 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
274void 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
288void 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
304void 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
327void 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
351void 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
375void 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
384void 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
411void 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
420void LocalDiscoveryUIHandler::DeviceCacheFlushed() {
421  web_ui()->CallJavascriptFunction("local_discovery.onDeviceCacheFlushed");
422  privet_lister_->DiscoverNewDevices(false);
423}
424
425void 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
432void LocalDiscoveryUIHandler::OnDeviceListUnavailable() {
433  ++failed_list_count_;
434  CheckListingDone();
435}
436
437void LocalDiscoveryUIHandler::GoogleSigninSucceeded(
438    const std::string& username,
439    const std::string& password) {
440  CheckUserLoggedIn();
441}
442
443void LocalDiscoveryUIHandler::GoogleSignedOut(const std::string& username) {
444  CheckUserLoggedIn();
445}
446
447void LocalDiscoveryUIHandler::SendRegisterError() {
448  web_ui()->CallJavascriptFunction("local_discovery.onRegistrationFailed");
449}
450
451void 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
464void LocalDiscoveryUIHandler::SetIsVisible(bool visible) {
465  if (visible != is_visible_) {
466    g_num_visible += visible ? 1 : -1;
467    is_visible_ = visible;
468  }
469}
470
471std::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.
484void 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
495void LocalDiscoveryUIHandler::CheckUserLoggedIn() {
496  base::FundamentalValue logged_in_value(!GetSyncAccount().empty());
497  web_ui()->CallJavascriptFunction("local_discovery.setUserLoggedIn",
498                                   logged_in_value);
499}
500
501void 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
533scoped_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)
551void 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
577void LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged() {
578  if (cloud_print_connector_ui_enabled_)
579    SetupCloudPrintConnectorSection();
580}
581
582void 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
598void 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
606void 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
645void LocalDiscoveryUIHandler::RemoveCloudPrintConnectorSection() {
646  web_ui()->CallJavascriptFunction(
647      "local_discovery.removeCloudPrintConnectorSection");
648}
649
650void 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
660void 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
677void 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