1 // Copyright (c) 2012 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/chromeos/sim_unlock_ui.h" 6 7 #include <string> 8 9 #include "base/basictypes.h" 10 #include "base/bind.h" 11 #include "base/bind_helpers.h" 12 #include "base/location.h" 13 #include "base/logging.h" 14 #include "base/memory/ref_counted_memory.h" 15 #include "base/memory/weak_ptr.h" 16 #include "base/message_loop/message_loop.h" 17 #include "base/strings/string_piece.h" 18 #include "base/values.h" 19 #include "chrome/browser/chrome_notification_types.h" 20 #include "chrome/browser/chromeos/sim_dialog_delegate.h" 21 #include "chrome/browser/profiles/profile.h" 22 #include "chrome/common/url_constants.h" 23 #include "chromeos/network/device_state.h" 24 #include "chromeos/network/network_device_handler.h" 25 #include "chromeos/network/network_event_log.h" 26 #include "chromeos/network/network_state_handler.h" 27 #include "chromeos/network/network_state_handler_observer.h" 28 #include "content/public/browser/browser_thread.h" 29 #include "content/public/browser/notification_service.h" 30 #include "content/public/browser/url_data_source.h" 31 #include "content/public/browser/web_contents.h" 32 #include "content/public/browser/web_ui.h" 33 #include "content/public/browser/web_ui_message_handler.h" 34 #include "grit/browser_resources.h" 35 #include "grit/generated_resources.h" 36 #include "third_party/cros_system_api/dbus/service_constants.h" 37 #include "ui/base/l10n/l10n_util.h" 38 #include "ui/base/resource/resource_bundle.h" 39 #include "ui/webui/jstemplate_builder.h" 40 #include "ui/webui/web_ui_util.h" 41 42 using content::BrowserThread; 43 using content::WebContents; 44 using content::WebUIMessageHandler; 45 46 namespace { 47 48 // JS API callbacks names. 49 const char kJsApiCancel[] = "cancel"; 50 const char kJsApiChangePinCode[] = "changePinCode"; 51 const char kJsApiEnterPinCode[] = "enterPinCode"; 52 const char kJsApiEnterPukCode[] = "enterPukCode"; 53 const char kJsApiProceedToPukInput[] = "proceedToPukInput"; 54 const char kJsApiSimStatusInitialize[] = "simStatusInitialize"; 55 56 // Page JS API function names. 57 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged"; 58 59 // SIM state variables which are passed to the page. 60 const char kState[] = "state"; 61 const char kError[] = "error"; 62 const char kTriesLeft[] = "tries"; 63 64 // Error constants, passed to the page. 65 const char kErrorPin[] = "incorrectPin"; 66 const char kErrorPuk[] = "incorrectPuk"; 67 const char kErrorOk[] = "ok"; 68 69 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() { 70 return chromeos::NetworkHandler::Get()->network_device_handler(); 71 } 72 73 chromeos::NetworkStateHandler* GetNetworkStateHandler() { 74 return chromeos::NetworkHandler::Get()->network_state_handler(); 75 } 76 77 } // namespace 78 79 namespace chromeos { 80 81 class SimUnlockUIHTMLSource : public content::URLDataSource { 82 public: 83 SimUnlockUIHTMLSource(); 84 85 // content::URLDataSource implementation. 86 virtual std::string GetSource() const OVERRIDE; 87 virtual void StartDataRequest( 88 const std::string& path, 89 int render_process_id, 90 int render_view_id, 91 const content::URLDataSource::GotDataCallback& callback) OVERRIDE; 92 virtual std::string GetMimeType(const std::string&) const OVERRIDE { 93 return "text/html"; 94 } 95 virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE { 96 return false; 97 } 98 99 private: 100 virtual ~SimUnlockUIHTMLSource() {} 101 102 std::string service_path_; 103 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource); 104 }; 105 106 // The handler for Javascript messages related to the "sim-unlock" view. 107 class SimUnlockHandler : public WebUIMessageHandler, 108 public base::SupportsWeakPtr<SimUnlockHandler>, 109 public NetworkStateHandlerObserver { 110 public: 111 SimUnlockHandler(); 112 virtual ~SimUnlockHandler(); 113 114 // WebUIMessageHandler implementation. 115 virtual void RegisterMessages() OVERRIDE; 116 117 // NetworkStateHandlerObserver implementation. 118 virtual void DeviceListChanged() OVERRIDE; 119 120 private: 121 // Should keep this state enum in sync with similar one in JS code. 122 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user 123 // for PIN input because PinRequired preference change was requested. 124 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN 125 // and new PIN to change it. 126 typedef enum SimUnlockState { 127 SIM_UNLOCK_LOADING = -1, 128 SIM_ABSENT_NOT_LOCKED = 0, 129 SIM_NOT_LOCKED_ASK_PIN = 1, 130 SIM_NOT_LOCKED_CHANGE_PIN = 2, 131 SIM_LOCKED_PIN = 3, 132 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4, 133 SIM_LOCKED_PUK = 5, 134 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6, 135 SIM_DISABLED = 7, 136 } SimUnlockState; 137 138 // Type of the SIM unlock code. 139 enum SimUnlockCode { 140 CODE_PIN, 141 CODE_PUK 142 }; 143 144 enum PinOperationError { 145 PIN_ERROR_NONE = 0, 146 PIN_ERROR_UNKNOWN = 1, 147 PIN_ERROR_INCORRECT_CODE = 2, 148 PIN_ERROR_BLOCKED = 3 149 }; 150 151 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { 152 public: 153 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler) 154 : handler_(handler), 155 code_type_() { 156 } 157 158 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler, 159 const std::string& code, 160 SimUnlockCode code_type) 161 : handler_(handler), 162 code_(code), 163 code_type_(code_type) { 164 } 165 166 void HandleCancel() { 167 if (handler_) 168 handler_->CancelDialog(); 169 } 170 171 void HandleEnterCode() { 172 if (handler_) 173 handler_->EnterCode(code_, code_type_); 174 } 175 176 void HandleInitialize() { 177 if (handler_) 178 handler_->InitializeSimStatus(); 179 } 180 181 void HandleProceedToPukInput() { 182 if (handler_) 183 handler_->ProceedToPukInput(); 184 } 185 186 private: 187 friend class base::RefCountedThreadSafe<TaskProxy>; 188 189 ~TaskProxy() {} 190 191 base::WeakPtr<SimUnlockHandler> handler_; 192 193 // Pending code input (PIN/PUK). 194 std::string code_; 195 196 // Pending code type. 197 SimUnlockCode code_type_; 198 199 DISALLOW_COPY_AND_ASSIGN(TaskProxy); 200 }; 201 202 // Returns the cellular device that this dialog currently corresponds to. 203 const DeviceState* GetCellularDevice(); 204 205 // Processing for the cases when dialog was cancelled. 206 void CancelDialog(); 207 208 // Pass PIN/PUK code to shill and check status. 209 void EnterCode(const std::string& code, SimUnlockCode code_type); 210 211 // Methods to invoke shill PIN/PUK D-Bus operations. 212 void ChangeRequirePin(bool require_pin, const std::string& pin); 213 void EnterPin(const std::string& pin); 214 void ChangePin(const std::string& old_pin, const std::string& new_pin); 215 void UnblockPin(const std::string& puk, const std::string& new_pin); 216 void PinOperationSuccessCallback(const std::string& operation_name); 217 void PinOperationErrorCallback(const std::string& operation_name, 218 const std::string& error_name, 219 scoped_ptr<base::DictionaryValue> error_data); 220 221 // Called when an asynchronous PIN operation has completed. 222 void OnPinOperationCompleted(PinOperationError error); 223 224 // Single handler for PIN/PUK code operations. 225 void HandleEnterCode(SimUnlockCode code_type, const std::string& code); 226 227 // Handlers for JS WebUI messages. 228 void HandleCancel(const ListValue* args); 229 void HandleChangePinCode(const ListValue* args); 230 void HandleEnterPinCode(const ListValue* args); 231 void HandleEnterPukCode(const ListValue* args); 232 void HandleProceedToPukInput(const ListValue* args); 233 void HandleSimStatusInitialize(const ListValue* args); 234 235 // Initialize current SIM card status, passes that to page. 236 void InitializeSimStatus(); 237 238 // Notifies SIM Security tab handler that RequirePin preference change 239 // has been ended (either updated or cancelled). 240 void NotifyOnRequirePinChangeEnded(bool new_value); 241 242 // Notifies observers that the EnterPin or EnterPuk dialog has been 243 // completed (either cancelled or with entry of PIN/PUK). 244 void NotifyOnEnterPinEnded(bool cancelled); 245 246 // Checks whether SIM card is in PUK locked state and proceeds to PUK input. 247 void ProceedToPukInput(); 248 249 // Processes current SIM card state and update internal state/page. 250 void ProcessSimCardState(const DeviceState* cellular); 251 252 // Updates page with the current state/SIM card info/error. 253 void UpdatePage(const DeviceState* cellular, const std::string& error_msg); 254 255 // Dialog internal state. 256 SimUnlockState state_; 257 258 // Path of the Cellular device that we monitor property updates from. 259 std::string cellular_device_path_; 260 261 // Type of the dialog: generic unlock/change pin/change PinRequire. 262 SimDialogDelegate::SimDialogMode dialog_mode_; 263 264 // New PIN value for the case when we unblock SIM card or change PIN. 265 std::string new_pin_; 266 267 // The initial lock type value, used to observe changes to lock status; 268 std::string sim_lock_type_; 269 270 // True if there's a pending PIN operation. 271 // That means that SIM lock state change will be received 2 times: 272 // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted. 273 // First one should be ignored. 274 bool pending_pin_operation_; 275 276 base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_; 277 278 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler); 279 }; 280 281 // SimUnlockUIHTMLSource ------------------------------------------------------- 282 283 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() { 284 } 285 286 std::string SimUnlockUIHTMLSource::GetSource() const { 287 return chrome::kChromeUISimUnlockHost; 288 } 289 290 void SimUnlockUIHTMLSource::StartDataRequest( 291 const std::string& path, 292 int render_process_id, 293 int render_view_id, 294 const content::URLDataSource::GotDataCallback& callback) { 295 DictionaryValue strings; 296 strings.SetString("title", 297 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 298 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK)); 299 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); 300 strings.SetString("enterPinTitle", 301 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 302 strings.SetString("enterPinMessage", 303 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE)); 304 strings.SetString("enterPinTriesMessage", 305 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE)); 306 strings.SetString("incorrectPinTriesMessage", 307 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE)); 308 strings.SetString("incorrectPinTitle", 309 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE)); 310 // TODO(nkostylev): Pass carrier name if we know that. 311 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16( 312 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE, 313 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 314 strings.SetString("enterPukButton", 315 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON)); 316 strings.SetString("enterPukTitle", 317 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE)); 318 strings.SetString("enterPukWarning", 319 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING)); 320 // TODO(nkostylev): Pass carrier name if we know that. 321 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16( 322 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE, 323 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 324 strings.SetString("choosePinTitle", 325 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE)); 326 strings.SetString("choosePinMessage", 327 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE)); 328 strings.SetString("newPin", l10n_util::GetStringUTF16( 329 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN)); 330 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16( 331 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN)); 332 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16( 333 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR)); 334 strings.SetString("noPukTriesLeft", 335 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE)); 336 strings.SetString("simDisabledTitle", 337 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE)); 338 strings.SetString("simDisabledMessage", 339 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE)); 340 341 strings.SetString("changePinTitle", l10n_util::GetStringUTF16( 342 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE)); 343 strings.SetString("changePinMessage", l10n_util::GetStringUTF16( 344 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE)); 345 strings.SetString("oldPin", l10n_util::GetStringUTF16( 346 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN)); 347 348 webui::SetFontAndTextDirection(&strings); 349 350 static const base::StringPiece html( 351 ResourceBundle::GetSharedInstance().GetRawDataResource( 352 IDR_SIM_UNLOCK_HTML)); 353 354 std::string full_html = webui::GetI18nTemplateHtml(html, &strings); 355 356 callback.Run(base::RefCountedString::TakeString(&full_html)); 357 } 358 359 // SimUnlockHandler ------------------------------------------------------------ 360 361 SimUnlockHandler::SimUnlockHandler() 362 : state_(SIM_UNLOCK_LOADING), 363 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK), 364 pending_pin_operation_(false), 365 weak_ptr_factory_(this) { 366 if (GetNetworkStateHandler()->GetTechnologyState(flimflam::kTypeCellular) 367 != NetworkStateHandler::TECHNOLOGY_UNAVAILABLE) 368 GetNetworkStateHandler()->AddObserver(this, FROM_HERE); 369 } 370 371 SimUnlockHandler::~SimUnlockHandler() { 372 GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE); 373 } 374 375 void SimUnlockHandler::RegisterMessages() { 376 web_ui()->RegisterMessageCallback(kJsApiCancel, 377 base::Bind(&SimUnlockHandler::HandleCancel, 378 base::Unretained(this))); 379 web_ui()->RegisterMessageCallback(kJsApiChangePinCode, 380 base::Bind(&SimUnlockHandler::HandleChangePinCode, 381 base::Unretained(this))); 382 web_ui()->RegisterMessageCallback(kJsApiEnterPinCode, 383 base::Bind(&SimUnlockHandler::HandleEnterPinCode, 384 base::Unretained(this))); 385 web_ui()->RegisterMessageCallback(kJsApiEnterPukCode, 386 base::Bind(&SimUnlockHandler::HandleEnterPukCode, 387 base::Unretained(this))); 388 web_ui()->RegisterMessageCallback(kJsApiProceedToPukInput, 389 base::Bind(&SimUnlockHandler::HandleProceedToPukInput, 390 base::Unretained(this))); 391 web_ui()->RegisterMessageCallback(kJsApiSimStatusInitialize, 392 base::Bind(&SimUnlockHandler::HandleSimStatusInitialize, 393 base::Unretained(this))); 394 } 395 396 void SimUnlockHandler::DeviceListChanged() { 397 const DeviceState* cellular_device = GetCellularDevice(); 398 if (!cellular_device) { 399 LOG(WARNING) << "Cellular device with path '" << cellular_device_path_ 400 << "' disappeared."; 401 ProcessSimCardState(NULL); 402 return; 403 } 404 405 // Process the SIM card state only if the lock state changed. 406 if (cellular_device->sim_lock_type() == sim_lock_type_) 407 return; 408 409 sim_lock_type_ = cellular_device->sim_lock_type(); 410 uint32 retries_left = cellular_device->sim_retries_left(); 411 VLOG(1) << "OnNetworkDeviceSimLockChanged, lock: " << sim_lock_type_ 412 << ", retries: " << retries_left; 413 // There's a pending PIN operation. 414 // Wait for it to finish and refresh state then. 415 if (!pending_pin_operation_) 416 ProcessSimCardState(cellular_device); 417 } 418 419 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) { 420 pending_pin_operation_ = false; 421 VLOG(1) << "OnPinOperationCompleted, error: " << error; 422 const DeviceState* cellular = GetCellularDevice(); 423 if (!cellular) { 424 VLOG(1) << "Cellular device disappeared. Dismissing dialog."; 425 ProcessSimCardState(NULL); 426 return; 427 } 428 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) { 429 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 430 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF); 431 // Async change RequirePin operation has finished OK. 432 NotifyOnRequirePinChangeEnded( 433 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON); 434 // Dialog will close itself. 435 state_ = SIM_ABSENT_NOT_LOCKED; 436 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) { 437 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN); 438 // Dialog will close itself. 439 state_ = SIM_ABSENT_NOT_LOCKED; 440 } 441 // If previous EnterPIN was last PIN attempt and SIMLock state was already 442 // processed by OnNetworkDeviceChanged, let dialog stay on 443 // NO_PIN_RETRIES_LEFT step. 444 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED)) 445 ProcessSimCardState(cellular); 446 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK && 447 state_ == SIM_ABSENT_NOT_LOCKED) 448 NotifyOnEnterPinEnded(false); 449 } 450 451 const DeviceState* SimUnlockHandler::GetCellularDevice() { 452 return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_); 453 } 454 455 void SimUnlockHandler::CancelDialog() { 456 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 457 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 458 // When async change RequirePin operation is performed, 459 // dialog UI controls such as Cancel button are disabled. 460 // If dialog was cancelled that means RequirePin preference hasn't been 461 // changed and is not in process of changing at the moment. 462 NotifyOnRequirePinChangeEnded( 463 !(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON)); 464 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK) { 465 NotifyOnEnterPinEnded(true); 466 } 467 } 468 469 void SimUnlockHandler::EnterCode(const std::string& code, 470 SimUnlockCode code_type) { 471 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 472 473 pending_pin_operation_ = true; 474 475 switch (code_type) { 476 case CODE_PIN: 477 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 478 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 479 if (!sim_lock_type_.empty()) { 480 // If SIM is locked/absent, change RequirePin UI is not accessible. 481 NOTREACHED() << 482 "Changing RequirePin pref on locked / uninitialized SIM."; 483 } 484 ChangeRequirePin( 485 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON, 486 code); 487 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) { 488 if (!sim_lock_type_.empty()) { 489 // If SIM is locked/absent, changing PIN UI is not accessible. 490 NOTREACHED() << "Changing PIN on locked / uninitialized SIM."; 491 } 492 ChangePin(code, new_pin_); 493 } else { 494 EnterPin(code); 495 } 496 break; 497 case CODE_PUK: 498 DCHECK(!new_pin_.empty()); 499 UnblockPin(code, new_pin_); 500 break; 501 } 502 } 503 504 void SimUnlockHandler::ChangeRequirePin(bool require_pin, 505 const std::string& pin) { 506 const DeviceState* cellular = GetCellularDevice(); 507 if (!cellular) { 508 NOTREACHED() << "Calling RequirePin method w/o cellular device."; 509 return; 510 } 511 std::string operation_name = "ChangeRequirePin"; 512 NET_LOG_USER(operation_name, cellular->path()); 513 GetNetworkDeviceHandler()->RequirePin( 514 cellular->path(), 515 require_pin, 516 pin, 517 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback, 518 weak_ptr_factory_.GetWeakPtr(), 519 operation_name), 520 base::Bind(&SimUnlockHandler::PinOperationErrorCallback, 521 weak_ptr_factory_.GetWeakPtr(), 522 operation_name)); 523 } 524 525 void SimUnlockHandler::EnterPin(const std::string& pin) { 526 const DeviceState* cellular = GetCellularDevice(); 527 if (!cellular) { 528 NOTREACHED() << "Calling RequirePin method w/o cellular device."; 529 return; 530 } 531 std::string operation_name = "EnterPin"; 532 NET_LOG_USER(operation_name, cellular->path()); 533 GetNetworkDeviceHandler()->EnterPin( 534 cellular->path(), 535 pin, 536 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback, 537 weak_ptr_factory_.GetWeakPtr(), 538 operation_name), 539 base::Bind(&SimUnlockHandler::PinOperationErrorCallback, 540 weak_ptr_factory_.GetWeakPtr(), 541 operation_name)); 542 } 543 544 void SimUnlockHandler::ChangePin(const std::string& old_pin, 545 const std::string& new_pin) { 546 const DeviceState* cellular = GetCellularDevice(); 547 if (!cellular) { 548 NOTREACHED() << "Calling RequirePin method w/o cellular device."; 549 return; 550 } 551 std::string operation_name = "ChangePin"; 552 NET_LOG_USER(operation_name, cellular->path()); 553 GetNetworkDeviceHandler()->ChangePin( 554 cellular->path(), 555 old_pin, 556 new_pin, 557 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback, 558 weak_ptr_factory_.GetWeakPtr(), 559 operation_name), 560 base::Bind(&SimUnlockHandler::PinOperationErrorCallback, 561 weak_ptr_factory_.GetWeakPtr(), 562 operation_name)); 563 } 564 565 void SimUnlockHandler::UnblockPin(const std::string& puk, 566 const std::string& new_pin) { 567 const DeviceState* cellular = GetCellularDevice(); 568 if (!cellular) { 569 NOTREACHED() << "Calling RequirePin method w/o cellular device."; 570 return; 571 } 572 std::string operation_name = "UnblockPin"; 573 NET_LOG_USER(operation_name, cellular->path()); 574 GetNetworkDeviceHandler()->UnblockPin( 575 cellular->path(), 576 puk, 577 new_pin, 578 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback, 579 weak_ptr_factory_.GetWeakPtr(), 580 operation_name), 581 base::Bind(&SimUnlockHandler::PinOperationErrorCallback, 582 weak_ptr_factory_.GetWeakPtr(), 583 operation_name)); 584 } 585 586 void SimUnlockHandler::PinOperationSuccessCallback( 587 const std::string& operation_name) { 588 NET_LOG_DEBUG("Pin operation successful.", operation_name); 589 OnPinOperationCompleted(PIN_ERROR_NONE); 590 } 591 592 void SimUnlockHandler::PinOperationErrorCallback( 593 const std::string& operation_name, 594 const std::string& error_name, 595 scoped_ptr<base::DictionaryValue> error_data) { 596 NET_LOG_ERROR("Pin operation failed: " + error_name, operation_name); 597 PinOperationError pin_error; 598 if (error_name == NetworkDeviceHandler::kErrorIncorrectPin || 599 error_name == NetworkDeviceHandler::kErrorPinRequired) 600 pin_error = PIN_ERROR_INCORRECT_CODE; 601 else if (error_name == NetworkDeviceHandler::kErrorPinBlocked) 602 pin_error = PIN_ERROR_BLOCKED; 603 else 604 pin_error = PIN_ERROR_UNKNOWN; 605 OnPinOperationCompleted(pin_error); 606 } 607 608 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) { 609 content::NotificationService::current()->Notify( 610 chrome::NOTIFICATION_ENTER_PIN_ENDED, 611 content::NotificationService::AllSources(), 612 content::Details<bool>(&cancelled)); 613 } 614 615 void SimUnlockHandler::NotifyOnRequirePinChangeEnded(bool new_value) { 616 content::NotificationService::current()->Notify( 617 chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED, 618 content::NotificationService::AllSources(), 619 content::Details<bool>(&new_value)); 620 } 621 622 void SimUnlockHandler::HandleCancel(const ListValue* args) { 623 const size_t kEnterCodeParamCount = 0; 624 if (args->GetSize() != kEnterCodeParamCount) { 625 NOTREACHED(); 626 return; 627 } 628 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 629 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 630 base::Bind(&TaskProxy::HandleCancel, task.get())); 631 } 632 633 void SimUnlockHandler::HandleChangePinCode(const ListValue* args) { 634 const size_t kChangePinParamCount = 2; 635 std::string pin; 636 std::string new_pin; 637 if (args->GetSize() != kChangePinParamCount || 638 !args->GetString(0, &pin) || 639 !args->GetString(1, &new_pin)) { 640 NOTREACHED(); 641 return; 642 } 643 new_pin_ = new_pin; 644 HandleEnterCode(CODE_PIN, pin); 645 } 646 647 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type, 648 const std::string& code) { 649 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type); 650 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 651 base::Bind(&TaskProxy::HandleEnterCode, task.get())); 652 } 653 654 void SimUnlockHandler::HandleEnterPinCode(const ListValue* args) { 655 const size_t kEnterPinParamCount = 1; 656 std::string pin; 657 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) { 658 NOTREACHED(); 659 return; 660 } 661 HandleEnterCode(CODE_PIN, pin); 662 } 663 664 void SimUnlockHandler::HandleEnterPukCode(const ListValue* args) { 665 const size_t kEnterPukParamCount = 2; 666 std::string puk; 667 std::string new_pin; 668 if (args->GetSize() != kEnterPukParamCount || 669 !args->GetString(0, &puk) || 670 !args->GetString(1, &new_pin)) { 671 NOTREACHED(); 672 return; 673 } 674 new_pin_ = new_pin; 675 HandleEnterCode(CODE_PUK, puk); 676 } 677 678 void SimUnlockHandler::HandleProceedToPukInput(const ListValue* args) { 679 const size_t kProceedToPukInputParamCount = 0; 680 if (args->GetSize() != kProceedToPukInputParamCount) { 681 NOTREACHED(); 682 return; 683 } 684 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 685 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 686 base::Bind(&TaskProxy::HandleProceedToPukInput, task.get())); 687 } 688 689 void SimUnlockHandler::HandleSimStatusInitialize(const ListValue* args) { 690 const size_t kSimStatusInitializeParamCount = 1; 691 double mode; 692 if (args->GetSize() != kSimStatusInitializeParamCount || 693 !args->GetDouble(0, &mode)) { 694 NOTREACHED(); 695 return; 696 } 697 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode); 698 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_; 699 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 700 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 701 base::Bind(&TaskProxy::HandleInitialize, task.get())); 702 } 703 704 void SimUnlockHandler::InitializeSimStatus() { 705 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 706 // TODO(armansito): For now, we're initializing the device path to the first 707 // available cellular device. We should try to obtain a specific device here, 708 // as there can be multiple cellular devices present. 709 const DeviceState* cellular_device = GetNetworkStateHandler()-> 710 GetDeviceStateByType(flimflam::kTypeCellular); 711 if (cellular_device) { 712 cellular_device_path_ = cellular_device->path(); 713 sim_lock_type_ = cellular_device->sim_lock_type(); 714 } 715 ProcessSimCardState(cellular_device); 716 } 717 718 void SimUnlockHandler::ProceedToPukInput() { 719 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 720 ProcessSimCardState(GetCellularDevice()); 721 } 722 723 void SimUnlockHandler::ProcessSimCardState( 724 const DeviceState* cellular) { 725 std::string error_msg; 726 if (cellular) { 727 uint32 retries_left = cellular->sim_retries_left(); 728 VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_ 729 << " retries: " << retries_left; 730 switch (state_) { 731 case SIM_UNLOCK_LOADING: 732 if (sim_lock_type_ == flimflam::kSIMLockPin) { 733 state_ = SIM_LOCKED_PIN; 734 } else if (sim_lock_type_ == flimflam::kSIMLockPuk) { 735 if (retries_left > 0) 736 state_ = SIM_LOCKED_PUK; 737 else 738 state_ = SIM_DISABLED; 739 } else if (sim_lock_type_.empty()) { 740 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 741 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 742 state_ = SIM_NOT_LOCKED_ASK_PIN; 743 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) { 744 state_ = SIM_NOT_LOCKED_CHANGE_PIN; 745 } else { 746 state_ = SIM_ABSENT_NOT_LOCKED; 747 } 748 } else { 749 // SIM_UNKNOWN: when SIM status is not initialized (should not happen, 750 // since this UI is accessible when SIM is initialized) 751 // or SIM card is absent. In latter case just close dialog. 752 state_ = SIM_ABSENT_NOT_LOCKED; 753 } 754 break; 755 case SIM_ABSENT_NOT_LOCKED: 756 // Dialog will close itself in this case. 757 break; 758 case SIM_NOT_LOCKED_ASK_PIN: 759 case SIM_NOT_LOCKED_CHANGE_PIN: 760 // We always start in these states when SIM is unlocked. 761 // So if we get here while still being UNLOCKED, 762 // that means entered PIN was incorrect. 763 if (sim_lock_type_.empty()) { 764 error_msg = kErrorPin; 765 } else if (sim_lock_type_ == flimflam::kSIMLockPuk) { 766 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 767 } else { 768 NOTREACHED() 769 << "Change PIN / Set lock mode with unexpected SIM lock state"; 770 state_ = SIM_ABSENT_NOT_LOCKED; 771 } 772 break; 773 case SIM_LOCKED_PIN: 774 if (sim_lock_type_ == flimflam::kSIMLockPuk) { 775 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 776 } else if (sim_lock_type_ == flimflam::kSIMLockPin) { 777 // Still locked with PIN. 778 error_msg = kErrorPin; 779 } else { 780 state_ = SIM_ABSENT_NOT_LOCKED; 781 } 782 break; 783 case SIM_LOCKED_NO_PIN_TRIES_LEFT: 784 // Proceed user to PUK input. 785 state_ = SIM_LOCKED_PUK; 786 break; 787 case SIM_LOCKED_PUK: 788 if (sim_lock_type_ != flimflam::kSIMLockPin && 789 sim_lock_type_ != flimflam::kSIMLockPuk) { 790 state_ = SIM_ABSENT_NOT_LOCKED; 791 } else if (retries_left == 0) { 792 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT; 793 } 794 // Otherwise SIM card is still locked with PUK code. 795 // Dialog will display enter PUK screen with an updated retries count. 796 break; 797 case SIM_LOCKED_NO_PUK_TRIES_LEFT: 798 case SIM_DISABLED: 799 // User will close dialog manually. 800 break; 801 } 802 } else { 803 VLOG(1) << "Cellular device is absent."; 804 // No cellular device, should close dialog. 805 state_ = SIM_ABSENT_NOT_LOCKED; 806 } 807 VLOG(1) << "New state: " << state_; 808 UpdatePage(cellular, error_msg); 809 } 810 811 void SimUnlockHandler::UpdatePage(const DeviceState* cellular, 812 const std::string& error_msg) { 813 DictionaryValue sim_dict; 814 if (cellular) 815 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left()); 816 sim_dict.SetInteger(kState, state_); 817 if (!error_msg.empty()) 818 sim_dict.SetString(kError, error_msg); 819 else 820 sim_dict.SetString(kError, kErrorOk); 821 web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict); 822 } 823 824 // SimUnlockUI ----------------------------------------------------------------- 825 826 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) { 827 SimUnlockHandler* handler = new SimUnlockHandler(); 828 web_ui->AddMessageHandler(handler); 829 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource(); 830 831 // Set up the chrome://sim-unlock/ source. 832 Profile* profile = Profile::FromWebUI(web_ui); 833 content::URLDataSource::Add(profile, html_source); 834 } 835 836 } // namespace chromeos 837