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 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 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 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 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 133 bool LocalDiscoveryUIHandler::GetHasVisible() { 134 return g_num_visible != 0; 135 } 136 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 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 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 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 250 void LocalDiscoveryUIHandler::HandleConfirmCode(const base::ListValue* args) { 251 device_code_callback_.Run(true); 252 } 253 254 void LocalDiscoveryUIHandler::HandleCancelRegistration( 255 const base::ListValue* args) { 256 ResetCurrentRegistration(); 257 } 258 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 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 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 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 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 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 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 384 void LocalDiscoveryUIHandler::GetWiFiCredentials( 385 const CredentialsCallback& callback) { 386 callback.Run("", ""); 387 } 388 389 void LocalDiscoveryUIHandler::SwitchToSetupWiFi( 390 const ResultCallback& callback) { 391 callback.Run(true); 392 } 393 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 403 void LocalDiscoveryUIHandler::RestoreWifi(const ResultCallback& callback) { 404 callback.Run(true); 405 } 406 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 415 void LocalDiscoveryUIHandler::OnSetupError() { 416 ResetCurrentRegistration(); 417 SendRegisterError(); 418 } 419 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 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 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 465 void LocalDiscoveryUIHandler::DeviceCacheFlushed() { 466 web_ui()->CallJavascriptFunction("local_discovery.onDeviceCacheFlushed"); 467 privet_lister_->DiscoverNewDevices(false); 468 } 469 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 477 void LocalDiscoveryUIHandler::OnDeviceListUnavailable() { 478 ++failed_list_count_; 479 CheckListingDone(); 480 } 481 482 void LocalDiscoveryUIHandler::GoogleSigninSucceeded( 483 const std::string& account_id, 484 const std::string& username, 485 const std::string& password) { 486 CheckUserLoggedIn(); 487 } 488 489 void LocalDiscoveryUIHandler::GoogleSignedOut(const std::string& account_id, 490 const std::string& username) { 491 CheckUserLoggedIn(); 492 } 493 494 void LocalDiscoveryUIHandler::SendRegisterError() { 495 web_ui()->CallJavascriptFunction("local_discovery.onRegistrationFailed"); 496 } 497 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 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 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. 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 559 void LocalDiscoveryUIHandler::PrivetClientToV3( 560 const PrivetClientCallback& callback, 561 scoped_ptr<PrivetHTTPClient> client) { 562 callback.Run(client.Pass()); 563 } 564 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 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 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 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 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) 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 673 void LocalDiscoveryUIHandler::OnCloudPrintPrefsChanged() { 674 if (cloud_print_connector_ui_enabled_) 675 SetupCloudPrintConnectorSection(); 676 } 677 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 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 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 741 void LocalDiscoveryUIHandler::RemoveCloudPrintConnectorSection() { 742 web_ui()->CallJavascriptFunction( 743 "local_discovery.removeCloudPrintConnectorSection"); 744 } 745 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 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 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