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