Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / chromeos / sim_unlock_ui.cc
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/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"
39
40 using content::BrowserThread;
41 using content::WebContents;
42 using content::WebUIMessageHandler;
43
44 namespace {
45
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";
52
53 // Page JS API function names.
54 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
55
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";
60
61 // Error constants, passed to the page.
62 const char kErrorPin[] = "incorrectPin";
63 const char kErrorOk[] = "ok";
64
65 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
66   return chromeos::NetworkHandler::Get()->network_device_handler();
67 }
68
69 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
70   return chromeos::NetworkHandler::Get()->network_state_handler();
71 }
72
73 }  // namespace
74
75 namespace chromeos {
76
77 class SimUnlockUIHTMLSource : public content::URLDataSource {
78  public:
79   SimUnlockUIHTMLSource();
80
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,
86       int render_frame_id,
87       const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
88   virtual std::string GetMimeType(const std::string&) const OVERRIDE {
89     return "text/html";
90   }
91   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
92     return false;
93   }
94
95  private:
96   virtual ~SimUnlockUIHTMLSource() {}
97
98   std::string service_path_;
99   DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
100 };
101
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 {
106  public:
107   SimUnlockHandler();
108   virtual ~SimUnlockHandler();
109
110   // WebUIMessageHandler implementation.
111   virtual void RegisterMessages() OVERRIDE;
112
113   // NetworkStateHandlerObserver implementation.
114   virtual void DeviceListChanged() OVERRIDE;
115
116  private:
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,
127     SIM_LOCKED_PIN               =  3,
128     SIM_LOCKED_NO_PIN_TRIES_LEFT =  4,
129     SIM_LOCKED_PUK               =  5,
130     SIM_LOCKED_NO_PUK_TRIES_LEFT =  6,
131     SIM_DISABLED                 =  7,
132   } SimUnlockState;
133
134   // Type of the SIM unlock code.
135   enum SimUnlockCode {
136     CODE_PIN,
137     CODE_PUK
138   };
139
140   enum PinOperationError {
141     PIN_ERROR_NONE = 0,
142     PIN_ERROR_UNKNOWN = 1,
143     PIN_ERROR_INCORRECT_CODE = 2,
144     PIN_ERROR_BLOCKED = 3
145   };
146
147   class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
148    public:
149     explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
150         : handler_(handler),
151           code_type_() {
152     }
153
154     TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
155               const std::string& code,
156               SimUnlockCode code_type)
157         : handler_(handler),
158           code_(code),
159           code_type_(code_type) {
160     }
161
162     void HandleEnterCode() {
163       if (handler_)
164         handler_->EnterCode(code_, code_type_);
165     }
166
167     void HandleInitialize() {
168       if (handler_)
169         handler_->InitializeSimStatus();
170     }
171
172     void HandleProceedToPukInput() {
173       if (handler_)
174         handler_->ProceedToPukInput();
175     }
176
177    private:
178     friend class base::RefCountedThreadSafe<TaskProxy>;
179
180     ~TaskProxy() {}
181
182     base::WeakPtr<SimUnlockHandler> handler_;
183
184     // Pending code input (PIN/PUK).
185     std::string code_;
186
187     // Pending code type.
188     SimUnlockCode code_type_;
189
190     DISALLOW_COPY_AND_ASSIGN(TaskProxy);
191   };
192
193   // Returns the cellular device that this dialog currently corresponds to.
194   const DeviceState* GetCellularDevice();
195
196   // Pass PIN/PUK code to shill and check status.
197   void EnterCode(const std::string& code, SimUnlockCode code_type);
198
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);
208
209   // Called when an asynchronous PIN operation has completed.
210   void OnPinOperationCompleted(PinOperationError error);
211
212   // Single handler for PIN/PUK code operations.
213   void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
214
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);
221
222   // Initialize current SIM card status, passes that to page.
223   void InitializeSimStatus();
224
225   // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
226   void ProceedToPukInput();
227
228   // Processes current SIM card state and update internal state/page.
229   void ProcessSimCardState(const DeviceState* cellular);
230
231   // Updates page with the current state/SIM card info/error.
232   void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
233
234   // Dialog internal state.
235   SimUnlockState state_;
236
237   // Path of the Cellular device that we monitor property updates from.
238   std::string cellular_device_path_;
239
240   // Type of the dialog: generic unlock/change pin/change PinRequire.
241   SimDialogDelegate::SimDialogMode dialog_mode_;
242
243   // New PIN value for the case when we unblock SIM card or change PIN.
244   std::string new_pin_;
245
246   // The initial lock type value, used to observe changes to lock status;
247   std::string sim_lock_type_;
248
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_;
254
255   base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
256
257   DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
258 };
259
260 // SimUnlockUIHTMLSource -------------------------------------------------------
261
262 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
263 }
264
265 std::string SimUnlockUIHTMLSource::GetSource() const {
266   return chrome::kChromeUISimUnlockHost;
267 }
268
269 void SimUnlockUIHTMLSource::StartDataRequest(
270     const std::string& path,
271     int render_process_id,
272     int render_frame_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));
319
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));
326
327   webui::SetFontAndTextDirection(&strings);
328
329   static const base::StringPiece html(
330       ResourceBundle::GetSharedInstance().GetRawDataResource(
331           IDR_SIM_UNLOCK_HTML));
332
333   webui::UseVersion2 version2;
334   std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
335
336   callback.Run(base::RefCountedString::TakeString(&full_html));
337 }
338
339 // SimUnlockHandler ------------------------------------------------------------
340
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);
350 }
351
352 SimUnlockHandler::~SimUnlockHandler() {
353   GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
354 }
355
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)));
372 }
373
374 void SimUnlockHandler::DeviceListChanged() {
375   const DeviceState* cellular_device = GetCellularDevice();
376   if (!cellular_device) {
377     LOG(WARNING) << "Cellular device with path '" << cellular_device_path_
378                  << "' disappeared.";
379     ProcessSimCardState(NULL);
380     return;
381   }
382
383   // Process the SIM card state only if the lock state changed.
384   if (cellular_device->sim_lock_type() == sim_lock_type_)
385     return;
386
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);
395 }
396
397 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) {
398   pending_pin_operation_ = false;
399   VLOG(1) << "OnPinOperationCompleted, error: " << error;
400   const DeviceState* cellular = GetCellularDevice();
401   if (!cellular) {
402     VLOG(1) << "Cellular device disappeared. Dismissing dialog.";
403     ProcessSimCardState(NULL);
404     return;
405   }
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;
415   }
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);
421 }
422
423 const DeviceState* SimUnlockHandler::GetCellularDevice() {
424   return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
425 }
426
427 void SimUnlockHandler::EnterCode(const std::string& code,
428                                  SimUnlockCode code_type) {
429   DCHECK_CURRENTLY_ON(BrowserThread::UI);
430
431   pending_pin_operation_ = true;
432
433   switch (code_type) {
434     case CODE_PIN:
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.
439           NOTREACHED() <<
440               "Changing RequirePin pref on locked / uninitialized SIM.";
441         }
442         ChangeRequirePin(
443             dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
444             code);
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.";
449         }
450         ChangePin(code, new_pin_);
451       } else {
452         EnterPin(code);
453       }
454       break;
455     case CODE_PUK:
456       DCHECK(!new_pin_.empty());
457       UnblockPin(code, new_pin_);
458       break;
459   }
460 }
461
462 void SimUnlockHandler::ChangeRequirePin(bool require_pin,
463                                         const std::string& pin) {
464   const DeviceState* cellular = GetCellularDevice();
465   if (!cellular) {
466     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
467     return;
468   }
469   std::string operation_name = "ChangeRequirePin";
470   NET_LOG_USER(operation_name, cellular->path());
471   GetNetworkDeviceHandler()->RequirePin(
472       cellular->path(),
473       require_pin,
474       pin,
475       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
476                  weak_ptr_factory_.GetWeakPtr(),
477                  operation_name),
478       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
479                  weak_ptr_factory_.GetWeakPtr(),
480                  operation_name));
481 }
482
483 void SimUnlockHandler::EnterPin(const std::string& pin) {
484   const DeviceState* cellular = GetCellularDevice();
485   if (!cellular) {
486     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
487     return;
488   }
489   std::string operation_name = "EnterPin";
490   NET_LOG_USER(operation_name, cellular->path());
491   GetNetworkDeviceHandler()->EnterPin(
492       cellular->path(),
493       pin,
494       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
495                  weak_ptr_factory_.GetWeakPtr(),
496                  operation_name),
497       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
498                  weak_ptr_factory_.GetWeakPtr(),
499                  operation_name));
500 }
501
502 void SimUnlockHandler::ChangePin(const std::string& old_pin,
503                                  const std::string& new_pin) {
504   const DeviceState* cellular = GetCellularDevice();
505   if (!cellular) {
506     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
507     return;
508   }
509   std::string operation_name = "ChangePin";
510   NET_LOG_USER(operation_name, cellular->path());
511   GetNetworkDeviceHandler()->ChangePin(
512       cellular->path(),
513       old_pin,
514       new_pin,
515       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
516                  weak_ptr_factory_.GetWeakPtr(),
517                  operation_name),
518       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
519                  weak_ptr_factory_.GetWeakPtr(),
520                  operation_name));
521 }
522
523 void SimUnlockHandler::UnblockPin(const std::string& puk,
524                                   const std::string& new_pin) {
525   const DeviceState* cellular = GetCellularDevice();
526   if (!cellular) {
527     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
528     return;
529   }
530   std::string operation_name = "UnblockPin";
531   NET_LOG_USER(operation_name, cellular->path());
532   GetNetworkDeviceHandler()->UnblockPin(
533       cellular->path(),
534       puk,
535       new_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::PinOperationSuccessCallback(
545     const std::string& operation_name) {
546   NET_LOG_DEBUG("Pin operation successful.", operation_name);
547   OnPinOperationCompleted(PIN_ERROR_NONE);
548 }
549
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;
561   else
562     pin_error = PIN_ERROR_UNKNOWN;
563   OnPinOperationCompleted(pin_error);
564 }
565
566 void SimUnlockHandler::HandleChangePinCode(const base::ListValue* args) {
567   const size_t kChangePinParamCount = 2;
568   std::string pin;
569   std::string new_pin;
570   if (args->GetSize() != kChangePinParamCount ||
571       !args->GetString(0, &pin) ||
572       !args->GetString(1, &new_pin)) {
573     NOTREACHED();
574     return;
575   }
576   new_pin_ = new_pin;
577   HandleEnterCode(CODE_PIN, pin);
578 }
579
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()));
585 }
586
587 void SimUnlockHandler::HandleEnterPinCode(const base::ListValue* args) {
588   const size_t kEnterPinParamCount = 1;
589   std::string pin;
590   if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
591     NOTREACHED();
592     return;
593   }
594   HandleEnterCode(CODE_PIN, pin);
595 }
596
597 void SimUnlockHandler::HandleEnterPukCode(const base::ListValue* args) {
598   const size_t kEnterPukParamCount = 2;
599   std::string puk;
600   std::string new_pin;
601   if (args->GetSize() != kEnterPukParamCount ||
602       !args->GetString(0, &puk) ||
603       !args->GetString(1, &new_pin)) {
604     NOTREACHED();
605     return;
606   }
607   new_pin_ = new_pin;
608   HandleEnterCode(CODE_PUK, puk);
609 }
610
611 void SimUnlockHandler::HandleProceedToPukInput(const base::ListValue* args) {
612   const size_t kProceedToPukInputParamCount = 0;
613   if (args->GetSize() != kProceedToPukInputParamCount) {
614     NOTREACHED();
615     return;
616   }
617   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
618   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
619       base::Bind(&TaskProxy::HandleProceedToPukInput, task.get()));
620 }
621
622 void SimUnlockHandler::HandleSimStatusInitialize(const base::ListValue* args) {
623   const size_t kSimStatusInitializeParamCount = 1;
624   double mode;
625   if (args->GetSize() != kSimStatusInitializeParamCount ||
626       !args->GetDouble(0, &mode)) {
627     NOTREACHED();
628     return;
629   }
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()));
635 }
636
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();
648   }
649   ProcessSimCardState(cellular_device);
650 }
651
652 void SimUnlockHandler::ProceedToPukInput() {
653   DCHECK_CURRENTLY_ON(BrowserThread::UI);
654   ProcessSimCardState(GetCellularDevice());
655 }
656
657 void SimUnlockHandler::ProcessSimCardState(
658     const DeviceState* cellular) {
659   std::string error_msg;
660   if (cellular) {
661     uint32 retries_left = cellular->sim_retries_left();
662     VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
663             << " retries: " << retries_left;
664     switch (state_) {
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;
671           else
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;
679           } else {
680             state_ = SIM_ABSENT_NOT_LOCKED;
681           }
682         } else {
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;
687         }
688         break;
689       case SIM_ABSENT_NOT_LOCKED:
690         // Dialog will close itself in this case.
691         break;
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;
701         } else {
702           NOTREACHED()
703               << "Change PIN / Set lock mode with unexpected SIM lock state";
704           state_ = SIM_ABSENT_NOT_LOCKED;
705         }
706         break;
707       case SIM_LOCKED_PIN:
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;
713         } else {
714           state_ = SIM_ABSENT_NOT_LOCKED;
715         }
716         break;
717       case SIM_LOCKED_NO_PIN_TRIES_LEFT:
718         // Proceed user to PUK input.
719         state_ = SIM_LOCKED_PUK;
720         break;
721       case 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;
727         }
728         // Otherwise SIM card is still locked with PUK code.
729         // Dialog will display enter PUK screen with an updated retries count.
730         break;
731       case SIM_LOCKED_NO_PUK_TRIES_LEFT:
732       case SIM_DISABLED:
733         // User will close dialog manually.
734         break;
735     }
736   } else {
737     VLOG(1) << "Cellular device is absent.";
738     // No cellular device, should close dialog.
739     state_ = SIM_ABSENT_NOT_LOCKED;
740   }
741   VLOG(1) << "New state: " << state_;
742   UpdatePage(cellular, error_msg);
743 }
744
745 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
746                                   const std::string& error_msg) {
747   base::DictionaryValue sim_dict;
748   if (cellular)
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);
753   else
754     sim_dict.SetString(kError, kErrorOk);
755   web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
756 }
757
758 // SimUnlockUI -----------------------------------------------------------------
759
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();
764
765   // Set up the chrome://sim-unlock/ source.
766   Profile* profile = Profile::FromWebUI(web_ui);
767   content::URLDataSource::Add(profile, html_source);
768 }
769
770 }  // namespace chromeos