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.
5 #include "chrome/browser/ui/webui/chromeos/sim_unlock_ui.h"
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/chromeos/sim_dialog_delegate.h"
20 #include "chrome/browser/profiles/profile.h"
21 #include "chrome/common/url_constants.h"
22 #include "chrome/grit/generated_resources.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/url_data_source.h"
30 #include "content/public/browser/web_contents.h"
31 #include "content/public/browser/web_ui.h"
32 #include "content/public/browser/web_ui_message_handler.h"
33 #include "grit/browser_resources.h"
34 #include "third_party/cros_system_api/dbus/service_constants.h"
35 #include "ui/base/l10n/l10n_util.h"
36 #include "ui/base/resource/resource_bundle.h"
37 #include "ui/base/webui/jstemplate_builder.h"
38 #include "ui/base/webui/web_ui_util.h"
40 using content::BrowserThread;
41 using content::WebContents;
42 using content::WebUIMessageHandler;
46 // JS API callbacks names.
47 const char kJsApiChangePinCode[] = "changePinCode";
48 const char kJsApiEnterPinCode[] = "enterPinCode";
49 const char kJsApiEnterPukCode[] = "enterPukCode";
50 const char kJsApiProceedToPukInput[] = "proceedToPukInput";
51 const char kJsApiSimStatusInitialize[] = "simStatusInitialize";
53 // Page JS API function names.
54 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
56 // SIM state variables which are passed to the page.
57 const char kState[] = "state";
58 const char kError[] = "error";
59 const char kTriesLeft[] = "tries";
61 // Error constants, passed to the page.
62 const char kErrorPin[] = "incorrectPin";
63 const char kErrorOk[] = "ok";
65 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
66 return chromeos::NetworkHandler::Get()->network_device_handler();
69 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
70 return chromeos::NetworkHandler::Get()->network_state_handler();
77 class SimUnlockUIHTMLSource : public content::URLDataSource {
79 SimUnlockUIHTMLSource();
81 // content::URLDataSource implementation.
82 virtual std::string GetSource() const OVERRIDE;
83 virtual void StartDataRequest(
84 const std::string& path,
85 int render_process_id,
87 const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
88 virtual std::string GetMimeType(const std::string&) const OVERRIDE {
91 virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
96 virtual ~SimUnlockUIHTMLSource() {}
98 std::string service_path_;
99 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
102 // The handler for Javascript messages related to the "sim-unlock" view.
103 class SimUnlockHandler : public WebUIMessageHandler,
104 public base::SupportsWeakPtr<SimUnlockHandler>,
105 public NetworkStateHandlerObserver {
108 virtual ~SimUnlockHandler();
110 // WebUIMessageHandler implementation.
111 virtual void RegisterMessages() OVERRIDE;
113 // NetworkStateHandlerObserver implementation.
114 virtual void DeviceListChanged() OVERRIDE;
117 // Should keep this state enum in sync with similar one in JS code.
118 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
119 // for PIN input because PinRequired preference change was requested.
120 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
121 // and new PIN to change it.
122 typedef enum SimUnlockState {
123 SIM_UNLOCK_LOADING = -1,
124 SIM_ABSENT_NOT_LOCKED = 0,
125 SIM_NOT_LOCKED_ASK_PIN = 1,
126 SIM_NOT_LOCKED_CHANGE_PIN = 2,
128 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4,
130 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6,
134 // Type of the SIM unlock code.
140 enum PinOperationError {
142 PIN_ERROR_UNKNOWN = 1,
143 PIN_ERROR_INCORRECT_CODE = 2,
144 PIN_ERROR_BLOCKED = 3
147 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
149 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
154 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
155 const std::string& code,
156 SimUnlockCode code_type)
159 code_type_(code_type) {
162 void HandleEnterCode() {
164 handler_->EnterCode(code_, code_type_);
167 void HandleInitialize() {
169 handler_->InitializeSimStatus();
172 void HandleProceedToPukInput() {
174 handler_->ProceedToPukInput();
178 friend class base::RefCountedThreadSafe<TaskProxy>;
182 base::WeakPtr<SimUnlockHandler> handler_;
184 // Pending code input (PIN/PUK).
187 // Pending code type.
188 SimUnlockCode code_type_;
190 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
193 // Returns the cellular device that this dialog currently corresponds to.
194 const DeviceState* GetCellularDevice();
196 // Pass PIN/PUK code to shill and check status.
197 void EnterCode(const std::string& code, SimUnlockCode code_type);
199 // Methods to invoke shill PIN/PUK D-Bus operations.
200 void ChangeRequirePin(bool require_pin, const std::string& pin);
201 void EnterPin(const std::string& pin);
202 void ChangePin(const std::string& old_pin, const std::string& new_pin);
203 void UnblockPin(const std::string& puk, const std::string& new_pin);
204 void PinOperationSuccessCallback(const std::string& operation_name);
205 void PinOperationErrorCallback(const std::string& operation_name,
206 const std::string& error_name,
207 scoped_ptr<base::DictionaryValue> error_data);
209 // Called when an asynchronous PIN operation has completed.
210 void OnPinOperationCompleted(PinOperationError error);
212 // Single handler for PIN/PUK code operations.
213 void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
215 // Handlers for JS WebUI messages.
216 void HandleChangePinCode(const base::ListValue* args);
217 void HandleEnterPinCode(const base::ListValue* args);
218 void HandleEnterPukCode(const base::ListValue* args);
219 void HandleProceedToPukInput(const base::ListValue* args);
220 void HandleSimStatusInitialize(const base::ListValue* args);
222 // Initialize current SIM card status, passes that to page.
223 void InitializeSimStatus();
225 // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
226 void ProceedToPukInput();
228 // Processes current SIM card state and update internal state/page.
229 void ProcessSimCardState(const DeviceState* cellular);
231 // Updates page with the current state/SIM card info/error.
232 void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
234 // Dialog internal state.
235 SimUnlockState state_;
237 // Path of the Cellular device that we monitor property updates from.
238 std::string cellular_device_path_;
240 // Type of the dialog: generic unlock/change pin/change PinRequire.
241 SimDialogDelegate::SimDialogMode dialog_mode_;
243 // New PIN value for the case when we unblock SIM card or change PIN.
244 std::string new_pin_;
246 // The initial lock type value, used to observe changes to lock status;
247 std::string sim_lock_type_;
249 // True if there's a pending PIN operation.
250 // That means that SIM lock state change will be received 2 times:
251 // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted.
252 // First one should be ignored.
253 bool pending_pin_operation_;
255 base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
257 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
260 // SimUnlockUIHTMLSource -------------------------------------------------------
262 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
265 std::string SimUnlockUIHTMLSource::GetSource() const {
266 return chrome::kChromeUISimUnlockHost;
269 void SimUnlockUIHTMLSource::StartDataRequest(
270 const std::string& path,
271 int render_process_id,
273 const content::URLDataSource::GotDataCallback& callback) {
274 base::DictionaryValue strings;
275 strings.SetString("title",
276 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
277 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
278 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
279 strings.SetString("enterPinTitle",
280 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
281 strings.SetString("enterPinMessage",
282 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
283 strings.SetString("enterPinTriesMessage",
284 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
285 strings.SetString("incorrectPinTriesMessage",
286 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
287 strings.SetString("incorrectPinTitle",
288 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
289 // TODO(nkostylev): Pass carrier name if we know that.
290 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
291 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
292 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
293 strings.SetString("enterPukButton",
294 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
295 strings.SetString("enterPukTitle",
296 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
297 strings.SetString("enterPukWarning",
298 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
299 // TODO(nkostylev): Pass carrier name if we know that.
300 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
301 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
302 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
303 strings.SetString("choosePinTitle",
304 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
305 strings.SetString("choosePinMessage",
306 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
307 strings.SetString("newPin", l10n_util::GetStringUTF16(
308 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
309 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
310 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
311 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
312 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
313 strings.SetString("noPukTriesLeft",
314 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
315 strings.SetString("simDisabledTitle",
316 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
317 strings.SetString("simDisabledMessage",
318 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
320 strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
321 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
322 strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
323 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
324 strings.SetString("oldPin", l10n_util::GetStringUTF16(
325 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
327 webui::SetFontAndTextDirection(&strings);
329 static const base::StringPiece html(
330 ResourceBundle::GetSharedInstance().GetRawDataResource(
331 IDR_SIM_UNLOCK_HTML));
333 webui::UseVersion2 version2;
334 std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
336 callback.Run(base::RefCountedString::TakeString(&full_html));
339 // SimUnlockHandler ------------------------------------------------------------
341 SimUnlockHandler::SimUnlockHandler()
342 : state_(SIM_UNLOCK_LOADING),
343 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK),
344 pending_pin_operation_(false),
345 weak_ptr_factory_(this) {
346 if (GetNetworkStateHandler()
347 ->GetTechnologyState(NetworkTypePattern::Cellular()) !=
348 NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)
349 GetNetworkStateHandler()->AddObserver(this, FROM_HERE);
352 SimUnlockHandler::~SimUnlockHandler() {
353 GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
356 void SimUnlockHandler::RegisterMessages() {
357 web_ui()->RegisterMessageCallback(kJsApiChangePinCode,
358 base::Bind(&SimUnlockHandler::HandleChangePinCode,
359 base::Unretained(this)));
360 web_ui()->RegisterMessageCallback(kJsApiEnterPinCode,
361 base::Bind(&SimUnlockHandler::HandleEnterPinCode,
362 base::Unretained(this)));
363 web_ui()->RegisterMessageCallback(kJsApiEnterPukCode,
364 base::Bind(&SimUnlockHandler::HandleEnterPukCode,
365 base::Unretained(this)));
366 web_ui()->RegisterMessageCallback(kJsApiProceedToPukInput,
367 base::Bind(&SimUnlockHandler::HandleProceedToPukInput,
368 base::Unretained(this)));
369 web_ui()->RegisterMessageCallback(kJsApiSimStatusInitialize,
370 base::Bind(&SimUnlockHandler::HandleSimStatusInitialize,
371 base::Unretained(this)));
374 void SimUnlockHandler::DeviceListChanged() {
375 const DeviceState* cellular_device = GetCellularDevice();
376 if (!cellular_device) {
377 LOG(WARNING) << "Cellular device with path '" << cellular_device_path_
379 ProcessSimCardState(NULL);
383 // Process the SIM card state only if the lock state changed.
384 if (cellular_device->sim_lock_type() == sim_lock_type_)
387 sim_lock_type_ = cellular_device->sim_lock_type();
388 uint32 retries_left = cellular_device->sim_retries_left();
389 VLOG(1) << "OnNetworkDeviceSimLockChanged, lock: " << sim_lock_type_
390 << ", retries: " << retries_left;
391 // There's a pending PIN operation.
392 // Wait for it to finish and refresh state then.
393 if (!pending_pin_operation_)
394 ProcessSimCardState(cellular_device);
397 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) {
398 pending_pin_operation_ = false;
399 VLOG(1) << "OnPinOperationCompleted, error: " << error;
400 const DeviceState* cellular = GetCellularDevice();
402 VLOG(1) << "Cellular device disappeared. Dismissing dialog.";
403 ProcessSimCardState(NULL);
406 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) {
407 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
408 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF);
409 // Dialog will close itself.
410 state_ = SIM_ABSENT_NOT_LOCKED;
411 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) {
412 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
413 // Dialog will close itself.
414 state_ = SIM_ABSENT_NOT_LOCKED;
416 // If previous EnterPIN was last PIN attempt and SIMLock state was already
417 // processed by OnNetworkDeviceChanged, let dialog stay on
418 // NO_PIN_RETRIES_LEFT step.
419 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED))
420 ProcessSimCardState(cellular);
423 const DeviceState* SimUnlockHandler::GetCellularDevice() {
424 return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
427 void SimUnlockHandler::EnterCode(const std::string& code,
428 SimUnlockCode code_type) {
429 DCHECK_CURRENTLY_ON(BrowserThread::UI);
431 pending_pin_operation_ = true;
435 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
436 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
437 if (!sim_lock_type_.empty()) {
438 // If SIM is locked/absent, change RequirePin UI is not accessible.
440 "Changing RequirePin pref on locked / uninitialized SIM.";
443 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
445 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
446 if (!sim_lock_type_.empty()) {
447 // If SIM is locked/absent, changing PIN UI is not accessible.
448 NOTREACHED() << "Changing PIN on locked / uninitialized SIM.";
450 ChangePin(code, new_pin_);
456 DCHECK(!new_pin_.empty());
457 UnblockPin(code, new_pin_);
462 void SimUnlockHandler::ChangeRequirePin(bool require_pin,
463 const std::string& pin) {
464 const DeviceState* cellular = GetCellularDevice();
466 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
469 std::string operation_name = "ChangeRequirePin";
470 NET_LOG_USER(operation_name, cellular->path());
471 GetNetworkDeviceHandler()->RequirePin(
475 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
476 weak_ptr_factory_.GetWeakPtr(),
478 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
479 weak_ptr_factory_.GetWeakPtr(),
483 void SimUnlockHandler::EnterPin(const std::string& pin) {
484 const DeviceState* cellular = GetCellularDevice();
486 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
489 std::string operation_name = "EnterPin";
490 NET_LOG_USER(operation_name, cellular->path());
491 GetNetworkDeviceHandler()->EnterPin(
494 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
495 weak_ptr_factory_.GetWeakPtr(),
497 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
498 weak_ptr_factory_.GetWeakPtr(),
502 void SimUnlockHandler::ChangePin(const std::string& old_pin,
503 const std::string& new_pin) {
504 const DeviceState* cellular = GetCellularDevice();
506 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
509 std::string operation_name = "ChangePin";
510 NET_LOG_USER(operation_name, cellular->path());
511 GetNetworkDeviceHandler()->ChangePin(
515 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
516 weak_ptr_factory_.GetWeakPtr(),
518 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
519 weak_ptr_factory_.GetWeakPtr(),
523 void SimUnlockHandler::UnblockPin(const std::string& puk,
524 const std::string& new_pin) {
525 const DeviceState* cellular = GetCellularDevice();
527 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
530 std::string operation_name = "UnblockPin";
531 NET_LOG_USER(operation_name, cellular->path());
532 GetNetworkDeviceHandler()->UnblockPin(
536 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
537 weak_ptr_factory_.GetWeakPtr(),
539 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
540 weak_ptr_factory_.GetWeakPtr(),
544 void SimUnlockHandler::PinOperationSuccessCallback(
545 const std::string& operation_name) {
546 NET_LOG_DEBUG("Pin operation successful.", operation_name);
547 OnPinOperationCompleted(PIN_ERROR_NONE);
550 void SimUnlockHandler::PinOperationErrorCallback(
551 const std::string& operation_name,
552 const std::string& error_name,
553 scoped_ptr<base::DictionaryValue> error_data) {
554 NET_LOG_ERROR("Pin operation failed: " + error_name, operation_name);
555 PinOperationError pin_error;
556 if (error_name == NetworkDeviceHandler::kErrorIncorrectPin ||
557 error_name == NetworkDeviceHandler::kErrorPinRequired)
558 pin_error = PIN_ERROR_INCORRECT_CODE;
559 else if (error_name == NetworkDeviceHandler::kErrorPinBlocked)
560 pin_error = PIN_ERROR_BLOCKED;
562 pin_error = PIN_ERROR_UNKNOWN;
563 OnPinOperationCompleted(pin_error);
566 void SimUnlockHandler::HandleChangePinCode(const base::ListValue* args) {
567 const size_t kChangePinParamCount = 2;
570 if (args->GetSize() != kChangePinParamCount ||
571 !args->GetString(0, &pin) ||
572 !args->GetString(1, &new_pin)) {
577 HandleEnterCode(CODE_PIN, pin);
580 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type,
581 const std::string& code) {
582 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type);
583 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
584 base::Bind(&TaskProxy::HandleEnterCode, task.get()));
587 void SimUnlockHandler::HandleEnterPinCode(const base::ListValue* args) {
588 const size_t kEnterPinParamCount = 1;
590 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
594 HandleEnterCode(CODE_PIN, pin);
597 void SimUnlockHandler::HandleEnterPukCode(const base::ListValue* args) {
598 const size_t kEnterPukParamCount = 2;
601 if (args->GetSize() != kEnterPukParamCount ||
602 !args->GetString(0, &puk) ||
603 !args->GetString(1, &new_pin)) {
608 HandleEnterCode(CODE_PUK, puk);
611 void SimUnlockHandler::HandleProceedToPukInput(const base::ListValue* args) {
612 const size_t kProceedToPukInputParamCount = 0;
613 if (args->GetSize() != kProceedToPukInputParamCount) {
617 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
618 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
619 base::Bind(&TaskProxy::HandleProceedToPukInput, task.get()));
622 void SimUnlockHandler::HandleSimStatusInitialize(const base::ListValue* args) {
623 const size_t kSimStatusInitializeParamCount = 1;
625 if (args->GetSize() != kSimStatusInitializeParamCount ||
626 !args->GetDouble(0, &mode)) {
630 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode);
631 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_;
632 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
633 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
634 base::Bind(&TaskProxy::HandleInitialize, task.get()));
637 void SimUnlockHandler::InitializeSimStatus() {
638 DCHECK_CURRENTLY_ON(BrowserThread::UI);
639 // TODO(armansito): For now, we're initializing the device path to the first
640 // available cellular device. We should try to obtain a specific device here,
641 // as there can be multiple cellular devices present.
642 const DeviceState* cellular_device =
643 GetNetworkStateHandler()
644 ->GetDeviceStateByType(NetworkTypePattern::Cellular());
645 if (cellular_device) {
646 cellular_device_path_ = cellular_device->path();
647 sim_lock_type_ = cellular_device->sim_lock_type();
649 ProcessSimCardState(cellular_device);
652 void SimUnlockHandler::ProceedToPukInput() {
653 DCHECK_CURRENTLY_ON(BrowserThread::UI);
654 ProcessSimCardState(GetCellularDevice());
657 void SimUnlockHandler::ProcessSimCardState(
658 const DeviceState* cellular) {
659 std::string error_msg;
661 uint32 retries_left = cellular->sim_retries_left();
662 VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
663 << " retries: " << retries_left;
665 case SIM_UNLOCK_LOADING:
666 if (sim_lock_type_ == shill::kSIMLockPin) {
667 state_ = SIM_LOCKED_PIN;
668 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
669 if (retries_left > 0)
670 state_ = SIM_LOCKED_PUK;
672 state_ = SIM_DISABLED;
673 } else if (sim_lock_type_.empty()) {
674 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
675 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
676 state_ = SIM_NOT_LOCKED_ASK_PIN;
677 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
678 state_ = SIM_NOT_LOCKED_CHANGE_PIN;
680 state_ = SIM_ABSENT_NOT_LOCKED;
683 // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
684 // since this UI is accessible when SIM is initialized)
685 // or SIM card is absent. In latter case just close dialog.
686 state_ = SIM_ABSENT_NOT_LOCKED;
689 case SIM_ABSENT_NOT_LOCKED:
690 // Dialog will close itself in this case.
692 case SIM_NOT_LOCKED_ASK_PIN:
693 case SIM_NOT_LOCKED_CHANGE_PIN:
694 // We always start in these states when SIM is unlocked.
695 // So if we get here while still being UNLOCKED,
696 // that means entered PIN was incorrect.
697 if (sim_lock_type_.empty()) {
698 error_msg = kErrorPin;
699 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
700 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
703 << "Change PIN / Set lock mode with unexpected SIM lock state";
704 state_ = SIM_ABSENT_NOT_LOCKED;
708 if (sim_lock_type_ == shill::kSIMLockPuk) {
709 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
710 } else if (sim_lock_type_ == shill::kSIMLockPin) {
711 // Still locked with PIN.
712 error_msg = kErrorPin;
714 state_ = SIM_ABSENT_NOT_LOCKED;
717 case SIM_LOCKED_NO_PIN_TRIES_LEFT:
718 // Proceed user to PUK input.
719 state_ = SIM_LOCKED_PUK;
722 if (sim_lock_type_ != shill::kSIMLockPin &&
723 sim_lock_type_ != shill::kSIMLockPuk) {
724 state_ = SIM_ABSENT_NOT_LOCKED;
725 } else if (retries_left == 0) {
726 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
728 // Otherwise SIM card is still locked with PUK code.
729 // Dialog will display enter PUK screen with an updated retries count.
731 case SIM_LOCKED_NO_PUK_TRIES_LEFT:
733 // User will close dialog manually.
737 VLOG(1) << "Cellular device is absent.";
738 // No cellular device, should close dialog.
739 state_ = SIM_ABSENT_NOT_LOCKED;
741 VLOG(1) << "New state: " << state_;
742 UpdatePage(cellular, error_msg);
745 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
746 const std::string& error_msg) {
747 base::DictionaryValue sim_dict;
749 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
750 sim_dict.SetInteger(kState, state_);
751 if (!error_msg.empty())
752 sim_dict.SetString(kError, error_msg);
754 sim_dict.SetString(kError, kErrorOk);
755 web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
758 // SimUnlockUI -----------------------------------------------------------------
760 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) {
761 SimUnlockHandler* handler = new SimUnlockHandler();
762 web_ui->AddMessageHandler(handler);
763 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
765 // Set up the chrome://sim-unlock/ source.
766 Profile* profile = Profile::FromWebUI(web_ui);
767 content::URLDataSource::Add(profile, html_source);
770 } // namespace chromeos