Popular sites on the NTP: check that experiment group StartsWith (rather than IS...
[chromium-blink-merge.git] / chrome / browser / ui / webui / chromeos / sim_unlock_ui.cc
blob5f8718f73c105011946f941a4e6b9e907cc9ad74
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"
7 #include <string>
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/browser_process.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 "chrome/grit/generated_resources.h"
24 #include "chromeos/network/device_state.h"
25 #include "chromeos/network/network_device_handler.h"
26 #include "chromeos/network/network_event_log.h"
27 #include "chromeos/network/network_state_handler.h"
28 #include "chromeos/network/network_state_handler_observer.h"
29 #include "content/public/browser/browser_thread.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 "third_party/cros_system_api/dbus/service_constants.h"
36 #include "ui/base/l10n/l10n_util.h"
37 #include "ui/base/resource/resource_bundle.h"
38 #include "ui/base/webui/jstemplate_builder.h"
39 #include "ui/base/webui/web_ui_util.h"
41 using content::BrowserThread;
42 using content::WebContents;
43 using content::WebUIMessageHandler;
45 namespace {
47 // JS API callbacks names.
48 const char kJsApiChangePinCode[] = "changePinCode";
49 const char kJsApiEnterPinCode[] = "enterPinCode";
50 const char kJsApiEnterPukCode[] = "enterPukCode";
51 const char kJsApiProceedToPukInput[] = "proceedToPukInput";
52 const char kJsApiSimStatusInitialize[] = "simStatusInitialize";
54 // Page JS API function names.
55 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
57 // SIM state variables which are passed to the page.
58 const char kState[] = "state";
59 const char kError[] = "error";
60 const char kTriesLeft[] = "tries";
62 // Error constants, passed to the page.
63 const char kErrorPin[] = "incorrectPin";
64 const char kErrorOk[] = "ok";
66 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
67 return chromeos::NetworkHandler::Get()->network_device_handler();
70 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
71 return chromeos::NetworkHandler::Get()->network_state_handler();
74 } // namespace
76 namespace chromeos {
78 class SimUnlockUIHTMLSource : public content::URLDataSource {
79 public:
80 SimUnlockUIHTMLSource();
82 // content::URLDataSource implementation.
83 std::string GetSource() const override;
84 void StartDataRequest(
85 const std::string& path,
86 int render_process_id,
87 int render_frame_id,
88 const content::URLDataSource::GotDataCallback& callback) override;
89 std::string GetMimeType(const std::string&) const override {
90 return "text/html";
92 bool ShouldAddContentSecurityPolicy() const override { return false; }
94 private:
95 ~SimUnlockUIHTMLSource() override {}
97 std::string service_path_;
98 DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
101 // The handler for Javascript messages related to the "sim-unlock" view.
102 class SimUnlockHandler : public WebUIMessageHandler,
103 public base::SupportsWeakPtr<SimUnlockHandler>,
104 public NetworkStateHandlerObserver {
105 public:
106 SimUnlockHandler();
107 ~SimUnlockHandler() override;
109 // WebUIMessageHandler implementation.
110 void RegisterMessages() override;
112 // NetworkStateHandlerObserver implementation.
113 void DeviceListChanged() override;
115 private:
116 // Should keep this state enum in sync with similar one in JS code.
117 // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
118 // for PIN input because PinRequired preference change was requested.
119 // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
120 // and new PIN to change it.
121 typedef enum SimUnlockState {
122 SIM_UNLOCK_LOADING = -1,
123 SIM_ABSENT_NOT_LOCKED = 0,
124 SIM_NOT_LOCKED_ASK_PIN = 1,
125 SIM_NOT_LOCKED_CHANGE_PIN = 2,
126 SIM_LOCKED_PIN = 3,
127 SIM_LOCKED_NO_PIN_TRIES_LEFT = 4,
128 SIM_LOCKED_PUK = 5,
129 SIM_LOCKED_NO_PUK_TRIES_LEFT = 6,
130 SIM_DISABLED = 7,
131 } SimUnlockState;
133 // Type of the SIM unlock code.
134 enum SimUnlockCode {
135 CODE_PIN,
136 CODE_PUK
139 enum PinOperationError {
140 PIN_ERROR_NONE = 0,
141 PIN_ERROR_UNKNOWN = 1,
142 PIN_ERROR_INCORRECT_CODE = 2,
143 PIN_ERROR_BLOCKED = 3
146 class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
147 public:
148 explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
149 : handler_(handler),
150 code_type_() {
153 TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
154 const std::string& code,
155 SimUnlockCode code_type)
156 : handler_(handler),
157 code_(code),
158 code_type_(code_type) {
161 void HandleEnterCode() {
162 if (handler_)
163 handler_->EnterCode(code_, code_type_);
166 void HandleInitialize() {
167 if (handler_)
168 handler_->InitializeSimStatus();
171 void HandleProceedToPukInput() {
172 if (handler_)
173 handler_->ProceedToPukInput();
176 private:
177 friend class base::RefCountedThreadSafe<TaskProxy>;
179 ~TaskProxy() {}
181 base::WeakPtr<SimUnlockHandler> handler_;
183 // Pending code input (PIN/PUK).
184 std::string code_;
186 // Pending code type.
187 SimUnlockCode code_type_;
189 DISALLOW_COPY_AND_ASSIGN(TaskProxy);
192 // Returns the cellular device that this dialog currently corresponds to.
193 const DeviceState* GetCellularDevice();
195 // Pass PIN/PUK code to shill and check status.
196 void EnterCode(const std::string& code, SimUnlockCode code_type);
198 // Methods to invoke shill PIN/PUK D-Bus operations.
199 void ChangeRequirePin(bool require_pin, const std::string& pin);
200 void EnterPin(const std::string& pin);
201 void ChangePin(const std::string& old_pin, const std::string& new_pin);
202 void UnblockPin(const std::string& puk, const std::string& new_pin);
203 void PinOperationSuccessCallback(const std::string& operation_name);
204 void PinOperationErrorCallback(const std::string& operation_name,
205 const std::string& error_name,
206 scoped_ptr<base::DictionaryValue> error_data);
208 // Called when an asynchronous PIN operation has completed.
209 void OnPinOperationCompleted(PinOperationError error);
211 // Single handler for PIN/PUK code operations.
212 void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
214 // Handlers for JS WebUI messages.
215 void HandleChangePinCode(const base::ListValue* args);
216 void HandleEnterPinCode(const base::ListValue* args);
217 void HandleEnterPukCode(const base::ListValue* args);
218 void HandleProceedToPukInput(const base::ListValue* args);
219 void HandleSimStatusInitialize(const base::ListValue* args);
221 // Initialize current SIM card status, passes that to page.
222 void InitializeSimStatus();
224 // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
225 void ProceedToPukInput();
227 // Processes current SIM card state and update internal state/page.
228 void ProcessSimCardState(const DeviceState* cellular);
230 // Updates page with the current state/SIM card info/error.
231 void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
233 // Dialog internal state.
234 SimUnlockState state_;
236 // Path of the Cellular device that we monitor property updates from.
237 std::string cellular_device_path_;
239 // Type of the dialog: generic unlock/change pin/change PinRequire.
240 SimDialogDelegate::SimDialogMode dialog_mode_;
242 // New PIN value for the case when we unblock SIM card or change PIN.
243 std::string new_pin_;
245 // The initial lock type value, used to observe changes to lock status;
246 std::string sim_lock_type_;
248 // True if there's a pending PIN operation.
249 // That means that SIM lock state change will be received 2 times:
250 // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted.
251 // First one should be ignored.
252 bool pending_pin_operation_;
254 base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
256 DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
259 // SimUnlockUIHTMLSource -------------------------------------------------------
261 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
264 std::string SimUnlockUIHTMLSource::GetSource() const {
265 return chrome::kChromeUISimUnlockHost;
268 void SimUnlockUIHTMLSource::StartDataRequest(
269 const std::string& path,
270 int render_process_id,
271 int render_frame_id,
272 const content::URLDataSource::GotDataCallback& callback) {
273 base::DictionaryValue strings;
274 strings.SetString("title",
275 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
276 strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
277 strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
278 strings.SetString("enterPinTitle",
279 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
280 strings.SetString("enterPinMessage",
281 l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
282 strings.SetString("enterPinTriesMessage",
283 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
284 strings.SetString("incorrectPinTriesMessage",
285 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
286 strings.SetString("incorrectPinTitle",
287 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
288 // TODO(nkostylev): Pass carrier name if we know that.
289 strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
290 IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
291 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
292 strings.SetString("enterPukButton",
293 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
294 strings.SetString("enterPukTitle",
295 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
296 strings.SetString("enterPukWarning",
297 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
298 // TODO(nkostylev): Pass carrier name if we know that.
299 strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
300 IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
301 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
302 strings.SetString("choosePinTitle",
303 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
304 strings.SetString("choosePinMessage",
305 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
306 strings.SetString("newPin", l10n_util::GetStringUTF16(
307 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
308 strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
309 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
310 strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
311 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
312 strings.SetString("noPukTriesLeft",
313 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
314 strings.SetString("simDisabledTitle",
315 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
316 strings.SetString("simDisabledMessage",
317 l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
319 strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
320 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
321 strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
322 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
323 strings.SetString("oldPin", l10n_util::GetStringUTF16(
324 IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
326 const std::string& app_locale = g_browser_process->GetApplicationLocale();
327 webui::SetLoadTimeDataDefaults(app_locale, &strings);
329 static const base::StringPiece html(
330 ResourceBundle::GetSharedInstance().GetRawDataResource(
331 IDR_SIM_UNLOCK_HTML));
333 std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
334 callback.Run(base::RefCountedString::TakeString(&full_html));
337 // SimUnlockHandler ------------------------------------------------------------
339 SimUnlockHandler::SimUnlockHandler()
340 : state_(SIM_UNLOCK_LOADING),
341 dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK),
342 pending_pin_operation_(false),
343 weak_ptr_factory_(this) {
344 if (GetNetworkStateHandler()
345 ->GetTechnologyState(NetworkTypePattern::Cellular()) !=
346 NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)
347 GetNetworkStateHandler()->AddObserver(this, FROM_HERE);
350 SimUnlockHandler::~SimUnlockHandler() {
351 GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
354 void SimUnlockHandler::RegisterMessages() {
355 web_ui()->RegisterMessageCallback(kJsApiChangePinCode,
356 base::Bind(&SimUnlockHandler::HandleChangePinCode,
357 base::Unretained(this)));
358 web_ui()->RegisterMessageCallback(kJsApiEnterPinCode,
359 base::Bind(&SimUnlockHandler::HandleEnterPinCode,
360 base::Unretained(this)));
361 web_ui()->RegisterMessageCallback(kJsApiEnterPukCode,
362 base::Bind(&SimUnlockHandler::HandleEnterPukCode,
363 base::Unretained(this)));
364 web_ui()->RegisterMessageCallback(kJsApiProceedToPukInput,
365 base::Bind(&SimUnlockHandler::HandleProceedToPukInput,
366 base::Unretained(this)));
367 web_ui()->RegisterMessageCallback(kJsApiSimStatusInitialize,
368 base::Bind(&SimUnlockHandler::HandleSimStatusInitialize,
369 base::Unretained(this)));
372 void SimUnlockHandler::DeviceListChanged() {
373 const DeviceState* cellular_device = GetCellularDevice();
374 if (!cellular_device) {
375 LOG(WARNING) << "Cellular device with path '" << cellular_device_path_
376 << "' disappeared.";
377 ProcessSimCardState(NULL);
378 return;
381 // Process the SIM card state only if the lock state changed.
382 if (cellular_device->sim_lock_type() == sim_lock_type_)
383 return;
385 sim_lock_type_ = cellular_device->sim_lock_type();
386 uint32 retries_left = cellular_device->sim_retries_left();
387 VLOG(1) << "OnNetworkDeviceSimLockChanged, lock: " << sim_lock_type_
388 << ", retries: " << retries_left;
389 // There's a pending PIN operation.
390 // Wait for it to finish and refresh state then.
391 if (!pending_pin_operation_)
392 ProcessSimCardState(cellular_device);
395 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) {
396 pending_pin_operation_ = false;
397 VLOG(1) << "OnPinOperationCompleted, error: " << error;
398 const DeviceState* cellular = GetCellularDevice();
399 if (!cellular) {
400 VLOG(1) << "Cellular device disappeared. Dismissing dialog.";
401 ProcessSimCardState(NULL);
402 return;
404 if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) {
405 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
406 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF);
407 // Dialog will close itself.
408 state_ = SIM_ABSENT_NOT_LOCKED;
409 } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) {
410 CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
411 // Dialog will close itself.
412 state_ = SIM_ABSENT_NOT_LOCKED;
414 // If previous EnterPIN was last PIN attempt and SIMLock state was already
415 // processed by OnNetworkDeviceChanged, let dialog stay on
416 // NO_PIN_RETRIES_LEFT step.
417 if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED))
418 ProcessSimCardState(cellular);
421 const DeviceState* SimUnlockHandler::GetCellularDevice() {
422 return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
425 void SimUnlockHandler::EnterCode(const std::string& code,
426 SimUnlockCode code_type) {
427 DCHECK_CURRENTLY_ON(BrowserThread::UI);
429 pending_pin_operation_ = true;
431 switch (code_type) {
432 case CODE_PIN:
433 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
434 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
435 if (!sim_lock_type_.empty()) {
436 // If SIM is locked/absent, change RequirePin UI is not accessible.
437 NOTREACHED() <<
438 "Changing RequirePin pref on locked / uninitialized SIM.";
440 ChangeRequirePin(
441 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
442 code);
443 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
444 if (!sim_lock_type_.empty()) {
445 // If SIM is locked/absent, changing PIN UI is not accessible.
446 NOTREACHED() << "Changing PIN on locked / uninitialized SIM.";
448 ChangePin(code, new_pin_);
449 } else {
450 EnterPin(code);
452 break;
453 case CODE_PUK:
454 DCHECK(!new_pin_.empty());
455 UnblockPin(code, new_pin_);
456 break;
460 void SimUnlockHandler::ChangeRequirePin(bool require_pin,
461 const std::string& pin) {
462 const DeviceState* cellular = GetCellularDevice();
463 if (!cellular) {
464 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
465 return;
467 std::string operation_name = "ChangeRequirePin";
468 NET_LOG_USER(operation_name, cellular->path());
469 GetNetworkDeviceHandler()->RequirePin(
470 cellular->path(),
471 require_pin,
472 pin,
473 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
474 weak_ptr_factory_.GetWeakPtr(),
475 operation_name),
476 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
477 weak_ptr_factory_.GetWeakPtr(),
478 operation_name));
481 void SimUnlockHandler::EnterPin(const std::string& pin) {
482 const DeviceState* cellular = GetCellularDevice();
483 if (!cellular) {
484 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
485 return;
487 std::string operation_name = "EnterPin";
488 NET_LOG_USER(operation_name, cellular->path());
489 GetNetworkDeviceHandler()->EnterPin(
490 cellular->path(),
491 pin,
492 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
493 weak_ptr_factory_.GetWeakPtr(),
494 operation_name),
495 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
496 weak_ptr_factory_.GetWeakPtr(),
497 operation_name));
500 void SimUnlockHandler::ChangePin(const std::string& old_pin,
501 const std::string& new_pin) {
502 const DeviceState* cellular = GetCellularDevice();
503 if (!cellular) {
504 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
505 return;
507 std::string operation_name = "ChangePin";
508 NET_LOG_USER(operation_name, cellular->path());
509 GetNetworkDeviceHandler()->ChangePin(
510 cellular->path(),
511 old_pin,
512 new_pin,
513 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
514 weak_ptr_factory_.GetWeakPtr(),
515 operation_name),
516 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
517 weak_ptr_factory_.GetWeakPtr(),
518 operation_name));
521 void SimUnlockHandler::UnblockPin(const std::string& puk,
522 const std::string& new_pin) {
523 const DeviceState* cellular = GetCellularDevice();
524 if (!cellular) {
525 NOTREACHED() << "Calling RequirePin method w/o cellular device.";
526 return;
528 std::string operation_name = "UnblockPin";
529 NET_LOG_USER(operation_name, cellular->path());
530 GetNetworkDeviceHandler()->UnblockPin(
531 cellular->path(),
532 puk,
533 new_pin,
534 base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
535 weak_ptr_factory_.GetWeakPtr(),
536 operation_name),
537 base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
538 weak_ptr_factory_.GetWeakPtr(),
539 operation_name));
542 void SimUnlockHandler::PinOperationSuccessCallback(
543 const std::string& operation_name) {
544 NET_LOG_DEBUG("Pin operation successful.", operation_name);
545 OnPinOperationCompleted(PIN_ERROR_NONE);
548 void SimUnlockHandler::PinOperationErrorCallback(
549 const std::string& operation_name,
550 const std::string& error_name,
551 scoped_ptr<base::DictionaryValue> error_data) {
552 NET_LOG_ERROR("Pin operation failed: " + error_name, operation_name);
553 PinOperationError pin_error;
554 if (error_name == NetworkDeviceHandler::kErrorIncorrectPin ||
555 error_name == NetworkDeviceHandler::kErrorPinRequired)
556 pin_error = PIN_ERROR_INCORRECT_CODE;
557 else if (error_name == NetworkDeviceHandler::kErrorPinBlocked)
558 pin_error = PIN_ERROR_BLOCKED;
559 else
560 pin_error = PIN_ERROR_UNKNOWN;
561 OnPinOperationCompleted(pin_error);
564 void SimUnlockHandler::HandleChangePinCode(const base::ListValue* args) {
565 const size_t kChangePinParamCount = 2;
566 std::string pin;
567 std::string new_pin;
568 if (args->GetSize() != kChangePinParamCount ||
569 !args->GetString(0, &pin) ||
570 !args->GetString(1, &new_pin)) {
571 NOTREACHED();
572 return;
574 new_pin_ = new_pin;
575 HandleEnterCode(CODE_PIN, pin);
578 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type,
579 const std::string& code) {
580 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type);
581 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
582 base::Bind(&TaskProxy::HandleEnterCode, task.get()));
585 void SimUnlockHandler::HandleEnterPinCode(const base::ListValue* args) {
586 const size_t kEnterPinParamCount = 1;
587 std::string pin;
588 if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
589 NOTREACHED();
590 return;
592 HandleEnterCode(CODE_PIN, pin);
595 void SimUnlockHandler::HandleEnterPukCode(const base::ListValue* args) {
596 const size_t kEnterPukParamCount = 2;
597 std::string puk;
598 std::string new_pin;
599 if (args->GetSize() != kEnterPukParamCount ||
600 !args->GetString(0, &puk) ||
601 !args->GetString(1, &new_pin)) {
602 NOTREACHED();
603 return;
605 new_pin_ = new_pin;
606 HandleEnterCode(CODE_PUK, puk);
609 void SimUnlockHandler::HandleProceedToPukInput(const base::ListValue* args) {
610 const size_t kProceedToPukInputParamCount = 0;
611 if (args->GetSize() != kProceedToPukInputParamCount) {
612 NOTREACHED();
613 return;
615 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
616 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
617 base::Bind(&TaskProxy::HandleProceedToPukInput, task.get()));
620 void SimUnlockHandler::HandleSimStatusInitialize(const base::ListValue* args) {
621 const size_t kSimStatusInitializeParamCount = 1;
622 double mode;
623 if (args->GetSize() != kSimStatusInitializeParamCount ||
624 !args->GetDouble(0, &mode)) {
625 NOTREACHED();
626 return;
628 dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode);
629 VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_;
630 scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
631 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
632 base::Bind(&TaskProxy::HandleInitialize, task.get()));
635 void SimUnlockHandler::InitializeSimStatus() {
636 DCHECK_CURRENTLY_ON(BrowserThread::UI);
637 // TODO(armansito): For now, we're initializing the device path to the first
638 // available cellular device. We should try to obtain a specific device here,
639 // as there can be multiple cellular devices present.
640 const DeviceState* cellular_device =
641 GetNetworkStateHandler()
642 ->GetDeviceStateByType(NetworkTypePattern::Cellular());
643 if (cellular_device) {
644 cellular_device_path_ = cellular_device->path();
645 sim_lock_type_ = cellular_device->sim_lock_type();
647 ProcessSimCardState(cellular_device);
650 void SimUnlockHandler::ProceedToPukInput() {
651 DCHECK_CURRENTLY_ON(BrowserThread::UI);
652 ProcessSimCardState(GetCellularDevice());
655 void SimUnlockHandler::ProcessSimCardState(
656 const DeviceState* cellular) {
657 std::string error_msg;
658 if (cellular) {
659 uint32 retries_left = cellular->sim_retries_left();
660 VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
661 << " retries: " << retries_left;
662 switch (state_) {
663 case SIM_UNLOCK_LOADING:
664 if (sim_lock_type_ == shill::kSIMLockPin) {
665 state_ = SIM_LOCKED_PIN;
666 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
667 if (retries_left > 0)
668 state_ = SIM_LOCKED_PUK;
669 else
670 state_ = SIM_DISABLED;
671 } else if (sim_lock_type_.empty()) {
672 if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
673 dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
674 state_ = SIM_NOT_LOCKED_ASK_PIN;
675 } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
676 state_ = SIM_NOT_LOCKED_CHANGE_PIN;
677 } else {
678 state_ = SIM_ABSENT_NOT_LOCKED;
680 } else {
681 // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
682 // since this UI is accessible when SIM is initialized)
683 // or SIM card is absent. In latter case just close dialog.
684 state_ = SIM_ABSENT_NOT_LOCKED;
686 break;
687 case SIM_ABSENT_NOT_LOCKED:
688 // Dialog will close itself in this case.
689 break;
690 case SIM_NOT_LOCKED_ASK_PIN:
691 case SIM_NOT_LOCKED_CHANGE_PIN:
692 // We always start in these states when SIM is unlocked.
693 // So if we get here while still being UNLOCKED,
694 // that means entered PIN was incorrect.
695 if (sim_lock_type_.empty()) {
696 error_msg = kErrorPin;
697 } else if (sim_lock_type_ == shill::kSIMLockPuk) {
698 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
699 } else {
700 NOTREACHED()
701 << "Change PIN / Set lock mode with unexpected SIM lock state";
702 state_ = SIM_ABSENT_NOT_LOCKED;
704 break;
705 case SIM_LOCKED_PIN:
706 if (sim_lock_type_ == shill::kSIMLockPuk) {
707 state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
708 } else if (sim_lock_type_ == shill::kSIMLockPin) {
709 // Still locked with PIN.
710 error_msg = kErrorPin;
711 } else {
712 state_ = SIM_ABSENT_NOT_LOCKED;
714 break;
715 case SIM_LOCKED_NO_PIN_TRIES_LEFT:
716 // Proceed user to PUK input.
717 state_ = SIM_LOCKED_PUK;
718 break;
719 case SIM_LOCKED_PUK:
720 if (sim_lock_type_ != shill::kSIMLockPin &&
721 sim_lock_type_ != shill::kSIMLockPuk) {
722 state_ = SIM_ABSENT_NOT_LOCKED;
723 } else if (retries_left == 0) {
724 state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
726 // Otherwise SIM card is still locked with PUK code.
727 // Dialog will display enter PUK screen with an updated retries count.
728 break;
729 case SIM_LOCKED_NO_PUK_TRIES_LEFT:
730 case SIM_DISABLED:
731 // User will close dialog manually.
732 break;
734 } else {
735 VLOG(1) << "Cellular device is absent.";
736 // No cellular device, should close dialog.
737 state_ = SIM_ABSENT_NOT_LOCKED;
739 VLOG(1) << "New state: " << state_;
740 UpdatePage(cellular, error_msg);
743 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
744 const std::string& error_msg) {
745 base::DictionaryValue sim_dict;
746 if (cellular)
747 sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
748 sim_dict.SetInteger(kState, state_);
749 if (!error_msg.empty())
750 sim_dict.SetString(kError, error_msg);
751 else
752 sim_dict.SetString(kError, kErrorOk);
753 web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
756 // SimUnlockUI -----------------------------------------------------------------
758 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) {
759 SimUnlockHandler* handler = new SimUnlockHandler();
760 web_ui->AddMessageHandler(handler);
761 SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
763 // Set up the chrome://sim-unlock/ source.
764 Profile* profile = Profile::FromWebUI(web_ui);
765 content::URLDataSource::Add(profile, html_source);
768 } // namespace chromeos