• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
GetCellularDevice()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);
GetMimeType(const std::string &) const72   virtual std::string GetMimeType(const std::string&) const {
73     return "text/html";
74   }
75 
76  private:
~SimUnlockUIHTMLSource()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:
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler)133     explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
134         : handler_(handler) {
135     }
136 
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler,const std::string & code,SimUnlockCode code_type)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 
HandleCancel()145     void HandleCancel() {
146       if (handler_)
147         handler_->CancelDialog();
148     }
149 
HandleEnterCode()150     void HandleEnterCode() {
151       if (handler_)
152         handler_->EnterCode(code_, code_type_);
153     }
154 
HandleInitialize()155     void HandleInitialize() {
156       if (handler_)
157         handler_->InitializeSimStatus();
158     }
159 
HandleProceedToPukInput()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 
SimUnlockUIHTMLSource()232 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource()
233     : DataSource(chrome::kChromeUISimUnlockHost, MessageLoop::current()) {
234 }
235 
StartDataRequest(const std::string & path,bool is_incognito,int request_id)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 
SimUnlockHandler()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 
~SimUnlockHandler()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 
Attach(WebUI * web_ui)332 WebUIMessageHandler* SimUnlockHandler::Attach(WebUI* web_ui) {
333   return WebUIMessageHandler::Attach(web_ui);
334 }
335 
Init(TabContents * contents)336 void SimUnlockHandler::Init(TabContents* contents) {
337   tab_contents_ = contents;
338 }
339 
RegisterMessages()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 
OnNetworkDeviceChanged(NetworkLibrary * cros,const NetworkDevice * device)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 
OnPinOperationCompleted(NetworkLibrary * cros,PinOperationError error)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 
CancelDialog()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 
EnterCode(const std::string & code,SimUnlockCode code_type)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 
NotifyOnEnterPinEnded(bool cancelled)445 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) {
446   NotificationService::current()->Notify(
447       NotificationType::ENTER_PIN_ENDED,
448       NotificationService::AllSources(),
449       Details<bool>(&cancelled));
450 }
451 
NotifyOnRequirePinChangeEnded(bool new_value)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 
HandleCancel(const ListValue * args)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 
HandleChangePinCode(const ListValue * args)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 
HandleEnterCode(SimUnlockCode code_type,const std::string & code)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 
HandleEnterPinCode(const ListValue * args)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 
HandleEnterPukCode(const ListValue * args)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 
HandleProceedToPukInput(const ListValue * args)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 
HandleSimStatusInitialize(const ListValue * args)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 
InitializeSimStatus()541 void SimUnlockHandler::InitializeSimStatus() {
542   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
543   ProcessSimCardState(GetCellularDevice());
544 }
545 
ProceedToPukInput()546 void SimUnlockHandler::ProceedToPukInput() {
547   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
548   ProcessSimCardState(GetCellularDevice());
549 }
550 
ProcessSimCardState(const chromeos::NetworkDevice * cellular)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 
UpdatePage(const chromeos::NetworkDevice * cellular,const std::string & error_msg)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 
SimUnlockUI(TabContents * contents)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