Home | History | Annotate | Download | only in chromeos
      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 
     68 chromeos::NetworkDeviceHandler* GetNetworkDeviceHandler() {
     69   return chromeos::NetworkHandler::Get()->network_device_handler();
     70 }
     71 
     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;
     91   virtual std::string GetMimeType(const std::string&) const OVERRIDE {
     92     return "text/html";
     93   }
     94   virtual bool ShouldAddContentSecurityPolicy() const OVERRIDE {
     95     return false;
     96   }
     97 
     98  private:
     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:
    152     explicit TaskProxy(const base::WeakPtr<SimUnlockHandler>& handler)
    153         : handler_(handler),
    154           code_type_() {
    155     }
    156 
    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 
    165     void HandleCancel() {
    166       if (handler_)
    167         handler_->CancelDialog();
    168     }
    169 
    170     void HandleEnterCode() {
    171       if (handler_)
    172         handler_->EnterCode(code_, code_type_);
    173     }
    174 
    175     void HandleInitialize() {
    176       if (handler_)
    177         handler_->InitializeSimStatus();
    178     }
    179 
    180     void HandleProceedToPukInput() {
    181       if (handler_)
    182         handler_->ProceedToPukInput();
    183     }
    184 
    185    private:
    186     friend class base::RefCountedThreadSafe<TaskProxy>;
    187 
    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 
    282 SimUnlockUIHTMLSource::SimUnlockUIHTMLSource() {
    283 }
    284 
    285 std::string SimUnlockUIHTMLSource::GetSource() const {
    286   return chrome::kChromeUISimUnlockHost;
    287 }
    288 
    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 
    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 
    371 SimUnlockHandler::~SimUnlockHandler() {
    372   GetNetworkStateHandler()->RemoveObserver(this, FROM_HERE);
    373 }
    374 
    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 
    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 
    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 
    451 const DeviceState* SimUnlockHandler::GetCellularDevice() {
    452   return GetNetworkStateHandler()->GetDeviceState(cellular_device_path_);
    453 }
    454 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    719 void SimUnlockHandler::ProceedToPukInput() {
    720   DCHECK_CURRENTLY_ON(BrowserThread::UI);
    721   ProcessSimCardState(GetCellularDevice());
    722 }
    723 
    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 
    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 
    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