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