1 // Copyright (c) 2011 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/logging.h" 10 #include "base/memory/weak_ptr.h" 11 #include "base/string_piece.h" 12 #include "base/values.h" 13 #include "chrome/browser/chromeos/cros/cros_library.h" 14 #include "chrome/browser/chromeos/cros/network_library.h" 15 #include "chrome/browser/chromeos/sim_dialog_delegate.h" 16 #include "chrome/browser/profiles/profile.h" 17 #include "chrome/browser/ui/webui/chrome_url_data_manager.h" 18 #include "chrome/common/jstemplate_builder.h" 19 #include "chrome/common/url_constants.h" 20 #include "content/browser/browser_thread.h" 21 #include "content/browser/tab_contents/tab_contents.h" 22 #include "content/common/notification_service.h" 23 #include "content/common/notification_type.h" 24 #include "grit/browser_resources.h" 25 #include "grit/generated_resources.h" 26 #include "ui/base/l10n/l10n_util.h" 27 #include "ui/base/resource/resource_bundle.h" 28 29 namespace { 30 31 // JS API callbacks names. 32 const char kJsApiCancel[] = "cancel"; 33 const char kJsApiChangePinCode[] = "changePinCode"; 34 const char kJsApiEnterPinCode[] = "enterPinCode"; 35 const char kJsApiEnterPukCode[] = "enterPukCode"; 36 const char kJsApiProceedToPukInput[] = "proceedToPukInput"; 37 const char kJsApiSimStatusInitialize[] = "simStatusInitialize"; 38 39 // Page JS API function names. 40 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged"; 41 42 // SIM state variables which are passed to the page. 43 const char kState[] = "state"; 44 const char kError[] = "error"; 45 const char kTriesLeft[] = "tries"; 46 47 // Error constants, passed to the page. 48 const char kErrorPin[] = "incorrectPin"; 49 const char kErrorPuk[] = "incorrectPuk"; 50 const char kErrorOk[] = "ok"; 51 52 const chromeos::NetworkDevice* GetCellularDevice() { 53 chromeos::NetworkLibrary* lib = chromeos::CrosLibrary::Get()-> 54 GetNetworkLibrary(); 55 CHECK(lib); 56 return lib->FindCellularDevice(); 57 } 58 59 } // namespace 60 61 namespace chromeos { 62 63 class SimUnlockUIHTMLSource : public ChromeURLDataManager::DataSource { 64 public: 65 SimUnlockUIHTMLSource(); 66 67 // Called when the network layer has requested a resource underneath 68 // the path we registered. 69 virtual void StartDataRequest(const std::string& path, 70 bool is_incognito, 71 int request_id); 72 virtual std::string GetMimeType(const std::string&) const { 73 return "text/html"; 74 } 75 76 private: 77 virtual ~SimUnlockUIHTMLSource() {} 78 79 std::string service_path_; 80 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource); 81 }; 82 83 // The handler for Javascript messages related to the "sim-unlock" view. 84 class SimUnlockHandler : public WebUIMessageHandler, 85 public base::SupportsWeakPtr<SimUnlockHandler>, 86 public NetworkLibrary::NetworkDeviceObserver, 87 public NetworkLibrary::PinOperationObserver { 88 public: 89 SimUnlockHandler(); 90 virtual ~SimUnlockHandler(); 91 92 // Init work after Attach. 93 void Init(TabContents* contents); 94 95 // WebUIMessageHandler implementation. 96 virtual WebUIMessageHandler* Attach(WebUI* web_ui); 97 virtual void RegisterMessages(); 98 99 // NetworkLibrary::NetworkDeviceObserver implementation. 100 virtual void OnNetworkDeviceChanged(NetworkLibrary* cros, 101 const NetworkDevice* device); 102 103 // NetworkLibrary::PinOperationObserver implementation. 104 virtual void OnPinOperationCompleted(NetworkLibrary* cros, 105 PinOperationError error); 106 107 private: 108 // Should keep this state enum in sync with similar one in JS code. 109 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user 110 // for PIN input because PinRequired preference change was requested. 111 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN 112 // and new PIN to change it. 113 typedef enum SimUnlockState { 114 SIM_UNLOCK_LOADING = -1, 115 SIM_ABSENT_NOT_LOCKED = 0, 116 SIM_NOT_LOCKED_ASK_PIN = 1, 117 SIM_NOT_LOCKED_CHANGE_PIN = 2, 118 SIM_LOCKED_PIN = 3, 119 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4, 120 SIM_LOCKED_PUK = 5, 121 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6, 122 SIM_DISABLED = 7, 123 } SimUnlockState; 124 125 // Type of the SIM unlock code. 126 typedef enum SimUnlockCode { 127 CODE_PIN, 128 CODE_PUK, 129 } SimUnlockCode; 130 131 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> { 132 public: 133 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler) 134 : handler_(handler) { 135 } 136 137 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler, 138 const std::string& code, 139 SimUnlockCode code_type) 140 : handler_(handler), 141 code_(code), 142 code_type_(code_type) { 143 } 144 145 void HandleCancel() { 146 if (handler_) 147 handler_->CancelDialog(); 148 } 149 150 void HandleEnterCode() { 151 if (handler_) 152 handler_->EnterCode(code_, code_type_); 153 } 154 155 void HandleInitialize() { 156 if (handler_) 157 handler_->InitializeSimStatus(); 158 } 159 160 void HandleProceedToPukInput() { 161 if (handler_) 162 handler_->ProceedToPukInput(); 163 } 164 165 private: 166 base::WeakPtr<SimUnlockHandler> handler_; 167 168 // Pending code input (PIN/PUK). 169 std::string code_; 170 171 // Pending code type. 172 SimUnlockCode code_type_; 173 174 DISALLOW_COPY_AND_ASSIGN(TaskProxy); 175 }; 176 177 // Processing for the cases when dialog was cancelled. 178 void CancelDialog(); 179 180 // Pass PIN/PUK code to flimflam and check status. 181 void EnterCode(const std::string& code, SimUnlockCode code_type); 182 183 // Single handler for PIN/PUK code operations. 184 void HandleEnterCode(SimUnlockCode code_type, const std::string& code); 185 186 // Handlers for JS WebUI messages. 187 void HandleCancel(const ListValue* args); 188 void HandleChangePinCode(const ListValue* args); 189 void HandleEnterPinCode(const ListValue* args); 190 void HandleEnterPukCode(const ListValue* args); 191 void HandleProceedToPukInput(const ListValue* args); 192 void HandleSimStatusInitialize(const ListValue* args); 193 194 // Initialize current SIM card status, passes that to page. 195 void InitializeSimStatus(); 196 197 // Notifies SIM Security tab handler that RequirePin preference change 198 // has been ended (either updated or cancelled). 199 void NotifyOnRequirePinChangeEnded(bool new_value); 200 201 // Notifies observers that the EnterPin or EnterPuk dialog has been 202 // completed (either cancelled or with entry of PIN/PUK). 203 void NotifyOnEnterPinEnded(bool cancelled); 204 205 // Checks whether SIM card is in PUK locked state and proceeds to PUK input. 206 void ProceedToPukInput(); 207 208 // Processes current SIM card state and update internal state/page. 209 void ProcessSimCardState(const chromeos::NetworkDevice* cellular); 210 211 // Updates page with the current state/SIM card info/error. 212 void UpdatePage(const chromeos::NetworkDevice* cellular, 213 const std::string& error_msg); 214 215 TabContents* tab_contents_; 216 SimUnlockState state_; 217 218 // Path of the Cellular device that we monitor property updates from. 219 std::string cellular_device_path_; 220 221 // Type of the dialog: generic unlock/change pin/change PinRequire. 222 SimDialogDelegate::SimDialogMode dialog_mode_; 223 224 // New PIN value for the case when we unblock SIM card or change PIN. 225 std::string new_pin_; 226 227 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler); 228 }; 229 230 // SimUnlockUIHTMLSource ------------------------------------------------------- 231 232 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() 233 : DataSource(chrome::kChromeUISimUnlockHost, MessageLoop::current()) { 234 } 235 236 void SimUnlockUIHTMLSource::StartDataRequest(const std::string& path, 237 bool is_incognito, 238 int request_id) { 239 DictionaryValue strings; 240 strings.SetString("title", 241 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 242 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK)); 243 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL)); 244 strings.SetString("enterPinTitle", 245 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE)); 246 strings.SetString("enterPinMessage", 247 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE)); 248 strings.SetString("enterPinTriesMessage", 249 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE)); 250 strings.SetString("incorrectPinTriesMessage", 251 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE)); 252 strings.SetString("incorrectPinTitle", 253 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE)); 254 // TODO(nkostylev): Pass carrier name if we know that. 255 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16( 256 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE, 257 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 258 strings.SetString("enterPukButton", 259 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON)); 260 strings.SetString("enterPukTitle", 261 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE)); 262 strings.SetString("enterPukWarning", 263 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING)); 264 // TODO(nkostylev): Pass carrier name if we know that. 265 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16( 266 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE, 267 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER))); 268 strings.SetString("choosePinTitle", 269 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE)); 270 strings.SetString("choosePinMessage", 271 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE)); 272 strings.SetString("newPin", l10n_util::GetStringUTF16( 273 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN)); 274 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16( 275 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN)); 276 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16( 277 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR)); 278 strings.SetString("noPukTriesLeft", 279 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE)); 280 strings.SetString("simDisabledTitle", 281 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE)); 282 strings.SetString("simDisabledMessage", 283 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE)); 284 285 strings.SetString("changePinTitle", l10n_util::GetStringUTF16( 286 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE)); 287 strings.SetString("changePinMessage", l10n_util::GetStringUTF16( 288 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE)); 289 strings.SetString("oldPin", l10n_util::GetStringUTF16( 290 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN)); 291 292 SetFontAndTextDirection(&strings); 293 294 static const base::StringPiece html( 295 ResourceBundle::GetSharedInstance().GetRawDataResource( 296 IDR_SIM_UNLOCK_HTML)); 297 298 const std::string& full_html = jstemplate_builder::GetI18nTemplateHtml( 299 html, &strings); 300 301 scoped_refptr<RefCountedBytes> html_bytes(new RefCountedBytes()); 302 html_bytes->data.resize(full_html.size()); 303 std::copy(full_html.begin(), full_html.end(), html_bytes->data.begin()); 304 305 SendResponse(request_id, html_bytes); 306 } 307 308 // SimUnlockHandler ------------------------------------------------------------ 309 310 SimUnlockHandler::SimUnlockHandler() 311 : tab_contents_(NULL), 312 state_(SIM_UNLOCK_LOADING), 313 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK) { 314 const chromeos::NetworkDevice* cellular = GetCellularDevice(); 315 // One could just call us directly via chrome://sim-unlock. 316 if (cellular) { 317 cellular_device_path_ = cellular->device_path(); 318 CrosLibrary::Get()->GetNetworkLibrary()->AddNetworkDeviceObserver( 319 cellular_device_path_, this); 320 CrosLibrary::Get()->GetNetworkLibrary()->AddPinOperationObserver(this); 321 } 322 } 323 324 SimUnlockHandler::~SimUnlockHandler() { 325 if (!cellular_device_path_.empty()) { 326 CrosLibrary::Get()->GetNetworkLibrary()->RemoveNetworkDeviceObserver( 327 cellular_device_path_, this); 328 CrosLibrary::Get()->GetNetworkLibrary()->RemovePinOperationObserver(this); 329 } 330 } 331 332 WebUIMessageHandler* SimUnlockHandler::Attach(WebUI* web_ui) { 333 return WebUIMessageHandler::Attach(web_ui); 334 } 335 336 void SimUnlockHandler::Init(TabContents* contents) { 337 tab_contents_ = contents; 338 } 339 340 void SimUnlockHandler::RegisterMessages() { 341 web_ui_->RegisterMessageCallback(kJsApiCancel, 342 NewCallback(this, &SimUnlockHandler::HandleCancel)); 343 web_ui_->RegisterMessageCallback(kJsApiChangePinCode, 344 NewCallback(this, &SimUnlockHandler::HandleChangePinCode)); 345 web_ui_->RegisterMessageCallback(kJsApiEnterPinCode, 346 NewCallback(this, &SimUnlockHandler::HandleEnterPinCode)); 347 web_ui_->RegisterMessageCallback(kJsApiEnterPukCode, 348 NewCallback(this, &SimUnlockHandler::HandleEnterPukCode)); 349 web_ui_->RegisterMessageCallback(kJsApiProceedToPukInput, 350 NewCallback(this, &SimUnlockHandler::HandleProceedToPukInput)); 351 web_ui_->RegisterMessageCallback(kJsApiSimStatusInitialize, 352 NewCallback(this, &SimUnlockHandler::HandleSimStatusInitialize)); 353 } 354 355 void SimUnlockHandler::OnNetworkDeviceChanged(NetworkLibrary* cros, 356 const NetworkDevice* device) { 357 chromeos::SIMLockState lock_state = device->sim_lock_state(); 358 int retries_left = device->sim_retries_left(); 359 VLOG(1) << "OnNetworkDeviceChanged, lock: " << lock_state 360 << ", retries: " << retries_left; 361 ProcessSimCardState(GetCellularDevice()); 362 } 363 364 void SimUnlockHandler::OnPinOperationCompleted(NetworkLibrary* cros, 365 PinOperationError error) { 366 DCHECK(cros); 367 const NetworkDevice* cellular = cros->FindCellularDevice(); 368 DCHECK(cellular); 369 VLOG(1) << "OnPinOperationCompleted, error: " << error; 370 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) { 371 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 372 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF); 373 // Async change RequirePin operation has finished OK. 374 NotifyOnRequirePinChangeEnded( 375 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON); 376 // Dialog will close itself. 377 state_ = SIM_ABSENT_NOT_LOCKED; 378 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) { 379 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN); 380 // Dialog will close itself. 381 state_ = SIM_ABSENT_NOT_LOCKED; 382 } 383 // If previous EnterPIN was last PIN attempt and SIMLock state was already 384 // processed by OnNetworkDeviceChanged, let dialog stay on 385 // NO_PIN_RETRIES_LEFT step. 386 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED)) 387 ProcessSimCardState(cellular); 388 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK && 389 state_ == SIM_ABSENT_NOT_LOCKED) 390 NotifyOnEnterPinEnded(false); 391 } 392 393 void SimUnlockHandler::CancelDialog() { 394 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 395 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 396 // When async change RequirePin operation is performed, 397 // dialog UI controls such as Cancel button are disabled. 398 // If dialog was cancelled that means RequirePin preference hasn't been 399 // changed and is not in process of changing at the moment. 400 NotifyOnRequirePinChangeEnded( 401 !(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON)); 402 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK) { 403 NotifyOnEnterPinEnded(true); 404 } 405 } 406 407 void SimUnlockHandler::EnterCode(const std::string& code, 408 SimUnlockCode code_type) { 409 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 410 NetworkLibrary* lib = chromeos::CrosLibrary::Get()->GetNetworkLibrary(); 411 CHECK(lib); 412 413 const NetworkDevice* cellular = GetCellularDevice(); 414 chromeos::SIMLockState lock_state = cellular->sim_lock_state(); 415 416 switch (code_type) { 417 case CODE_PIN: 418 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 419 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 420 if (lock_state != chromeos::SIM_UNLOCKED) { 421 // If SIM is locked/absent, change RequirePin UI is not accessible. 422 NOTREACHED() << 423 "Changing RequirePin pref on locked / uninitialized SIM."; 424 } 425 lib->ChangeRequirePin( 426 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON, 427 code); 428 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) { 429 if (lock_state != chromeos::SIM_UNLOCKED) { 430 // If SIM is locked/absent, changing PIN UI is not accessible. 431 NOTREACHED() << "Changing PIN on locked / uninitialized SIM."; 432 } 433 lib->ChangePin(code, new_pin_); 434 } else { 435 lib->EnterPin(code); 436 } 437 break; 438 case CODE_PUK: 439 DCHECK(!new_pin_.empty()); 440 lib->UnblockPin(code, new_pin_); 441 break; 442 } 443 } 444 445 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) { 446 NotificationService::current()->Notify( 447 NotificationType::ENTER_PIN_ENDED, 448 NotificationService::AllSources(), 449 Details<bool>(&cancelled)); 450 } 451 452 void SimUnlockHandler::NotifyOnRequirePinChangeEnded(bool new_value) { 453 NotificationService::current()->Notify( 454 NotificationType::REQUIRE_PIN_SETTING_CHANGE_ENDED, 455 NotificationService::AllSources(), 456 Details<bool>(&new_value)); 457 } 458 459 void SimUnlockHandler::HandleCancel(const ListValue* args) { 460 const size_t kEnterCodeParamCount = 0; 461 if (args->GetSize() != kEnterCodeParamCount) { 462 NOTREACHED(); 463 return; 464 } 465 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 466 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 467 NewRunnableMethod(task.get(), &TaskProxy::HandleCancel)); 468 } 469 470 void SimUnlockHandler::HandleChangePinCode(const ListValue* args) { 471 const size_t kChangePinParamCount = 2; 472 std::string pin; 473 std::string new_pin; 474 if (args->GetSize() != kChangePinParamCount || 475 !args->GetString(0, &pin) || 476 !args->GetString(1, &new_pin)) { 477 NOTREACHED(); 478 return; 479 } 480 new_pin_ = new_pin; 481 HandleEnterCode(CODE_PIN, pin); 482 } 483 484 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type, 485 const std::string& code) { 486 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type); 487 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 488 NewRunnableMethod(task.get(), &TaskProxy::HandleEnterCode)); 489 } 490 491 void SimUnlockHandler::HandleEnterPinCode(const ListValue* args) { 492 const size_t kEnterPinParamCount = 1; 493 std::string pin; 494 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) { 495 NOTREACHED(); 496 return; 497 } 498 HandleEnterCode(CODE_PIN, pin); 499 } 500 501 void SimUnlockHandler::HandleEnterPukCode(const ListValue* args) { 502 const size_t kEnterPukParamCount = 2; 503 std::string puk; 504 std::string new_pin; 505 if (args->GetSize() != kEnterPukParamCount || 506 !args->GetString(0, &puk) || 507 !args->GetString(1, &new_pin)) { 508 NOTREACHED(); 509 return; 510 } 511 new_pin_ = new_pin; 512 HandleEnterCode(CODE_PUK, puk); 513 } 514 515 void SimUnlockHandler::HandleProceedToPukInput(const ListValue* args) { 516 const size_t kProceedToPukInputParamCount = 0; 517 if (args->GetSize() != kProceedToPukInputParamCount) { 518 NOTREACHED(); 519 return; 520 } 521 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 522 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 523 NewRunnableMethod(task.get(), &TaskProxy::HandleProceedToPukInput)); 524 } 525 526 void SimUnlockHandler::HandleSimStatusInitialize(const ListValue* args) { 527 const size_t kSimStatusInitializeParamCount = 1; 528 double mode; 529 if (args->GetSize() != kSimStatusInitializeParamCount || 530 !args->GetDouble(0, &mode)) { 531 NOTREACHED(); 532 return; 533 } 534 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode); 535 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_; 536 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr()); 537 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 538 NewRunnableMethod(task.get(), &TaskProxy::HandleInitialize)); 539 } 540 541 void SimUnlockHandler::InitializeSimStatus() { 542 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 543 ProcessSimCardState(GetCellularDevice()); 544 } 545 546 void SimUnlockHandler::ProceedToPukInput() { 547 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 548 ProcessSimCardState(GetCellularDevice()); 549 } 550 551 void SimUnlockHandler::ProcessSimCardState( 552 const chromeos::NetworkDevice* cellular) { 553 std::string error_msg; 554 if (cellular) { 555 chromeos::SIMLockState lock_state = cellular->sim_lock_state(); 556 int retries_left = cellular->sim_retries_left(); 557 VLOG(1) << "Current state: " << state_ << " lock_state: " << lock_state 558 << " retries: " << retries_left; 559 switch (state_) { 560 case SIM_UNLOCK_LOADING: 561 if (lock_state == chromeos::SIM_LOCKED_PIN) { 562 state_ = SIM_LOCKED_PIN; 563 } else if (lock_state == chromeos::SIM_LOCKED_PUK) { 564 if (retries_left > 0) 565 state_ = SIM_LOCKED_PUK; 566 else 567 state_ = SIM_DISABLED; 568 } else if (lock_state == chromeos::SIM_UNLOCKED) { 569 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON || 570 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) { 571 state_ = SIM_NOT_LOCKED_ASK_PIN; 572 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) { 573 state_ = SIM_NOT_LOCKED_CHANGE_PIN; 574 } else { 575 state_ = SIM_ABSENT_NOT_LOCKED; 576 } 577 } else { 578 // SIM_UNKNOWN: when SIM status is not initialized (should not happen, 579 // since this UI is accessible when SIM is initialized) 580 // or SIM card is absent. In latter case just close dialog. 581 state_ = SIM_ABSENT_NOT_LOCKED; 582 } 583 break; 584 case SIM_ABSENT_NOT_LOCKED: 585 // Dialog will close itself in this case. 586 break; 587 case SIM_NOT_LOCKED_ASK_PIN: 588 case SIM_NOT_LOCKED_CHANGE_PIN: 589 // We always start in these states when SIM is unlocked. 590 // So if we get here while still being UNLOCKED, 591 // that means entered PIN was incorrect. 592 if (lock_state == chromeos::SIM_UNLOCKED) { 593 error_msg = kErrorPin; 594 } else if (lock_state == chromeos::SIM_LOCKED_PUK) { 595 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 596 } else { 597 NOTREACHED() 598 << "Change PIN / Set lock mode with unexpected SIM lock state"; 599 state_ = SIM_ABSENT_NOT_LOCKED; 600 } 601 break; 602 case SIM_LOCKED_PIN: 603 if (lock_state == chromeos::SIM_UNLOCKED || 604 lock_state == chromeos::SIM_UNKNOWN) { 605 state_ = SIM_ABSENT_NOT_LOCKED; 606 } else if (lock_state == chromeos::SIM_LOCKED_PUK) { 607 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT; 608 } else { 609 // Still blocked with PIN. 610 error_msg = kErrorPin; 611 } 612 break; 613 case SIM_LOCKED_NO_PIN_TRIES_LEFT: 614 // Proceed user to PUK input. 615 state_ = SIM_LOCKED_PUK; 616 break; 617 case SIM_LOCKED_PUK: 618 if (lock_state == chromeos::SIM_UNLOCKED || 619 lock_state == chromeos::SIM_UNKNOWN) { 620 state_ = SIM_ABSENT_NOT_LOCKED; 621 } else if (retries_left == 0) { 622 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT; 623 } 624 // Otherwise SIM card is still locked with PUK code. 625 // Dialog will display enter PUK screen with an updated retries count. 626 break; 627 case SIM_LOCKED_NO_PUK_TRIES_LEFT: 628 case SIM_DISABLED: 629 // User will close dialog manually. 630 break; 631 } 632 } else { 633 VLOG(1) << "Cellular device is absent."; 634 // No cellular device, should close dialog. 635 state_ = SIM_ABSENT_NOT_LOCKED; 636 } 637 VLOG(1) << "New state: " << state_; 638 UpdatePage(cellular, error_msg); 639 } 640 641 void SimUnlockHandler::UpdatePage(const chromeos::NetworkDevice* cellular, 642 const std::string& error_msg) { 643 DictionaryValue sim_dict; 644 if (cellular) 645 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left()); 646 sim_dict.SetInteger(kState, state_); 647 if (!error_msg.empty()) 648 sim_dict.SetString(kError, error_msg); 649 else 650 sim_dict.SetString(kError, kErrorOk); 651 web_ui_->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict); 652 } 653 654 // SimUnlockUI ----------------------------------------------------------------- 655 656 SimUnlockUI::SimUnlockUI(TabContents* contents) : WebUI(contents) { 657 SimUnlockHandler* handler = new SimUnlockHandler(); 658 AddMessageHandler((handler)->Attach(this)); 659 handler->Init(contents); 660 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource(); 661 662 // Set up the chrome://sim-unlock/ source. 663 contents->profile()->GetChromeURLDataManager()->AddDataSource(html_source); 664 } 665 666 } // namespace chromeos 667