• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/chrome_notification_types.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 "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/notification_service.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 "grit/generated_resources.h"
36 #include "third_party/cros_system_api/dbus/service_constants.h"
37 #include "ui/base/l10n/l10n_util.h"
38 #include "ui/base/resource/resource_bundle.h"
39 #include "ui/base/webui/jstemplate_builder.h"
40 #include "ui/base/webui/web_ui_util.h"
41 
42 using content::BrowserThread;
43 using content::WebContents;
44 using content::WebUIMessageHandler;
45 
46 namespace {
47 
48 // JS API callbacks names.
49 const char kJsApiCancel[] = "cancel";
50 const char kJsApiChangePinCode[] = "changePinCode";
51 const char kJsApiEnterPinCode[] = "enterPinCode";
52 const char kJsApiEnterPukCode[] = "enterPukCode";
53 const char kJsApiProceedToPukInput[] = "proceedToPukInput";
54 const char kJsApiSimStatusInitialize[] = "simStatusInitialize";
55 
56 // Page JS API function names.
57 const char kJsApiSimStatusChanged[] = "mobile.SimUnlock.simStateChanged";
58 
59 // SIM state variables which are passed to the page.
60 const char kState[] = "state";
61 const char kError[] = "error";
62 const char kTriesLeft[] = "tries";
63 
64 // Error constants, passed to the page.
65 const char kErrorPin[] = "incorrectPin";
66 const char kErrorOk[] = "ok";
67 
GetNetworkDeviceHandler()68 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
69   return chromeos::NetworkHandler::Get()->network_device_handler();
70 }
71 
GetNetworkStateHandler()72 chromeos::NetworkStateHandler* GetNetworkStateHandler() {
73   return chromeos::NetworkHandler::Get()->network_state_handler();
74 }
75 
76 }  // namespace
77 
78 namespace chromeos {
79 
80 class SimUnlockUIHTMLSource : public content::URLDataSource {
81  public:
82   SimUnlockUIHTMLSource();
83 
84   // content::URLDataSource implementation.
85   virtual std::string GetSource() const OVERRIDE;
86   virtual void StartDataRequest(
87       const std::string& path,
88       int render_process_id,
89       int render_frame_id,
90       const content::URLDataSource::GotDataCallback& callback) OVERRIDE;
GetMimeType(const std::string &) const91   virtual std::string GetMimeType(const std::string&) const OVERRIDE {
92     return "text/html";
93   }
ShouldAddContentSecurityPolicy() const94   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
95     return false;
96   }
97 
98  private:
~SimUnlockUIHTMLSource()99   virtual ~SimUnlockUIHTMLSource() {}
100 
101   std::string service_path_;
102   DISALLOW_COPY_AND_ASSIGN(SimUnlockUIHTMLSource);
103 };
104 
105 // The handler for Javascript messages related to the "sim-unlock" view.
106 class SimUnlockHandler : public WebUIMessageHandler,
107                          public base::SupportsWeakPtr<SimUnlockHandler>,
108                          public NetworkStateHandlerObserver {
109  public:
110   SimUnlockHandler();
111   virtual ~SimUnlockHandler();
112 
113   // WebUIMessageHandler implementation.
114   virtual void RegisterMessages() OVERRIDE;
115 
116   // NetworkStateHandlerObserver implementation.
117   virtual void DeviceListChanged() OVERRIDE;
118 
119  private:
120   // Should keep this state enum in sync with similar one in JS code.
121   // SIM_NOT_LOCKED_ASK_PIN - SIM card is not locked but we ask user
122   // for PIN input because PinRequired preference change was requested.
123   // SIM_NOT_LOCKED_CHANGE_PIN - SIM card is not locked, ask user for old PIN
124   // and new PIN to change it.
125   typedef enum SimUnlockState {
126     SIM_UNLOCK_LOADING           = -1,
127     SIM_ABSENT_NOT_LOCKED        =  0,
128     SIM_NOT_LOCKED_ASK_PIN       =  1,
129     SIM_NOT_LOCKED_CHANGE_PIN    =  2,
130     SIM_LOCKED_PIN               =  3,
131     SIM_LOCKED_NO_PIN_TRIES_LEFT =  4,
132     SIM_LOCKED_PUK               =  5,
133     SIM_LOCKED_NO_PUK_TRIES_LEFT =  6,
134     SIM_DISABLED                 =  7,
135   } SimUnlockState;
136 
137   // Type of the SIM unlock code.
138   enum SimUnlockCode {
139     CODE_PIN,
140     CODE_PUK
141   };
142 
143   enum PinOperationError {
144     PIN_ERROR_NONE = 0,
145     PIN_ERROR_UNKNOWN = 1,
146     PIN_ERROR_INCORRECT_CODE = 2,
147     PIN_ERROR_BLOCKED = 3
148   };
149 
150   class TaskProxy : public base::RefCountedThreadSafe<TaskProxy> {
151    public:
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler)152     explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
153         : handler_(handler),
154           code_type_() {
155     }
156 
TaskProxy(const base::WeakPtr<SimUnlockHandler> & handler,const std::string & code,SimUnlockCode code_type)157     TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler,
158               const std::string& code,
159               SimUnlockCode code_type)
160         : handler_(handler),
161           code_(code),
162           code_type_(code_type) {
163     }
164 
HandleCancel()165     void HandleCancel() {
166       if (handler_)
167         handler_->CancelDialog();
168     }
169 
HandleEnterCode()170     void HandleEnterCode() {
171       if (handler_)
172         handler_->EnterCode(code_, code_type_);
173     }
174 
HandleInitialize()175     void HandleInitialize() {
176       if (handler_)
177         handler_->InitializeSimStatus();
178     }
179 
HandleProceedToPukInput()180     void HandleProceedToPukInput() {
181       if (handler_)
182         handler_->ProceedToPukInput();
183     }
184 
185    private:
186     friend class base::RefCountedThreadSafe<TaskProxy>;
187 
~TaskProxy()188     ~TaskProxy() {}
189 
190     base::WeakPtr<SimUnlockHandler> handler_;
191 
192     // Pending code input (PIN/PUK).
193     std::string code_;
194 
195     // Pending code type.
196     SimUnlockCode code_type_;
197 
198     DISALLOW_COPY_AND_ASSIGN(TaskProxy);
199   };
200 
201   // Returns the cellular device that this dialog currently corresponds to.
202   const DeviceState* GetCellularDevice();
203 
204   // Processing for the cases when dialog was cancelled.
205   void CancelDialog();
206 
207   // Pass PIN/PUK code to shill and check status.
208   void EnterCode(const std::string& code, SimUnlockCode code_type);
209 
210   // Methods to invoke shill PIN/PUK D-Bus operations.
211   void ChangeRequirePin(bool require_pin, const std::string& pin);
212   void EnterPin(const std::string& pin);
213   void ChangePin(const std::string& old_pin, const std::string& new_pin);
214   void UnblockPin(const std::string& puk, const std::string& new_pin);
215   void PinOperationSuccessCallback(const std::string& operation_name);
216   void PinOperationErrorCallback(const std::string& operation_name,
217                                  const std::string& error_name,
218                                  scoped_ptr<base::DictionaryValue> error_data);
219 
220   // Called when an asynchronous PIN operation has completed.
221   void OnPinOperationCompleted(PinOperationError error);
222 
223   // Single handler for PIN/PUK code operations.
224   void HandleEnterCode(SimUnlockCode code_type, const std::string& code);
225 
226   // Handlers for JS WebUI messages.
227   void HandleCancel(const base::ListValue* args);
228   void HandleChangePinCode(const base::ListValue* args);
229   void HandleEnterPinCode(const base::ListValue* args);
230   void HandleEnterPukCode(const base::ListValue* args);
231   void HandleProceedToPukInput(const base::ListValue* args);
232   void HandleSimStatusInitialize(const base::ListValue* args);
233 
234   // Initialize current SIM card status, passes that to page.
235   void InitializeSimStatus();
236 
237   // Notifies SIM Security tab handler that RequirePin preference change
238   // has been ended (either updated or cancelled).
239   void NotifyOnRequirePinChangeEnded(bool new_value);
240 
241   // Notifies observers that the EnterPin or EnterPuk dialog has been
242   // completed (either cancelled or with entry of PIN/PUK).
243   void NotifyOnEnterPinEnded(bool cancelled);
244 
245   // Checks whether SIM card is in PUK locked state and proceeds to PUK input.
246   void ProceedToPukInput();
247 
248   // Processes current SIM card state and update internal state/page.
249   void ProcessSimCardState(const DeviceState* cellular);
250 
251   // Updates page with the current state/SIM card info/error.
252   void UpdatePage(const DeviceState* cellular, const std::string& error_msg);
253 
254   // Dialog internal state.
255   SimUnlockState state_;
256 
257   // Path of the Cellular device that we monitor property updates from.
258   std::string cellular_device_path_;
259 
260   // Type of the dialog: generic unlock/change pin/change PinRequire.
261   SimDialogDelegate::SimDialogMode dialog_mode_;
262 
263   // New PIN value for the case when we unblock SIM card or change PIN.
264   std::string new_pin_;
265 
266   // The initial lock type value, used to observe changes to lock status;
267   std::string sim_lock_type_;
268 
269   // True if there's a pending PIN operation.
270   // That means that SIM lock state change will be received 2 times:
271   // OnNetworkDeviceSimLockChanged and OnPinOperationCompleted.
272   // First one should be ignored.
273   bool pending_pin_operation_;
274 
275   base::WeakPtrFactory<SimUnlockHandler> weak_ptr_factory_;
276 
277   DISALLOW_COPY_AND_ASSIGN(SimUnlockHandler);
278 };
279 
280 // SimUnlockUIHTMLSource -------------------------------------------------------
281 
SimUnlockUIHTMLSource()282 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
283 }
284 
GetSource() const285 std::string SimUnlockUIHTMLSource::GetSource() const {
286   return chrome::kChromeUISimUnlockHost;
287 }
288 
StartDataRequest(const std::string & path,int render_process_id,int render_frame_id,const content::URLDataSource::GotDataCallback & callback)289 void SimUnlockUIHTMLSource::StartDataRequest(
290     const std::string& path,
291     int render_process_id,
292     int render_frame_id,
293     const content::URLDataSource::GotDataCallback& callback) {
294   base::DictionaryValue strings;
295   strings.SetString("title",
296       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
297   strings.SetString("ok", l10n_util::GetStringUTF16(IDS_OK));
298   strings.SetString("cancel", l10n_util::GetStringUTF16(IDS_CANCEL));
299   strings.SetString("enterPinTitle",
300       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TITLE));
301   strings.SetString("enterPinMessage",
302       l10n_util::GetStringUTF16(IDS_SIM_ENTER_PIN_MESSAGE));
303   strings.SetString("enterPinTriesMessage",
304       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PIN_TRIES_MESSAGE));
305   strings.SetString("incorrectPinTriesMessage",
306       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TRIES_MESSAGE));
307   strings.SetString("incorrectPinTitle",
308       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_INCORRECT_PIN_TITLE));
309   // TODO(nkostylev): Pass carrier name if we know that.
310   strings.SetString("noPinTriesLeft", l10n_util::GetStringFUTF16(
311       IDS_SIM_UNLOCK_NO_PIN_TRIES_LEFT_MESSAGE,
312       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
313   strings.SetString("enterPukButton",
314       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_BUTTON));
315   strings.SetString("enterPukTitle",
316       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_TITLE));
317   strings.SetString("enterPukWarning",
318       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_ENTER_PUK_WARNING));
319   // TODO(nkostylev): Pass carrier name if we know that.
320   strings.SetString("enterPukMessage", l10n_util::GetStringFUTF16(
321       IDS_SIM_UNLOCK_ENTER_PUK_MESSAGE,
322       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_DEFAULT_CARRIER)));
323   strings.SetString("choosePinTitle",
324       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_TITLE));
325   strings.SetString("choosePinMessage",
326       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_CHOOSE_PIN_MESSAGE));
327   strings.SetString("newPin", l10n_util::GetStringUTF16(
328       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_NEW_PIN));
329   strings.SetString("retypeNewPin", l10n_util::GetStringUTF16(
330       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_RETYPE_PIN));
331   strings.SetString("pinsDontMatchMessage", l10n_util::GetStringUTF16(
332       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_PINS_DONT_MATCH_ERROR));
333   strings.SetString("noPukTriesLeft",
334       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_NO_PUK_TRIES_LEFT_MESSAGE));
335   strings.SetString("simDisabledTitle",
336       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_TITLE));
337   strings.SetString("simDisabledMessage",
338       l10n_util::GetStringUTF16(IDS_SIM_UNLOCK_SIM_DISABLED_MESSAGE));
339 
340   strings.SetString("changePinTitle", l10n_util::GetStringUTF16(
341       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_TITLE));
342   strings.SetString("changePinMessage", l10n_util::GetStringUTF16(
343       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_MESSAGE));
344   strings.SetString("oldPin", l10n_util::GetStringUTF16(
345       IDS_OPTIONS_SETTINGS_INTERNET_CELLULAR_CHANGE_PIN_OLD_PIN));
346 
347   webui::SetFontAndTextDirection(&strings);
348 
349   static const base::StringPiece html(
350       ResourceBundle::GetSharedInstance().GetRawDataResource(
351           IDR_SIM_UNLOCK_HTML));
352 
353   std::string full_html = webui::GetI18nTemplateHtml(html, &strings);
354 
355   callback.Run(base::RefCountedString::TakeString(&full_html));
356 }
357 
358 // SimUnlockHandler ------------------------------------------------------------
359 
SimUnlockHandler()360 SimUnlockHandler::SimUnlockHandler()
361     : state_(SIM_UNLOCK_LOADING),
362       dialog_mode_(SimDialogDelegate::SIM_DIALOG_UNLOCK),
363       pending_pin_operation_(false),
364       weak_ptr_factory_(this) {
365   if (GetNetworkStateHandler()
366           ->GetTechnologyState(NetworkTypePattern::Cellular()) !=
367       NetworkStateHandler::TECHNOLOGY_UNAVAILABLE)
368     GetNetworkStateHandler()->AddObserver(this, FROM_HERE);
369 }
370 
~SimUnlockHandler()371 SimUnlockHandler::~SimUnlockHandler() {
372   GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
373 }
374 
RegisterMessages()375 void SimUnlockHandler::RegisterMessages() {
376   web_ui()->RegisterMessageCallback(kJsApiCancel,
377       base::Bind(&SimUnlockHandler::HandleCancel,
378                  base::Unretained(this)));
379   web_ui()->RegisterMessageCallback(kJsApiChangePinCode,
380       base::Bind(&SimUnlockHandler::HandleChangePinCode,
381                  base::Unretained(this)));
382   web_ui()->RegisterMessageCallback(kJsApiEnterPinCode,
383       base::Bind(&SimUnlockHandler::HandleEnterPinCode,
384                  base::Unretained(this)));
385   web_ui()->RegisterMessageCallback(kJsApiEnterPukCode,
386       base::Bind(&SimUnlockHandler::HandleEnterPukCode,
387                  base::Unretained(this)));
388   web_ui()->RegisterMessageCallback(kJsApiProceedToPukInput,
389       base::Bind(&SimUnlockHandler::HandleProceedToPukInput,
390                  base::Unretained(this)));
391   web_ui()->RegisterMessageCallback(kJsApiSimStatusInitialize,
392       base::Bind(&SimUnlockHandler::HandleSimStatusInitialize,
393                  base::Unretained(this)));
394 }
395 
DeviceListChanged()396 void SimUnlockHandler::DeviceListChanged() {
397   const DeviceState* cellular_device = GetCellularDevice();
398   if (!cellular_device) {
399     LOG(WARNING) << "Cellular device with path '" << cellular_device_path_
400                  << "' disappeared.";
401     ProcessSimCardState(NULL);
402     return;
403   }
404 
405   // Process the SIM card state only if the lock state changed.
406   if (cellular_device->sim_lock_type() == sim_lock_type_)
407     return;
408 
409   sim_lock_type_ = cellular_device->sim_lock_type();
410   uint32 retries_left = cellular_device->sim_retries_left();
411   VLOG(1) << "OnNetworkDeviceSimLockChanged, lock: " << sim_lock_type_
412           << ", retries: " << retries_left;
413   // There's a pending PIN operation.
414   // Wait for it to finish and refresh state then.
415   if (!pending_pin_operation_)
416     ProcessSimCardState(cellular_device);
417 }
418 
OnPinOperationCompleted(PinOperationError error)419 void SimUnlockHandler::OnPinOperationCompleted(PinOperationError error) {
420   pending_pin_operation_ = false;
421   VLOG(1) << "OnPinOperationCompleted, error: " << error;
422   const DeviceState* cellular = GetCellularDevice();
423   if (!cellular) {
424     VLOG(1) << "Cellular device disappeared. Dismissing dialog.";
425     ProcessSimCardState(NULL);
426     return;
427   }
428   if (state_ == SIM_NOT_LOCKED_ASK_PIN && error == PIN_ERROR_NONE) {
429     CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
430           dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF);
431     // Async change RequirePin operation has finished OK.
432     NotifyOnRequirePinChangeEnded(
433         dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON);
434     // Dialog will close itself.
435     state_ = SIM_ABSENT_NOT_LOCKED;
436   } else if (state_ == SIM_NOT_LOCKED_CHANGE_PIN && error == PIN_ERROR_NONE) {
437     CHECK(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN);
438     // Dialog will close itself.
439     state_ = SIM_ABSENT_NOT_LOCKED;
440   }
441   // If previous EnterPIN was last PIN attempt and SIMLock state was already
442   // processed by OnNetworkDeviceChanged, let dialog stay on
443   // NO_PIN_RETRIES_LEFT step.
444   if (!(state_ == SIM_LOCKED_NO_PIN_TRIES_LEFT && error == PIN_ERROR_BLOCKED))
445     ProcessSimCardState(cellular);
446   if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK &&
447       state_ == SIM_ABSENT_NOT_LOCKED)
448     NotifyOnEnterPinEnded(false);
449 }
450 
GetCellularDevice()451 const DeviceState* SimUnlockHandler::GetCellularDevice() {
452   return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
453 }
454 
CancelDialog()455 void SimUnlockHandler::CancelDialog() {
456   if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
457       dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
458     // When async change RequirePin operation is performed,
459     // dialog UI controls such as Cancel button are disabled.
460     // If dialog was cancelled that means RequirePin preference hasn't been
461     // changed and is not in process of changing at the moment.
462     NotifyOnRequirePinChangeEnded(
463         !(dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON));
464   } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_UNLOCK) {
465     NotifyOnEnterPinEnded(true);
466   }
467 }
468 
EnterCode(const std::string & code,SimUnlockCode code_type)469 void SimUnlockHandler::EnterCode(const std::string& code,
470                                  SimUnlockCode code_type) {
471   DCHECK_CURRENTLY_ON(BrowserThread::UI);
472 
473   pending_pin_operation_ = true;
474 
475   switch (code_type) {
476     case CODE_PIN:
477       if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
478           dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
479         if (!sim_lock_type_.empty()) {
480           // If SIM is locked/absent, change RequirePin UI is not accessible.
481           NOTREACHED() <<
482               "Changing RequirePin pref on locked / uninitialized SIM.";
483         }
484         ChangeRequirePin(
485             dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON,
486             code);
487       } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
488         if (!sim_lock_type_.empty()) {
489           // If SIM is locked/absent, changing PIN UI is not accessible.
490           NOTREACHED() << "Changing PIN on locked / uninitialized SIM.";
491         }
492         ChangePin(code, new_pin_);
493       } else {
494         EnterPin(code);
495       }
496       break;
497     case CODE_PUK:
498       DCHECK(!new_pin_.empty());
499       UnblockPin(code, new_pin_);
500       break;
501   }
502 }
503 
ChangeRequirePin(bool require_pin,const std::string & pin)504 void SimUnlockHandler::ChangeRequirePin(bool require_pin,
505                                         const std::string& pin) {
506   const DeviceState* cellular = GetCellularDevice();
507   if (!cellular) {
508     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
509     return;
510   }
511   std::string operation_name = "ChangeRequirePin";
512   NET_LOG_USER(operation_name, cellular->path());
513   GetNetworkDeviceHandler()->RequirePin(
514       cellular->path(),
515       require_pin,
516       pin,
517       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
518                  weak_ptr_factory_.GetWeakPtr(),
519                  operation_name),
520       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
521                  weak_ptr_factory_.GetWeakPtr(),
522                  operation_name));
523 }
524 
EnterPin(const std::string & pin)525 void SimUnlockHandler::EnterPin(const std::string& pin) {
526   const DeviceState* cellular = GetCellularDevice();
527   if (!cellular) {
528     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
529     return;
530   }
531   std::string operation_name = "EnterPin";
532   NET_LOG_USER(operation_name, cellular->path());
533   GetNetworkDeviceHandler()->EnterPin(
534       cellular->path(),
535       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 
ChangePin(const std::string & old_pin,const std::string & new_pin)544 void SimUnlockHandler::ChangePin(const std::string& old_pin,
545                                  const std::string& new_pin) {
546   const DeviceState* cellular = GetCellularDevice();
547   if (!cellular) {
548     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
549     return;
550   }
551   std::string operation_name = "ChangePin";
552   NET_LOG_USER(operation_name, cellular->path());
553   GetNetworkDeviceHandler()->ChangePin(
554       cellular->path(),
555       old_pin,
556       new_pin,
557       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
558                  weak_ptr_factory_.GetWeakPtr(),
559                  operation_name),
560       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
561                  weak_ptr_factory_.GetWeakPtr(),
562                  operation_name));
563 }
564 
UnblockPin(const std::string & puk,const std::string & new_pin)565 void SimUnlockHandler::UnblockPin(const std::string& puk,
566                                   const std::string& new_pin) {
567   const DeviceState* cellular = GetCellularDevice();
568   if (!cellular) {
569     NOTREACHED() << "Calling RequirePin method w/o cellular device.";
570     return;
571   }
572   std::string operation_name = "UnblockPin";
573   NET_LOG_USER(operation_name, cellular->path());
574   GetNetworkDeviceHandler()->UnblockPin(
575       cellular->path(),
576       puk,
577       new_pin,
578       base::Bind(&SimUnlockHandler::PinOperationSuccessCallback,
579                  weak_ptr_factory_.GetWeakPtr(),
580                  operation_name),
581       base::Bind(&SimUnlockHandler::PinOperationErrorCallback,
582                  weak_ptr_factory_.GetWeakPtr(),
583                  operation_name));
584 }
585 
PinOperationSuccessCallback(const std::string & operation_name)586 void SimUnlockHandler::PinOperationSuccessCallback(
587     const std::string& operation_name) {
588   NET_LOG_DEBUG("Pin operation successful.", operation_name);
589   OnPinOperationCompleted(PIN_ERROR_NONE);
590 }
591 
PinOperationErrorCallback(const std::string & operation_name,const std::string & error_name,scoped_ptr<base::DictionaryValue> error_data)592 void SimUnlockHandler::PinOperationErrorCallback(
593     const std::string& operation_name,
594     const std::string& error_name,
595     scoped_ptr<base::DictionaryValue> error_data) {
596   NET_LOG_ERROR("Pin operation failed: " + error_name, operation_name);
597   PinOperationError pin_error;
598   if (error_name == NetworkDeviceHandler::kErrorIncorrectPin ||
599       error_name == NetworkDeviceHandler::kErrorPinRequired)
600     pin_error = PIN_ERROR_INCORRECT_CODE;
601   else if (error_name == NetworkDeviceHandler::kErrorPinBlocked)
602     pin_error = PIN_ERROR_BLOCKED;
603   else
604     pin_error = PIN_ERROR_UNKNOWN;
605   OnPinOperationCompleted(pin_error);
606 }
607 
NotifyOnEnterPinEnded(bool cancelled)608 void SimUnlockHandler::NotifyOnEnterPinEnded(bool cancelled) {
609   content::NotificationService::current()->Notify(
610       chrome::NOTIFICATION_ENTER_PIN_ENDED,
611       content::NotificationService::AllSources(),
612       content::Details<bool>(&cancelled));
613 }
614 
NotifyOnRequirePinChangeEnded(bool new_value)615 void SimUnlockHandler::NotifyOnRequirePinChangeEnded(bool new_value) {
616   content::NotificationService::current()->Notify(
617       chrome::NOTIFICATION_REQUIRE_PIN_SETTING_CHANGE_ENDED,
618       content::NotificationService::AllSources(),
619       content::Details<bool>(&new_value));
620 }
621 
HandleCancel(const base::ListValue * args)622 void SimUnlockHandler::HandleCancel(const base::ListValue* args) {
623   const size_t kEnterCodeParamCount = 0;
624   if (args->GetSize() != kEnterCodeParamCount) {
625     NOTREACHED();
626     return;
627   }
628   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
629   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
630       base::Bind(&TaskProxy::HandleCancel, task.get()));
631 }
632 
HandleChangePinCode(const base::ListValue * args)633 void SimUnlockHandler::HandleChangePinCode(const base::ListValue* args) {
634   const size_t kChangePinParamCount = 2;
635   std::string pin;
636   std::string new_pin;
637   if (args->GetSize() != kChangePinParamCount ||
638       !args->GetString(0, &pin) ||
639       !args->GetString(1, &new_pin)) {
640     NOTREACHED();
641     return;
642   }
643   new_pin_ = new_pin;
644   HandleEnterCode(CODE_PIN, pin);
645 }
646 
HandleEnterCode(SimUnlockCode code_type,const std::string & code)647 void SimUnlockHandler::HandleEnterCode(SimUnlockCode code_type,
648                                        const std::string& code) {
649   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr(), code, code_type);
650   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
651       base::Bind(&TaskProxy::HandleEnterCode, task.get()));
652 }
653 
HandleEnterPinCode(const base::ListValue * args)654 void SimUnlockHandler::HandleEnterPinCode(const base::ListValue* args) {
655   const size_t kEnterPinParamCount = 1;
656   std::string pin;
657   if (args->GetSize() != kEnterPinParamCount || !args->GetString(0, &pin)) {
658     NOTREACHED();
659     return;
660   }
661   HandleEnterCode(CODE_PIN, pin);
662 }
663 
HandleEnterPukCode(const base::ListValue * args)664 void SimUnlockHandler::HandleEnterPukCode(const base::ListValue* args) {
665   const size_t kEnterPukParamCount = 2;
666   std::string puk;
667   std::string new_pin;
668   if (args->GetSize() != kEnterPukParamCount ||
669       !args->GetString(0, &puk) ||
670       !args->GetString(1, &new_pin)) {
671     NOTREACHED();
672     return;
673   }
674   new_pin_ = new_pin;
675   HandleEnterCode(CODE_PUK, puk);
676 }
677 
HandleProceedToPukInput(const base::ListValue * args)678 void SimUnlockHandler::HandleProceedToPukInput(const base::ListValue* args) {
679   const size_t kProceedToPukInputParamCount = 0;
680   if (args->GetSize() != kProceedToPukInputParamCount) {
681     NOTREACHED();
682     return;
683   }
684   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
685   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
686       base::Bind(&TaskProxy::HandleProceedToPukInput, task.get()));
687 }
688 
HandleSimStatusInitialize(const base::ListValue * args)689 void SimUnlockHandler::HandleSimStatusInitialize(const base::ListValue* args) {
690   const size_t kSimStatusInitializeParamCount = 1;
691   double mode;
692   if (args->GetSize() != kSimStatusInitializeParamCount ||
693       !args->GetDouble(0, &mode)) {
694     NOTREACHED();
695     return;
696   }
697   dialog_mode_ = static_cast<SimDialogDelegate::SimDialogMode>(mode);
698   VLOG(1) << "Initializing SIM dialog in mode: " << dialog_mode_;
699   scoped_refptr<TaskProxy> task = new TaskProxy(AsWeakPtr());
700   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
701       base::Bind(&TaskProxy::HandleInitialize, task.get()));
702 }
703 
InitializeSimStatus()704 void SimUnlockHandler::InitializeSimStatus() {
705   DCHECK_CURRENTLY_ON(BrowserThread::UI);
706   // TODO(armansito): For now, we're initializing the device path to the first
707   // available cellular device. We should try to obtain a specific device here,
708   // as there can be multiple cellular devices present.
709   const DeviceState* cellular_device =
710       GetNetworkStateHandler()
711           ->GetDeviceStateByType(NetworkTypePattern::Cellular());
712   if (cellular_device) {
713     cellular_device_path_ = cellular_device->path();
714     sim_lock_type_ = cellular_device->sim_lock_type();
715   }
716   ProcessSimCardState(cellular_device);
717 }
718 
ProceedToPukInput()719 void SimUnlockHandler::ProceedToPukInput() {
720   DCHECK_CURRENTLY_ON(BrowserThread::UI);
721   ProcessSimCardState(GetCellularDevice());
722 }
723 
ProcessSimCardState(const DeviceState * cellular)724 void SimUnlockHandler::ProcessSimCardState(
725     const DeviceState* cellular) {
726   std::string error_msg;
727   if (cellular) {
728     uint32 retries_left = cellular->sim_retries_left();
729     VLOG(1) << "Current state: " << state_ << " lock_type: " << sim_lock_type_
730             << " retries: " << retries_left;
731     switch (state_) {
732       case SIM_UNLOCK_LOADING:
733         if (sim_lock_type_ == shill::kSIMLockPin) {
734           state_ = SIM_LOCKED_PIN;
735         } else if (sim_lock_type_ == shill::kSIMLockPuk) {
736           if (retries_left > 0)
737             state_ = SIM_LOCKED_PUK;
738           else
739             state_ = SIM_DISABLED;
740         } else if (sim_lock_type_.empty()) {
741           if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_ON ||
742               dialog_mode_ == SimDialogDelegate::SIM_DIALOG_SET_LOCK_OFF) {
743             state_ = SIM_NOT_LOCKED_ASK_PIN;
744           } else if (dialog_mode_ == SimDialogDelegate::SIM_DIALOG_CHANGE_PIN) {
745             state_ = SIM_NOT_LOCKED_CHANGE_PIN;
746           } else {
747             state_ = SIM_ABSENT_NOT_LOCKED;
748           }
749         } else {
750           // SIM_UNKNOWN: when SIM status is not initialized (should not happen,
751           // since this UI is accessible when SIM is initialized)
752           // or SIM card is absent. In latter case just close dialog.
753           state_ = SIM_ABSENT_NOT_LOCKED;
754         }
755         break;
756       case SIM_ABSENT_NOT_LOCKED:
757         // Dialog will close itself in this case.
758         break;
759       case SIM_NOT_LOCKED_ASK_PIN:
760       case SIM_NOT_LOCKED_CHANGE_PIN:
761         // We always start in these states when SIM is unlocked.
762         // So if we get here while still being UNLOCKED,
763         // that means entered PIN was incorrect.
764         if (sim_lock_type_.empty()) {
765           error_msg = kErrorPin;
766         } else if (sim_lock_type_ == shill::kSIMLockPuk) {
767           state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
768         } else {
769           NOTREACHED()
770               << "Change PIN / Set lock mode with unexpected SIM lock state";
771           state_ = SIM_ABSENT_NOT_LOCKED;
772         }
773         break;
774       case SIM_LOCKED_PIN:
775         if (sim_lock_type_ == shill::kSIMLockPuk) {
776           state_ = SIM_LOCKED_NO_PIN_TRIES_LEFT;
777         } else if (sim_lock_type_ == shill::kSIMLockPin) {
778           // Still locked with PIN.
779           error_msg = kErrorPin;
780         } else {
781           state_ = SIM_ABSENT_NOT_LOCKED;
782         }
783         break;
784       case SIM_LOCKED_NO_PIN_TRIES_LEFT:
785         // Proceed user to PUK input.
786         state_ = SIM_LOCKED_PUK;
787         break;
788       case SIM_LOCKED_PUK:
789         if (sim_lock_type_ != shill::kSIMLockPin &&
790             sim_lock_type_ != shill::kSIMLockPuk) {
791           state_ = SIM_ABSENT_NOT_LOCKED;
792         } else if (retries_left == 0) {
793           state_ = SIM_LOCKED_NO_PUK_TRIES_LEFT;
794         }
795         // Otherwise SIM card is still locked with PUK code.
796         // Dialog will display enter PUK screen with an updated retries count.
797         break;
798       case SIM_LOCKED_NO_PUK_TRIES_LEFT:
799       case SIM_DISABLED:
800         // User will close dialog manually.
801         break;
802     }
803   } else {
804     VLOG(1) << "Cellular device is absent.";
805     // No cellular device, should close dialog.
806     state_ = SIM_ABSENT_NOT_LOCKED;
807   }
808   VLOG(1) << "New state: " << state_;
809   UpdatePage(cellular, error_msg);
810 }
811 
UpdatePage(const DeviceState * cellular,const std::string & error_msg)812 void SimUnlockHandler::UpdatePage(const DeviceState* cellular,
813                                   const std::string& error_msg) {
814   base::DictionaryValue sim_dict;
815   if (cellular)
816     sim_dict.SetInteger(kTriesLeft, cellular->sim_retries_left());
817   sim_dict.SetInteger(kState, state_);
818   if (!error_msg.empty())
819     sim_dict.SetString(kError, error_msg);
820   else
821     sim_dict.SetString(kError, kErrorOk);
822   web_ui()->CallJavascriptFunction(kJsApiSimStatusChanged, sim_dict);
823 }
824 
825 // SimUnlockUI -----------------------------------------------------------------
826 
SimUnlockUI(content::WebUI * web_ui)827 SimUnlockUI::SimUnlockUI(content::WebUI* web_ui) : WebUIController(web_ui) {
828   SimUnlockHandler* handler = new SimUnlockHandler();
829   web_ui->AddMessageHandler(handler);
830   SimUnlockUIHTMLSource* html_source = new SimUnlockUIHTMLSource();
831 
832   // Set up the chrome://sim-unlock/ source.
833   Profile* profile = Profile::FromWebUI(web_ui);
834   content::URLDataSource::Add(profile, html_source);
835 }
836 
837 }  // namespace chromeos
838