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/base/webui/jstemplate_builder.h" 40 #include "ui/base/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 kErrorOk[] = "ok"; 67 68 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() { 69 return chromeos::NetworkHandler::Get()->network_device_handler(); 70 } 71 72 chromeos::NetworkStateHandler* GetNetworkStateHandler() { 73 return chromeos::NetworkHandler::Get()->network_state_handler(); 74 } 75 76 } // namespace 77 78 namespace chromeos { 79 80 class SimUnlockUIHTMLSource : public content::URLDataSource { 81 public: 82 SimUnlockUIHTMLSource(); 83 84 // content::URLDataSource implementation. 85 virtual std::string GetSource() const OVERRIDE; 86 virtual void StartDataRequest( 87 const std::string& path, 88 int render_process_id, 89 int render_frame_id, 90 const content::URLDataSource::GotDataCallback& callback) OVERRIDE; 91 virtual std::string GetMimeType(const std::string&) const OVERRIDE { 92 return "text/html"; 93 } 94 virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE { 95 return false; 96 } 97 98 private: 99 virtual ~SimUnlockUIHTMLSource() {} 100 101 std::string service_path_; 102 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource); 103 }; 104 105 // The handler for Javascript messages related to the "sim-unlock" view. 106 class SimUnlockHandler : public WebUIMessageHandler, 107 public base::SupportsWeakPtr<SimUnlockHandler>, 108 public NetworkStateHandlerObserver { 109 public: 110 SimUnlockHandler(); 111 virtual ~SimUnlockHandler(); 112 113 // WebUIMessageHandler implementation. 114 virtual void RegisterMessages() OVERRIDE; 115 116 // NetworkStateHandlerObserver implementation. 117 virtual void DeviceListChanged() OVERRIDE; 118 119 private: 120 // Should keep this state enum in sync with similar one in JS code. 121 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user 122 // for PIN input because PinRequired preference change was requested. 123 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN 124 // and new PIN to change it. 125 typedef enum SimUnlockState { 126 SIM_UNLOCK_LOADING = -1, 127 SIM_ABSENT_NOT_LOCKED = 0, 128 SIM_NOT_LOCKED_ASK_PIN = 1, 129 SIM_NOT_LOCKED_CHANGE_PIN = 2, 130 SIM_LOCKED_PIN = 3, 131 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4, 132 SIM_LOCKED_PUK = 5, 133 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6, 134 SIM_DISABLED = 7, 135 } SimUnlockState; 136 137 // Type of the SIM unlock code. 138 enum SimUnlockCode { 139 CODE_PIN, 140 CODE_PUK 141 }; 142 143 enum PinOperationError { 144 PIN_ERROR_NONE = 0, 145 PIN_ERROR_UNKNOWN = 1, 146 PIN_ERROR_INCORRECT_CODE = 2, 147 PIN_ERROR_BLOCKED = 3 148 }; 149 150 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { 151 public: 152 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler) 153 : handler_(handler), 154 code_type_() { 155 } 156 157 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler, 158 const std::string& code, 159 SimUnlockCode code_type) 160 : handler_(handler), 161 code_(code), 162 code_type_(code_type) { 163 } 164 165 void HandleCancel() { 166 if (handler_) 167 handler_->CancelDialog(); 168 } 169 170 void HandleEnterCode() { 171 if (handler_) 172 handler_->EnterCode(code_, code_type_); 173 } 174 175 void HandleInitialize() { 176 if (handler_) 177 handler_->InitializeSimStatus(); 178 } 179 180 void HandleProceedToPukInput() { 181 if (handler_) 182 handler_->ProceedToPukInput(); 183 } 184 185 private: 186 friend class base::RefCountedThreadSafe<TaskProxy>; 187 188 ~TaskProxy() {} 189 190 base::WeakPtr<SimUnlockHandler> handler_; 191 192 // Pending code input (PIN/PUK). 193 std::string code_; 194 195 // Pending code type. 196 SimUnlockCode code_type_; 197 198 DISALLOW_COPY_AND_ASSIGN(TaskProxy); 199 }; 200 201 // Returns the cellular device that this dialog currently corresponds to. 202 const DeviceState* GetCellularDevice(); 203 204 // Processing for the cases when dialog was cancelled. 205 void CancelDialog(); 206 207 // Pass PIN/PUK code to shill and check status. 208 void EnterCode(const std::string& code, SimUnlockCode code_type); 209 210 // Methods to invoke shill PIN/PUK D-Bus operations. 211 void ChangeRequirePin(bool require_pin, const std::string& pin); 212 void EnterPin(const std::string& pin); 213 void ChangePin(const std::string& old_pin, const std::string& new_pin); 214 void UnblockPin(const std::string& puk, const std::string& new_pin); 215 void PinOperationSuccessCallback(const std::string& operation_name); 216 void PinOperationErrorCallback(const std::string& operation_name, 217 const std::string& error_name, 218 scoped_ptr<base::DictionaryValue> error_data); 219 220 // Called when an asynchronous PIN operation has completed. 221 void OnPinOperationCompleted(PinOperationError error); 222 223 // Single handler for PIN/PUK code operations. 224 void HandleEnterCode(SimUnlockCode code_type, const std::string& code); 225 226 // Handlers for JS WebUI messages. 227 void HandleCancel(const base::ListValue* args); 228 void HandleChangePinCode(const base::ListValue* args); 229 void HandleEnterPinCode(const base::ListValue* args); 230 void HandleEnterPukCode(const base::ListValue* args); 231 void HandleProceedToPukInput(const base::ListValue* args); 232 void HandleSimStatusInitialize(const base::ListValue* args); 233 234 // Initialize current SIM card status, passes that to page. 235 void InitializeSimStatus(); 236 237 // Notifies SIM Security tab handler that RequirePin preference change 238 // has been ended (either updated or cancelled). 239 void NotifyOnRequirePinChangeEnded(bool new_value); 240 241 // Notifies observers that the EnterPin or EnterPuk dialog has been 242 // completed (either cancelled or with entry of PIN/PUK). 243 void NotifyOnEnterPinEnded(bool cancelled); 244 245 // Checks whether SIM card is in PUK locked state and proceeds to PUK input. 246 void ProceedToPukInput(); 247 248 // Processes current SIM card state and update internal state/page. 249 void ProcessSimCardState(const DeviceState* cellular); 250 251 // Updates page with the current state/SIM card info/error. 252 void UpdatePage(const DeviceState* cellular, const std::string& error_msg); 253 254 // Dialog internal state. 255 SimUnlockState state_; 256 257 // Path of the Cellular device that we monitor property updates from. 258 std::string cellular_device_path_; 259 260 // Type of the dialog: generic unlock/change pin/change PinRequire. 261 SimDialogDelegate::SimDialogMode dialog_mode_; 262 263 // New PIN value for the case when we unblock SIM card or change PIN. 264 std::string new_pin_; 265 266 // The initial lock type value, used to observe changes to lock status; 267 std::string sim_lock_type_; 268 269 // True if there's a pending PIN operation. 270 // That means that SIM lock state change will be received 2 times: 271 // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted. 272 // First one should be ignored. 273 bool pending_pin_operation_; 274 275 base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_; 276 277 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler); 278 }; 279 280 // SimUnlockUIHTMLSource ------------------------------------------------------- 281 282 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() { 283 } 284 285 std::string SimUnlockUIHTMLSource::GetSource() const { 286 return chrome::kChromeUISimUnlockHost; 287 } 288 289 void SimUnlockUIHTMLSource::StartDataRequest( 290 const std::string& path, 291 int render_process_id, 292 int render_frame_id, 293 const content::URLDataSource::GotDataCallback& callback) { 294 base::DictionaryValue strings; 295 strings.SetString("title", 296 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 297 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK)); 298 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); 299 strings.SetString("enterPinTitle", 300 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 301 strings.SetString("enterPinMessage", 302 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE)); 303 strings.SetString("enterPinTriesMessage", 304 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE)); 305 strings.SetString("incorrectPinTriesMessage", 306 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE)); 307 strings.SetString("incorrectPinTitle", 308 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE)); 309 // TODO(nkostylev): Pass carrier name if we know that. 310 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16( 311 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE, 312 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 313 strings.SetString("enterPukButton", 314 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON)); 315 strings.SetString("enterPukTitle", 316 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE)); 317 strings.SetString("enterPukWarning", 318 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING)); 319 // TODO(nkostylev): Pass carrier name if we know that. 320 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16( 321 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE, 322 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 323 strings.SetString("choosePinTitle", 324 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE)); 325 strings.SetString("choosePinMessage", 326 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE)); 327 strings.SetString("newPin", l10n_util::GetStringUTF16( 328 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN)); 329 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16( 330 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN)); 331 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16( 332 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR)); 333 strings.SetString("noPukTriesLeft", 334 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE)); 335 strings.SetString("simDisabledTitle", 336 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE)); 337 strings.SetString("simDisabledMessage", 338 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE)); 339 340 strings.SetString("changePinTitle", l10n_util::GetStringUTF16( 341 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE)); 342 strings.SetString("changePinMessage", l10n_util::GetStringUTF16( 343 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE)); 344 strings.SetString("oldPin", l10n_util::GetStringUTF16( 345 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN)); 346 347 webui::SetFontAndTextDirection(&strings); 348 349 static const base::StringPiece html( 350 ResourceBundle::GetSharedInstance().GetRawDataResource( 351 IDR_SIM_UNLOCK_HTML)); 352 353 std::string full_html = webui::GetI18nTemplateHtml(html, &strings); 354 355 callback.Run(base::RefCountedString::TakeString(&full_html)); 356 } 357 358 // SimUnlockHandler ------------------------------------------------------------ 359 360 SimUnlockHandler::SimUnlockHandler() 361 : state_(SIM_UNLOCK_LOADING), 362 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK), 363 pending_pin_operation_(false), 364 weak_ptr_factory_(this) { 365 if (GetNetworkStateHandler() 366 ->GetTechnologyState(NetworkTypePattern::Cellular()) != 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_CURRENTLY_ON(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 base::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 base::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 base::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 base::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 base::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 base::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_CURRENTLY_ON(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 = 710 GetNetworkStateHandler() 711 ->GetDeviceStateByType(NetworkTypePattern::Cellular()); 712 if (cellular_device) { 713 cellular_device_path_ = cellular_device->path(); 714 sim_lock_type_ = cellular_device->sim_lock_type(); 715 } 716 ProcessSimCardState(cellular_device); 717 } 718 719 void SimUnlockHandler::ProceedToPukInput() { 720 DCHECK_CURRENTLY_ON(BrowserThread::UI); 721 ProcessSimCardState(GetCellularDevice()); 722 } 723 724 void SimUnlockHandler::ProcessSimCardState( 725 const DeviceState* cellular) { 726 std::string error_msg; 727 if (cellular) { 728 uint32 retries_left = cellular->sim_retries_left(); 729 VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_ 730 << " retries: " << retries_left; 731 switch (state_) { 732 case SIM_UNLOCK_LOADING: 733 if (sim_lock_type_ == shill::kSIMLockPin) { 734 state_ = SIM_LOCKED_PIN; 735 } else if (sim_lock_type_ == shill::kSIMLockPuk) { 736 if (retries_left > 0) 737 state_ = SIM_LOCKED_PUK; 738 else 739 state_ = SIM_DISABLED; 740 } else if (sim_lock_type_.empty()) { 741 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 742 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 743 state_ = SIM_NOT_LOCKED_ASK_PIN; 744 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) { 745 state_ = SIM_NOT_LOCKED_CHANGE_PIN; 746 } else { 747 state_ = SIM_ABSENT_NOT_LOCKED; 748 } 749 } else { 750 // SIM_UNKNOWN: when SIM status is not initialized (should not happen, 751 // since this UI is accessible when SIM is initialized) 752 // or SIM card is absent. In latter case just close dialog. 753 state_ = SIM_ABSENT_NOT_LOCKED; 754 } 755 break; 756 case SIM_ABSENT_NOT_LOCKED: 757 // Dialog will close itself in this case. 758 break; 759 case SIM_NOT_LOCKED_ASK_PIN: 760 case SIM_NOT_LOCKED_CHANGE_PIN: 761 // We always start in these states when SIM is unlocked. 762 // So if we get here while still being UNLOCKED, 763 // that means entered PIN was incorrect. 764 if (sim_lock_type_.empty()) { 765 error_msg = kErrorPin; 766 } else if (sim_lock_type_ == shill::kSIMLockPuk) { 767 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 768 } else { 769 NOTREACHED() 770 << "Change PIN / Set lock mode with unexpected SIM lock state"; 771 state_ = SIM_ABSENT_NOT_LOCKED; 772 } 773 break; 774 case SIM_LOCKED_PIN: 775 if (sim_lock_type_ == shill::kSIMLockPuk) { 776 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 777 } else if (sim_lock_type_ == shill::kSIMLockPin) { 778 // Still locked with PIN. 779 error_msg = kErrorPin; 780 } else { 781 state_ = SIM_ABSENT_NOT_LOCKED; 782 } 783 break; 784 case SIM_LOCKED_NO_PIN_TRIES_LEFT: 785 // Proceed user to PUK input. 786 state_ = SIM_LOCKED_PUK; 787 break; 788 case SIM_LOCKED_PUK: 789 if (sim_lock_type_ != shill::kSIMLockPin && 790 sim_lock_type_ != shill::kSIMLockPuk) { 791 state_ = SIM_ABSENT_NOT_LOCKED; 792 } else if (retries_left == 0) { 793 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT; 794 } 795 // Otherwise SIM card is still locked with PUK code. 796 // Dialog will display enter PUK screen with an updated retries count. 797 break; 798 case SIM_LOCKED_NO_PUK_TRIES_LEFT: 799 case SIM_DISABLED: 800 // User will close dialog manually. 801 break; 802 } 803 } else { 804 VLOG(1) << "Cellular device is absent."; 805 // No cellular device, should close dialog. 806 state_ = SIM_ABSENT_NOT_LOCKED; 807 } 808 VLOG(1) << "New state: " << state_; 809 UpdatePage(cellular, error_msg); 810 } 811 812 void SimUnlockHandler::UpdatePage(const DeviceState* cellular, 813 const std::string& error_msg) { 814 base::DictionaryValue sim_dict; 815 if (cellular) 816 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left()); 817 sim_dict.SetInteger(kState, state_); 818 if (!error_msg.empty()) 819 sim_dict.SetString(kError, error_msg); 820 else 821 sim_dict.SetString(kError, kErrorOk); 822 web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict); 823 } 824 825 // SimUnlockUI ----------------------------------------------------------------- 826 827 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) { 828 SimUnlockHandler* handler = new SimUnlockHandler(); 829 web_ui->AddMessageHandler(handler); 830 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource(); 831 832 // Set up the chrome://sim-unlock/ source. 833 Profile* profile = Profile::FromWebUI(web_ui); 834 content::URLDataSource::Add(profile, html_source); 835 } 836 837 } // namespace chromeos 838